Compare commits

..
Author SHA1 Message Date
Rob Bygrave 5c447511c1 [maven-release-plugin] prepare release avaje-ebeanorm-3.4.1 2014-05-28 00:23:04 +12:00
Rob Bygrave f91789886c Backport of fix to 3.x for #131 - Memory issue (Hard refs) when using findIterate 2014-05-28 00:21:57 +12:00
Rob Bygrave 7d14ede1b9 [maven-release-plugin] prepare for next development iteration 2014-05-22 20:02:42 +12:00
Rob Bygrave 1ba8bc4557 [maven-release-plugin] prepare release avaje-ebeanorm-3.3.4 2014-05-22 20:02:26 +12:00
Rob Bygrave a234bd1201 Merge pull request #129 from jroper/java16-compat
Backport to JDK 6
2014-05-22 19:36:32 +12:00
James Roper 1c0c0893b6 Backport to JDK 6
Replaced all uses of ju.Objects.hashCode and ju.Objects.equals with a
copy of their implementations inlined into the code.

Also changed source/target for compiler plugin.

To test, I compiled my own avaje launchagent against 6, and changed to
use that in the pom, compiled/tested the whole project using JDK 7,
then ran mvn surefire:test using JDK 6 - running surefire:test ensures
that mvn doesn't try to recompile everything against 6, since that's not
possible because of some of the delegate classes having delegate methods
to JDK 7 jdbc classes.
2014-05-22 15:20:21 +10:00
Rob Bygrave ebbc560ae8 [maven-release-plugin] prepare for next development iteration 2014-05-19 01:03:43 +12:00
Rob Bygrave fcb9df05ad [maven-release-plugin] prepare release avaje-ebeanorm-3.3.3 2014-05-19 01:03:31 +12:00
Rob Bygrave 3de79b211a Change version in pom to 3.3.3-SNAPSHOT in preparation for release 2014-05-19 01:02:13 +12:00
Rob Bygrave d93952a920 Backport of fix for #56 - Using findIterate with MySQL streams 2014-05-19 00:59:05 +12:00
Rob Bygrave 3b4836cad9 [maven-release-plugin] prepare release avaje-ebeanorm-3.3.2 2014-04-03 23:18:50 +13:00
Rob Bygrave 6048d97aab Update version in README 2014-04-03 23:17:24 +13:00
Rob Bygrave 16d32b408e Merge branch 'master' of https://github.com/ebean-orm/avaje-ebeanorm 2014-04-03 23:15:01 +13:00
Rob Bygrave 0435ab0991 Fix for #84 Fix for classpath searching with maven surefire / jarfile with manifest 2014-04-03 23:14:55 +13:00
rob 95617d1bea Update README with pom version 2014-04-03 09:12:28 +13:00
Rob Bygrave 38d0e7642e [maven-release-plugin] prepare for next development iteration 2014-04-02 21:59:57 +13:00
Rob Bygrave e4306ce1ab [maven-release-plugin] prepare release avaje-ebeanorm-3.3.1 2014-04-02 21:59:46 +13:00
Rob Bygrave 444b656780 Update pom to 3.3.1 2014-04-02 21:58:13 +13:00
Rob Bygrave fcbba23441 Test case for #83 - Bug: Stateless update cascading to OneToOne or
ManyToOne incorrectly tries to INSERT rather than UPDATE
2014-04-02 21:44:41 +13:00
Rob Bygrave 18961047a1 Fix for #80 - Exposing discriminator value in entity bean throws
exception when updating or deleting
2014-03-31 22:49:44 +13:00
Rob Bygrave 34347fc3e1 Fix for #77 - NPE when lazy loading on a OneToMany that is not a leaf 2014-03-31 22:06:10 +13:00
Rob Bygrave 189e0a2ea9 Part of fix for #79 - moving deactivate() and notifyCommit() into finally block 2014-03-21 21:54:47 +13:00
Rob Bygrave 182e027521 Further changes for #79 - returning/cleanup of bad connection 2014-03-21 02:42:41 +13:00
Rob Bygrave f85fa2c21d Fix for #79 - Rollback in case of connection closed - deactivate() not called when connection.rollback() fails 2014-03-20 20:14:14 +13:00
Rob Bygrave 5a5f479568 Merge pull request #81 from rvowles/master
assume that if includes are specified then turn default includes off
2014-03-16 15:02:28 +13:00
Rob Bygrave 9ca2486c9c Change defaultJarMatch back to default to false (as per previous release) 2014-03-16 14:31:21 +13:00
Richard Vowles 656b239925 assume that if includes are specified then turn default includes off 2014-03-16 13:11:51 +13:00
Rob Bygrave 5d46904341 Fix for introduced issue with sub-query expression 2014-03-16 00:05:43 +13:00
Rob Bygrave f0dd069ed2 Fix for #70 - @PrivateOwned makes Ebean try to remove non persistent objects from DB and throws OptimisticLockException 2014-03-15 13:48:56 +13:00
Rob Bygrave 5bd454bdc0 Merge pull request #76 from icaromuniz/master
Adding test case TestPrivateOwnedIgnoreTransientOrphan related to issue #70
2014-03-15 13:14:17 +13:00
Rob Bygrave eeebaf9a08 Fix for #78 - Wrong collection used in excludeJar 2014-03-15 12:53:58 +13:00
Rob Bygrave 636a148509 Fix for #79 - Rollback in case of connection closed 2014-03-15 12:45:44 +13:00
Icaro Muniz 170cd6051e Adding test case TestPrivateOwnedIgnoreTransientOrphan 2014-02-26 09:23:35 -03:00
Rob Bygrave 522fc2384c [maven-release-plugin] prepare for next development iteration 2014-01-31 02:12:20 +13:00
Rob Bygrave 6f214590aa [maven-release-plugin] prepare release avaje-ebeanorm-3.3.1-RC2 2014-01-31 02:12:07 +13:00
Rob Bygrave 0014ea3501 Remove unused Lucene references including Query.UserIndex and associated methods 2014-01-31 01:26:12 +13:00
Rob Bygrave db3140512f set specific packages on dynamically loaded agent for tests 2014-01-31 00:59:48 +13:00
Rob Bygrave 8bfa331c61 Cleanup of expressions after FilterExprPath now only needed on FilterExpressionList 2014-01-31 00:48:59 +13:00
Rob Bygrave 456a1d8608 Remove AutoFetch query statistics meta entity beans, Remove Xml bean parsing (for json etc) 2014-01-31 00:22:38 +13:00
Rob Bygrave 695d3374a8 Default classPath scan include all jars (hopefully better default
behaviour)
2014-01-31 00:17:11 +13:00
Rob Bygrave 5488d054bf [maven-release-plugin] prepare for next development iteration 2014-01-30 23:25:57 +13:00
83 changed files with 1109 additions and 1724 deletions
+4 -4
View File
@@ -1,14 +1,14 @@
avaje-ebeanorm-server
=====================
avaje-ebeanorm
==============
The internal server implementation of EbeanORM API
Main EbeanORM artifact
Maven Dependency
----------------
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>3.2.5</version>
<version>3.3.2</version>
</dependency>
+11 -2
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>3.3.1-RC1</version>
<version>3.4.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -167,10 +167,19 @@
<!-- Enhance the meta beans -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>3.2.2</version>
<version>3.3.2</version>
<executions>
<execution>
<id>main</id>
@@ -36,11 +36,6 @@ import java.util.Map;
*/
public interface ExpressionFactory {
/**
* Return the language for this expression factory.
*/
public String getLang();
/**
* Equal To - property equal to the given value.
*/
@@ -244,14 +244,6 @@ public interface ExpressionList<T> extends Serializable {
*/
public Query<T> setMaxRows(int maxRows);
/**
* Set the number of rows after which the fetching should continue in a
* background thread.
*
* @see Query#setBackgroundFetchAfter(int)
*/
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter);
/**
* Set the name of the property which values become the key of a map.
*
@@ -259,15 +251,6 @@ public interface ExpressionList<T> extends Serializable {
*/
public Query<T> setMapKey(String mapKey);
/**
* Please migrate to using {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)}.
* Set a QueryListener for bean by bean processing.
*
* @see Query#setListener(QueryListener)
* @deprecated Migrate to {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)}
*/
public Query<T> setListener(QueryListener<T> queryListener);
/**
* Set to true to use the query for executing this query.
*
+3 -62
View File
@@ -269,26 +269,6 @@ import java.util.Set;
*/
public interface Query<T> extends Serializable {
/**
* How this query should use (or not) the Lucene Index if one is defined for
* the bean type.
*/
public enum UseIndex {
NO, DEFAULT, YES_IDS, YES_OBJECTS
}
/**
* Explicitly specify how this query should use a Lucene Index if one is
* defined for this bean type.
*/
public Query<T> setUseIndex(UseIndex useIndex);
/**
* Return the setting for how this query should use a Lucene Index if one is
* defined for this bean type.
*/
public UseIndex getUseIndex();
/**
* Return the RawSql that was set to use for this query.
*/
@@ -683,36 +663,6 @@ public interface Query<T> extends Serializable {
*/
public Query<T> setParameter(int position, Object value);
/**
* Please migrate to using {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)}
* <p>
* Set a listener to process the query on a row by row basis.
* </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>
* <p>
* It this case the rows are not loaded into the persistence context and
* instead are processed by the query listener.
* </p>
*
* <pre class="code">
* QueryListener&lt;Order&gt; listener = ...;
*
* Query&lt;Order&gt; query = Ebean.createQuery(Order.class);
*
* // set the listener that will process each order one at a time
* query.setListener(listener);
*
* // execute the query. Note that the returned
* // list (emptyList) will be empty ...
* List&lt;Order&gt; emtyList = query.findList();
* </pre>
* @deprecated Deprecated in favor of {@link #findIterate()} and {@link #findVisit(QueryResultVisitor)}
*/
public Query<T> setListener(QueryListener<T> queryListener);
/**
* Set the Id value to query. This is used with findUnique().
* <p>
@@ -986,13 +936,6 @@ public interface Query<T> extends Serializable {
*/
public Query<T> setMaxRows(int maxRows);
/**
* Set the rows after which fetching should continue in a background thread.
*
* @param backgroundFetchAfter
*/
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter);
/**
* Set the property to use as keys for a map.
* <p>
@@ -1072,16 +1015,14 @@ public interface Query<T> extends Serializable {
*/
public String getGeneratedSql();
/**
* Return the total hits matched for a lucene text search query.
*/
public int getTotalHits();
/**
* executed the select with "for update" which should lock the record
* "on read"
*/
public Query<T> setForUpdate(boolean forUpdate);
/**
* Return true if this query has forUpdate set.
*/
public boolean isForUpdate();
}
@@ -35,13 +35,6 @@ public interface Transaction extends Closeable {
*/
public static final int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
// /**
// * You can call this after the transaction commit to wait for any changes to
// * Lucene indexes to be made and committed. Note that generally this could
// * be some time so it is not expected that you call this method generally.
// */
// public void waitForIndexUpdates();
/**
* Return true if this transaction is read only.
*/
@@ -6,7 +6,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.avaje.ebean.Query;
import com.avaje.ebean.Query.UseIndex;
/**
* Specify the default cache use specific entity type.
@@ -56,9 +55,4 @@ public @interface CacheStrategy {
*/
String warmingQuery() default "";
/**
* Default setting for using a text index if it has been defined on this bean
* type.
*/
UseIndex useIndex() default UseIndex.DEFAULT;
};
@@ -1,7 +1,6 @@
package com.avaje.ebean.bean;
import java.io.Serializable;
import java.util.Objects;
/**
* Identifies a unique node of an object graph.
@@ -70,7 +69,7 @@ public final class ObjectGraphNode implements Serializable {
public int hashCode() {
int hc = 31 * originQueryPoint.hashCode();
hc = 31 * hc + Objects.hashCode(path);
hc = 31 * hc + (path == null ? 0 : path.hashCode());
return hc;
}
@@ -83,7 +82,7 @@ public final class ObjectGraphNode implements Serializable {
}
ObjectGraphNode e = (ObjectGraphNode) obj;
return Objects.equals(e.path, path)
return ((e.path == path) || (e.path != null && e.path.equals(path)))
&& e.originQueryPoint.equals(originQueryPoint);
}
}
@@ -1,228 +0,0 @@
package com.avaje.ebean.meta;
import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import com.avaje.ebean.bean.ObjectGraphOrigin;
/**
* Statistics collected by AutoFetch profiling.
*/
@Entity
public class MetaAutoFetchStatistic implements Serializable {
private static final long serialVersionUID = -6640406753257176803L;
@Id
private String id;
private ObjectGraphOrigin origin;
private String beanType;
private int counter;
@Transient
private List<QueryStats> queryStats;
@Transient
private List<NodeUsageStats> nodeUsageStats;
public MetaAutoFetchStatistic() {
}
public MetaAutoFetchStatistic(ObjectGraphOrigin origin, int counter, List<QueryStats> queryStats,
List<NodeUsageStats> nodeUsageStats) {
this.origin = origin;
this.beanType = origin == null ? null : origin.getBeanType();
this.id = origin == null ? null : origin.getKey();
this.counter = counter;
this.queryStats = queryStats;
this.nodeUsageStats = nodeUsageStats;
}
/**
* This is the query point key.
*/
public String getId() {
return id;
}
/**
* Return the bean type.
*/
public String getBeanType() {
return beanType;
}
/**
* Return the query point.
*/
public ObjectGraphOrigin getOrigin() {
return origin;
}
/**
* Return the number of profiled queries the statistics is based on.
*/
public int getCounter() {
return counter;
}
/**
* Return the query execution statistics.
*/
public List<QueryStats> getQueryStats() {
return queryStats;
}
/**
* Return the node usage statistics.
*/
public List<NodeUsageStats> getNodeUsageStats() {
return nodeUsageStats;
}
/**
* FIXME: This will likely be deprecated in favour of a separate object graph
* cost.
*/
public static class QueryStats implements Serializable {
private static final long serialVersionUID = -5517935732867671387L;
private final String path;
private final long exeCount;
private final long totalBeanLoaded;
private final long totalMicros;
public QueryStats(String path, long exeCount, long totalBeanLoaded, long totalMicros) {
this.path = path;
this.exeCount = exeCount;
this.totalBeanLoaded = totalBeanLoaded;
this.totalMicros = totalMicros;
}
/**
* Return the path. This is empty string for the origin query and otherwise
* the path for the associated lazy loading queries.
*/
public String getPath() {
return path;
}
/**
* The number of queries executed.
*/
public long getExeCount() {
return exeCount;
}
/**
* The total number of beans loaded by the query.
*/
public long getTotalBeanLoaded() {
return totalBeanLoaded;
}
/**
* The total time in microseconds of the queries.
*/
public long getTotalMicros() {
return totalMicros;
}
public String toString() {
long avgMicros = exeCount == 0 ? 0 : totalMicros / exeCount;
return "queryExe path[" + path + "] count[" + exeCount + "] totalBeansLoaded["
+ totalBeanLoaded + "] avgMicros[" + avgMicros + "] totalMicros[" + totalMicros
+ "]";
}
}
/**
* Collects usages statistics for a given node in the object graph.
*/
public static class NodeUsageStats implements Serializable {
private static final long serialVersionUID = 1786787832374844739L;
private final String path;
private final int profileCount;
private final int profileUsedCount;
private final String[] usedProperties;
public NodeUsageStats(String path, int profileCount, int profileUsedCount,
String[] usedProperties) {
this.path = path == null ? "" : path;
this.profileCount = profileCount;
this.profileUsedCount = profileUsedCount;
this.usedProperties = usedProperties;
}
/**
* Return the path. This is empty string for the origin and otherwise the
* path for the associated nodes.
*/
public String getPath() {
return path;
}
/**
* The number of profiled beans for this node.
*/
public int getProfileCount() {
return profileCount;
}
/**
* The number of profiled beans that where actually used for this node.
* <p>
* The difference between profiled and used could show uneven traversal of
* the object graph. UI paging through results means the traversal for the
* first x beans can be much higher than the last x beans.
* </p>
*/
public int getProfileUsedCount() {
return profileUsedCount;
}
/**
* The properties used at this node.
*/
public String[] getUsedProperties() {
return usedProperties;
}
/**
* Return the properties as a Set rather than an Array.
*/
public Set<String> getUsedPropertiesSet() {
LinkedHashSet<String> s = new LinkedHashSet<String>();
for (int i = 0; i < usedProperties.length; i++) {
s.add(usedProperties[i]);
}
return s;
}
public String toString() {
return "path[" + path + "] profileCount[" + profileCount + "] used[" + profileUsedCount
+ "] props" + Arrays.toString(usedProperties);
}
}
}
@@ -1,119 +0,0 @@
package com.avaje.ebean.meta;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import com.avaje.ebean.bean.ObjectGraphOrigin;
/**
* "Tuned fetch" information used by AutoFetch.
* <p>
* Note that the queryPoint is effectively the Id field for this bean.
* </p>
* <p>
* The queryPoint identifies both the query and call stack.
* </p>
*/
@Entity
public class MetaAutoFetchTunedQueryInfo implements Serializable {
private static final long serialVersionUID = 3119991928889170215L;
@Id
private String id;
private String beanType;
/**
* The profile query point (call stack and query).
*/
private ObjectGraphOrigin origin;
/**
* The tuned query details with joins and properties.
*/
private String tunedDetail;
/**
* The number of times profiling has been collected for this query point.
*/
private int profileCount;
/**
* The number of queries tuned by this info.
*/
private int tunedCount;
private long lastTuneTime;
public MetaAutoFetchTunedQueryInfo() {
}
public MetaAutoFetchTunedQueryInfo(final ObjectGraphOrigin origin, String tunedDetail,
int profileCount, int tunedCount, long lastTuneTime) {
this.origin = origin;
this.beanType = origin == null ? null : origin.getBeanType();
this.id = origin == null ? null : origin.getKey();
this.tunedDetail = tunedDetail;
this.profileCount = profileCount;
this.tunedCount = tunedCount;
this.lastTuneTime = lastTuneTime;
}
/**
* Return the query point key.
*/
public String getId() {
return id;
}
/**
* Return the type of bean this is tuned for.
*/
public String getBeanType() {
return beanType;
}
/**
* Return the query point.
*/
public ObjectGraphOrigin getOrigin() {
return origin;
}
/**
* The tuned query detail in string form.
*/
public String getTunedDetail() {
return tunedDetail;
}
/**
* The number of profiled queries the tuned query is based on.
*/
public int getProfileCount() {
return profileCount;
}
/**
* Return the number of queries tuned.
*/
public int getTunedCount() {
return tunedCount;
}
/**
* Return the time of the last tune (that changed the query).
*/
public long getLastTuneTime() {
return lastTuneTime;
}
public String toString() {
return "origin[" + origin + "] query[" + tunedDetail + "] profileCount[" + profileCount + "]";
}
}
@@ -1,7 +1,5 @@
package com.avaje.ebeaninternal.api;
import java.util.Objects;
/**
* A hash for a query plan.
*/
@@ -26,7 +24,7 @@ public class HashQueryPlan {
public int hashCode() {
int hc = planHash;
hc = hc * 31 + bindCount;
hc = hc * 31 + Objects.hashCode(rawSql);
hc = hc * 31 + (rawSql == null ? 0 : rawSql.hashCode());
return hc;
}
@@ -41,6 +39,6 @@ public class HashQueryPlan {
HashQueryPlan e = (HashQueryPlan) obj;
return e.planHash == planHash
&& e.bindCount == bindCount
&& Objects.equals(e.rawSql, rawSql);
&& ((e.rawSql == rawSql) || (e.rawSql != null && e.rawSql.equals(rawSql)));
}
}
@@ -1,7 +1,5 @@
package com.avaje.ebeaninternal.api;
import java.util.Objects;
/**
* Used to build HashQueryPlan instances.
*/
@@ -33,7 +31,7 @@ public class HashQueryPlanBuilder {
* Add an object to the hash calculation.
*/
public HashQueryPlanBuilder add(Object object) {
planHash = planHash * 31 + Objects.hashCode(object);
planHash = planHash * 31 + (object == null ? 0 : object.hashCode());
return this;
}
@@ -6,7 +6,6 @@ import java.util.List;
import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.OrderBy;
import com.avaje.ebean.Query;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.bean.BeanCollectionTouched;
import com.avaje.ebean.bean.CallStack;
import com.avaje.ebean.bean.EntityBean;
@@ -80,11 +79,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
SUBQUERY
}
/**
* Set total hits when querying against lucene.
*/
public void setTotalHits(int totalHits);
/**
* Return true if select all properties was used to ensure the property
@@ -514,12 +508,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
public String getMapKey();
/**
* Return the number of rows after which fetching should occur in a
* background thread.
*/
public int getBackgroundFetchAfter();
/**
* Return the maximum number of rows to return in the query.
*/
@@ -550,19 +538,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
public Object getId();
/**
* Return the queryListener.
*/
public QueryListener<T> getListener();
/**
* Return true if this query should use its own transaction.
* <p>
* This is true for background fetching and when using QueryListener.
* </p>
*/
public boolean createOwnTransaction();
/**
* Set the generated sql for debug purposes.
*
@@ -1,19 +1,14 @@
package com.avaje.ebeaninternal.server.autofetch;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.avaje.ebean.bean.NodeUsageCollector;
import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.ObjectGraphOrigin;
import com.avaje.ebean.meta.MetaAutoFetchStatistic;
import com.avaje.ebean.meta.MetaAutoFetchStatistic.NodeUsageStats;
import com.avaje.ebean.meta.MetaAutoFetchStatistic.QueryStats;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.text.PathProperties.Props;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
@@ -53,30 +48,6 @@ public class Statistics implements Serializable {
}
}
public MetaAutoFetchStatistic createPublicMeta() {
synchronized (monitor) {
StatisticsQuery[] sourceQueryStats = queryStatsMap.values().toArray(new StatisticsQuery[queryStatsMap.size()]);
List<QueryStats> destQueryStats = new ArrayList<QueryStats>(sourceQueryStats.length);
// copy the query statistics
for (int i = 0; i < sourceQueryStats.length; i++) {
destQueryStats.add(sourceQueryStats[i].createPublicMeta());
}
StatisticsNodeUsage[] sourceNodeUsage = nodeUsageMap.values().toArray(new StatisticsNodeUsage[nodeUsageMap.size()]);
List<NodeUsageStats> destNodeUsage = new ArrayList<NodeUsageStats>(sourceNodeUsage.length);
// copy the node usage statistics
for (int i = 0; i < sourceNodeUsage.length; i++) {
destNodeUsage.add(sourceNodeUsage[i].createPublicMeta());
}
return new MetaAutoFetchStatistic(origin, counter, destQueryStats, destNodeUsage);
}
}
/**
* Return the number of times the root query has executed.
* <p>
@@ -5,16 +5,16 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.bean.NodeUsageCollector;
import com.avaje.ebean.meta.MetaAutoFetchStatistic.NodeUsageStats;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SplitName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Collects usages statistics for a given node in the object graph.
@@ -44,13 +44,6 @@ public class StatisticsNodeUsage implements Serializable {
this.queryTuningAddVersion = queryTuningAddVersion;
}
public NodeUsageStats createPublicMeta() {
synchronized(monitor){
String[] usedProps = aggregateUsed.toArray(new String[aggregateUsed.size()]);
return new NodeUsageStats(path, profileCount, profileUsedCount, usedProps);
}
}
public void buildTunedFetch(PathProperties pathProps, BeanDescriptor<?> rootDesc) {
synchronized(monitor){
@@ -2,8 +2,6 @@ package com.avaje.ebeaninternal.server.autofetch;
import java.io.Serializable;
import com.avaje.ebean.meta.MetaAutoFetchStatistic.QueryStats;
/**
* Used to accumulate query execution statistics.
*/
@@ -22,10 +20,6 @@ public class StatisticsQuery implements Serializable {
public StatisticsQuery(String path){
this.path = path;
}
public QueryStats createPublicMeta() {
return new QueryStats(path, exeCount, totalBeanLoaded, totalMicros);
}
public void add(long beansLoaded, long micros) {
exeCount++;
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.autofetch;
import java.io.Serializable;
import com.avaje.ebean.bean.ObjectGraphOrigin;
import com.avaje.ebean.meta.MetaAutoFetchTunedQueryInfo;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
@@ -73,13 +72,6 @@ public class TunedQueryInfo implements Serializable {
}
}
/**
* Create a copy of this tuned fetch data for public consumption.
*/
public MetaAutoFetchTunedQueryInfo createPublicMeta() {
return new MetaAutoFetchTunedQueryInfo(origin, tunedDetail.toString(), profileCount, tunedCount, lastTuneTime);
}
/**
* Set the number of times profiling has been collected for this query
* point.
@@ -2,6 +2,11 @@ package com.avaje.ebeaninternal.server.core;
import java.sql.Connection;
import javax.persistence.PersistenceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiTransaction;
@@ -11,6 +16,8 @@ import com.avaje.ebeaninternal.api.SpiTransaction;
*/
public abstract class BeanRequest {
private static final Logger log = LoggerFactory.getLogger(BeanRequest.class);
/**
* The server processing the request.
*/
@@ -84,7 +91,14 @@ public abstract class BeanRequest {
*/
public void rollbackTransIfRequired() {
if (createdTransaction) {
transaction.rollback();
try {
transaction.rollback();
} catch (PersistenceException e) {
// Just log this and carry on. A previous exception has been
// thrown and if this rollback throws exception it likely means
// that the connection is broken (and the datasource and db will cleanup)
log.error("Error trying to rollack a transaction (after a prior exception thrown)", e);
}
}
}
@@ -82,16 +82,22 @@ public class BootupClassPathSearch {
ClassPathSearchFilter filter = new ClassPathSearchFilter();
filter.addDefaultExcludePackages();
if (packages != null) {
if (packages != null && packages.size() > 0) {
for (String packageName : packages) {
filter.includePackage(packageName);
}
// if they specified include packages, they don't want by default to include everything
filter.setDefaultPackageMatch(false);
}
if (jars != null) {
if (jars != null && jars.size() > 0) {
for (String jarName : jars) {
filter.includeJar(jarName);
}
// if they specified jars to specifically include, they don't want everything included
filter.setDefaultJarMatch(false);
}
return filter;
@@ -8,8 +8,9 @@ import java.util.List;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.ScalarTypeConverter;
@@ -22,8 +23,6 @@ import com.avaje.ebean.event.ServerConfigStartup;
import com.avaje.ebean.event.TransactionEventListener;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Interesting classes for a EbeanServer such as Embeddable, Entity,
@@ -33,8 +32,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);
private ArrayList<Class<?>> xmlBeanList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> embeddableList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> entityList = new ArrayList<Class<?>>();
@@ -55,8 +52,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> luceneIndexList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
@@ -75,7 +70,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
}
private BootupClasses(BootupClasses parent) {
this.xmlBeanList.addAll(parent.xmlBeanList);
this.embeddableList.addAll(parent.embeddableList);
this.entityList.addAll(parent.entityList);
this.scalarTypeList.addAll(parent.scalarTypeList);
@@ -86,7 +80,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
this.beanFinderList.addAll(parent.beanFinderList);
this.beanListenerList.addAll(parent.beanListenerList);
this.beanQueryAdapterList.addAll(parent.beanQueryAdapterList);
this.luceneIndexList.addAll(parent.luceneIndexList);
this.serverConfigStartupList.addAll(parent.serverConfigStartupList);
}
@@ -304,13 +297,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
return beanListenerList;
}
/**
* Return the list of XML Beans.
*/
public ArrayList<Class<?>> getXmlBeanList() {
return xmlBeanList;
}
public void add(Iterator<Class<?>> it) {
while (it.hasNext()) {
Class<?> clazz = it.next();
@@ -325,11 +311,7 @@ public class BootupClasses implements ClassPathSearchMatcher {
} else if (isEntity(cls)) {
entityList.add(cls);
} else if (isXmlBean(cls)){
entityList.add(cls);
//xmlBeanList.add(cls);
} else if (isInterestingInterface(cls)) {
return true;
@@ -419,18 +401,4 @@ public class BootupClasses implements ClassPathSearchMatcher {
}
return false;
}
private boolean isXmlBean(Class<?> cls) {
Annotation ann = cls.getAnnotation(XmlRootElement.class);
if (ann != null) {
return true;
}
ann = cls.getAnnotation(XmlType.class);
if (ann != null) {
// Only looking for Beans and not Enums
return !cls.isEnum();
}
return false;
}
}
@@ -90,7 +90,6 @@ import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.el.ElFilter;
import com.avaje.ebeaninternal.server.jmx.MAdminAutofetch;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
import com.avaje.ebeaninternal.server.query.CQuery;
import com.avaje.ebeaninternal.server.query.CQueryEngine;
import com.avaje.ebeaninternal.server.query.CallableQueryIds;
@@ -490,7 +489,7 @@ public final class DefaultServer implements SpiEbeanServer {
}
/**
* Compile a query. Only valid for ORM queries (not LDAP)
* Compile a query. Only valid for ORM queries.
*/
public <T> CQuery<T> compileQuery(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> qr = createQueryRequest(Type.SUBQUERY, query, t);
@@ -1133,7 +1132,7 @@ public final class DefaultServer implements SpiEbeanServer {
if (Mode.LAZYLOAD_MANY.equals(query.getMode())) {
allowOneManyFetch = false;
} else if (query.hasMaxRowsOrFirstRow() && !query.isRawSql() && !query.isSqlSelect() && query.getBackgroundFetchAfter() == 0) {
} else if (query.hasMaxRowsOrFirstRow() && !query.isRawSql() && !query.isSqlSelect()) {
// convert ALL fetch joins to Many's to be query joins
// so that limit offset type SQL clauses work
allowOneManyFetch = false;
@@ -1194,16 +1193,15 @@ public final class DefaultServer implements SpiEbeanServer {
if (cachedBean != null) {
if (context == null) {
context = new DefaultPersistenceContext();
}
context.put(query.getId(), cachedBean);
DLoadContext loadContext = new DLoadContext(this, beanDescriptor, query.isReadOnly(), query);
loadContext.setPersistenceContext(context);
EntityBeanIntercept ebi = ((EntityBean) cachedBean)._ebean_getIntercept();
// Not using a loadContext for beans coming out of L2 cache
// so that means no batch lazy loading for these beans
EntityBean entityBean = (EntityBean) cachedBean;
EntityBeanIntercept ebi = entityBean._ebean_getIntercept();
ebi.setPersistenceContext(context);
loadContext.register(null, ebi);
Object id = beanDescriptor.getId(entityBean);
context.put(id, entityBean);
}
return (T) cachedBean;
@@ -29,6 +29,7 @@ import com.avaje.ebeaninternal.server.deploy.DeployPropertyParserMap;
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
import com.avaje.ebeaninternal.server.query.CQueryPlan;
import com.avaje.ebeaninternal.server.query.CancelableQuery;
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
/**
* Wraps the objects involved in executing a Query.
@@ -43,7 +44,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
private final BeanFinder<T> finder;
private final LoadContext graphContext;
private LoadContext graphContext;
private final Boolean readOnly;
@@ -75,13 +76,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
this.queryEngine = queryEngine;
this.query = query;
this.readOnly = query.isReadOnly();
this.graphContext = new DLoadContext(ebeanServer, beanDescriptor, readOnly, query);
graphContext.registerSecondaryQueries(query);
}
public void setTotalHits(int totalHits) {
query.setTotalHits(totalHits);
}
public void executeSecondaryQueries(int defaultQueryBatch) {
@@ -167,12 +161,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
@Override
public void initTransIfRequired() {
// first check if the query requires its own transaction
if (query.createOwnTransaction()) {
// using background fetch or query listener etc
transaction = ebeanServer.createQueryTransaction();
createdTransaction = true;
} else if (transaction == null) {
if (transaction == null) {
// maybe a current one
transaction = ebeanServer.getCurrentServerTransaction();
if (transaction == null) {
@@ -181,8 +170,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
createdTransaction = true;
}
}
this.persistenceContext = getPersistenceContext(query, transaction);
this.graphContext.setPersistenceContext(persistenceContext);
this.graphContext = new DLoadContext(this);
this.graphContext.registerSecondaryQueries(query);
}
/**
@@ -385,7 +377,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
}
public void flushPersistenceContextOnIterate() {
beanDescriptor.flushPersistenceContextOnIterate(persistenceContext);
persistenceContext = new DefaultPersistenceContext();
graphContext.setPersistenceContext(persistenceContext);
}
}
@@ -19,7 +19,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.Query;
import com.avaje.ebean.Query.UseIndex;
import com.avaje.ebean.SqlUpdate;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.annotation.ConcurrencyMode;
@@ -97,7 +96,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
private final ConcurrentHashMap<String, BeanFkeyProperty> fkeyMap = new ConcurrentHashMap<String, BeanFkeyProperty>();
public enum EntityType {
ORM, EMBEDDED, SQL, META, XMLELEMENT
ORM, EMBEDDED, SQL
}
/**
@@ -106,7 +105,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
private final String serverName;
/**
* Set to true if this is a LDAP domain object.
* The nature/type of this bean.
*/
private final EntityType entityType;
@@ -346,12 +345,9 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
private final String defaultSelectClause;
private final Set<String> defaultSelectClauseSet;
private final String[] defaultSelectDbArray;
private final String descriptorId;
private final UseIndex useIndex;
private SpiEbeanServer ebeanServer;
private ServerCache beanCache;
@@ -372,7 +368,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
this.fullName = InternString.intern(deploy.getFullName());
this.descriptorId = descriptorId;
this.useIndex = deploy.getUseIndex();
this.typeManager = typeManager;
this.beanType = deploy.getBeanType();
this.factoryType = deploy.getFactoryType();
@@ -390,7 +385,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
this.defaultSelectClause = deploy.getDefaultSelectClause();
this.defaultSelectClauseSet = deploy.parseDefaultSelectClause(defaultSelectClause);
this.defaultSelectDbArray = deploy.getDefaultSelectDbArray(defaultSelectClauseSet);
this.idType = deploy.getIdType();
this.idGenerator = deploy.getIdGenerator();
@@ -569,14 +563,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
return entityType;
}
/**
* Return the default strategy for using a lucene index (if an index is
* defined on this bean type).
*/
public UseIndex getUseIndex() {
return useIndex;
}
/**
* Initialise the Id properties first.
* <p>
@@ -808,13 +794,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
return defaultSelectClauseSet;
}
/**
* For LDAP return array of (DB) attributes to include in query by default.
*/
public String[] getDefaultSelectDbArray() {
return defaultSelectDbArray;
}
/**
* Return true if this object is the root level object in its entity
* inheritance.
@@ -858,8 +837,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
}
/**
* Return true if there is L2 caching (Lucene or Bean cache) for this bean
* type.
* Return true if there is L2 bean caching for this bean type.
*/
public boolean isUsingL2Cache() {
return isBeanCaching();
@@ -2403,13 +2381,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
@SuppressWarnings("unchecked")
private T createJsonBean() {
if (EntityType.XMLELEMENT.equals(entityType)) {
try {
return beanType.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return (T)createEntityBean();
}
@@ -2473,13 +2444,5 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
return false;
}
public void flushPersistenceContextOnIterate(PersistenceContext persistenceContext) {
persistenceContext.clear(beanType);
for (int i = 0; i < propertiesMany.length; i++) {
persistenceContext.clear(propertiesMany[i].getBeanDescriptor().getBeanType());
}
}
}
@@ -106,9 +106,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private final BeanManagerFactory beanManagerFactory;
private int enhancedClassCount;
private int subclassClassCount;
private final HashSet<String> subclassedEntities = new HashSet<String>();
private final boolean updateChangesOnly;
private final BootupClasses bootupClasses;
@@ -447,26 +445,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
logger.debug("BeanPersistControllers[" + cc + "] BeanFinders[" + fc + "] BeanPersistListeners[" + lc + "] BeanQueryAdapters[" + qa + "]");
}
/**
* Log Warning if mixing subclass and enhancement.
* <p>
* If enhancement is used for some classes it is expected to be used for all
* and vice versa.
* </p>
*/
private void logStatus() {
String msg = "Entities enhanced[" + enhancedClassCount + "] subclassed[" + subclassClassCount + "]";
logger.info(msg);
if (enhancedClassCount > 0) {
if (subclassClassCount > 0) {
String subclassEntityNames = subclassedEntities.toString();
String m = "Mixing enhanced and subclassed entities. Subclassed classes:" + subclassEntityNames;
logger.warn(m);
}
}
logger.info("Entities enhanced[" + enhancedClassCount + "]");
}
private <T> BeanDescriptor<T> createEmbedded(Class<T> beanClass) {
@@ -1462,25 +1442,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private void checkEnhanced(DeployBeanDescriptor<?> desc, Class<?> beanClass) {
// the bean already implements EntityBean
checkInheritedClasses(true, beanClass);
desc.setFactoryType(beanClass);
if (!beanClass.getName().startsWith("com.avaje.ebean.meta")) {
enhancedClassCount++;
}
enhancedClassCount++;
}
private void checkSubclass(DeployBeanDescriptor<?> desc, Class<?> beanClass) {
checkInheritedClasses(false, beanClass);
desc.checkReadAndWriteMethods();
EntityType entityType = desc.getEntityType();
if (EntityType.XMLELEMENT.equals(entityType)) {
desc.setFactoryType(beanClass);
} else {
throw new PersistenceException("Entity type "+beanClass+" is not an enhanced entity bean. Subclassing is not longer supported in Ebean");
}
throw new PersistenceException("Entity type "+beanClass+" is not an enhanced entity bean. Subclassing is not longer supported in Ebean");
}
/**
@@ -1049,19 +1049,6 @@ public class BeanProperty implements ElPropertyValue {
return value;
}
// private ArrayList<LuceneIndex> luceneIndexes;
//
// public void registerLuceneIndex(LuceneIndex luceneIndex) {
// if (luceneIndexes == null) {
// luceneIndexes = new ArrayList<LuceneIndex>();
// }
// luceneIndexes.add(luceneIndex);
// }
//
// public boolean isDeltaRequired() {
// return true;//luceneIndexes != null;
// }
/**
* Return true if by default this property is set to fetch eager.
* Lob's usually default to fetch lazy.
@@ -6,9 +6,6 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
@@ -21,172 +18,156 @@ import com.avaje.ebeaninternal.server.type.DataBind;
*/
public interface IdBinder {
/**
* Initialise the binder.
*/
public void initialise();
/**
* Convert the Id value as a Lucene string term.
*/
public String writeTerm(Object idValue);
/**
* Initialise the binder.
*/
public void initialise();
/**
* Convert the Lucene string term into an Id value.
*/
public Object readTerm(String idTermValue);
/**
* Write the Id value to binary DataOuput.
*/
public void writeData(DataOutput dataOutput, Object idValue) throws IOException;
/**
* Write the Id value to binary DataOuput.
*/
public void writeData(DataOutput dataOutput, Object idValue) throws IOException;
/**
* Read the Id value from the binary DataInput.
*/
public Object readData(DataInput dataInput) throws IOException;
/**
* Read the Id value from the binary DataInput.
*/
public Object readData(DataInput dataInput) throws IOException;
/**
* Return the name(s) of the Id property(s). Comma delimited if there is more
* than one.
* <p>
* This can be used to include in a query.
* </p>
*/
public String getIdProperty();
/**
* Adds RDN's to the LdapName using the id value.
*/
public void createLdapNameById(LdapName name, Object id) throws InvalidNameException;
/**
* Find a BeanProperty that is mapped to the database column.
*/
public BeanProperty findBeanProperty(String dbColumnName);
/**
* Adds RDN's to the LdapName using the id value from the bean.
*/
public void createLdapNameByBean(LdapName name, Object bean) throws InvalidNameException;
/**
* Return the number of scalar properties for this id.
*/
public int getPropertyCount();
/**
* Return the name(s) of the Id property(s).
* Comma delimited if there is more than one.
* <p>
* This can be used to include in a query.
* </p>
*/
public String getIdProperty();
/**
* Return false if the id is a simple scalar and false if it is embedded or
* concatenated.
*/
public boolean isComplexId();
/**
* Find a BeanProperty that is mapped to the database column.
*/
public BeanProperty findBeanProperty(String dbColumnName);
/**
* Return the number of scalar properties for this id.
*/
public int getPropertyCount();
/**
* Return false if the id is a simple scalar and false if it is embedded or concatenated.
*/
public boolean isComplexId();
/**
* Return the default order by that may need to be used if the query includes a many property.
*/
public String getDefaultOrderBy();
public String getOrderBy(String pathPrefix, boolean ascending);
/**
* Return the values as an array of scalar bindable values.
* <p>
* For concatenated keys that use an Embedded bean or multiple id properties
* this determines the field values are returns them as an Object array.
* </p>
* <p>
* Added primarily for Query.addWhere().add(Expr.idEq()) support.
* </p>
*/
public Object[] getBindValues(Object idValue);
/**
* Return the id values for a given bean.
*/
public Object[] getIdValues(Object bean);
/**
* Build a string of the logical expressions.
* <p>
* Typically used to build a id = ? string.
* </p>
*/
public String getAssocOneIdExpr(String prefix, String operator);
/**
* Return the logical id in expression taking into account embedded id's.
*/
public String getAssocIdInExpr(String prefix);
/**
* Return the default order by that may need to be used if the query includes
* a many property.
*/
public String getDefaultOrderBy();
/**
* Binds an id value to a prepared statement.
*/
public void bindId(DataBind dataBind, Object value) throws SQLException;
public String getOrderBy(String pathPrefix, boolean ascending);
/**
* Bind the id value to a SqlUpdate statement.
*/
public void bindId(DefaultSqlUpdate sqlUpdate, Object value);
public void addIdInBindValue(SpiExpressionRequest request, Object value);
/**
* Return the sql for binding the id using an IN clause.
*/
public String getBindIdInSql(String baseTableAlias);
/**
* Return the binding expression (like "?" or "(?,?)")for the Id.
*/
public String getIdInValueExpr(int size);
/**
* Same as getIdInValueExpr but for delete by id.
*/
public String getIdInValueExprDelete(int size);
public void buildSelectExpressionChain(String prefix, List<String> selectChain);
/**
* Read the id value from the result set and set it to the bean also returning it.
*/
public Object readSet(DbReadContext ctx, Object bean) throws SQLException;
/**
* Return the values as an array of scalar bindable values.
* <p>
* For concatenated keys that use an Embedded bean or multiple id properties
* this determines the field values are returns them as an Object array.
* </p>
* <p>
* Added primarily for Query.addWhere().add(Expr.idEq()) support.
* </p>
*/
public Object[] getBindValues(Object idValue);
/**
* Ignore the appropriate number of scalar properties for this id.
*/
public void loadIgnore(DbReadContext ctx);
/**
* Read the id value from the result set and return it.
*/
public Object read(DbReadContext ctx) throws SQLException;
/**
* Return the id values for a given bean.
*/
public Object[] getIdValues(Object bean);
/**
* Append to the select clause.
*/
public void appendSelect(DbSqlContext ctx, boolean subQuery);
/**
* Return the sql for binding the id to. This includes table alias and columns that make up the id.
*/
public String getBindIdSql(String baseTableAlias);
/**
* Return the id properties in flat form.
*/
public BeanProperty[] getProperties();
/**
* Cast or convert the Id value if necessary and optionally set it.
* <p>
* The Id value is not assumed to be the correct type so it is converted to
* the correct type. Typically this is because we could get a Integer, Long
* or BigDecimal depending on the JDBC driver and situation.
* </p>
* <p>
* If the bean is not null, then the value is set to the bean.
* </p>
*/
public Object convertSetId(Object idValue, Object bean);
/**
* Build a string of the logical expressions.
* <p>
* Typically used to build a id = ? string.
* </p>
*/
public String getAssocOneIdExpr(String prefix, String operator);
/**
* Return the logical id in expression taking into account embedded id's.
*/
public String getAssocIdInExpr(String prefix);
/**
* Binds an id value to a prepared statement.
*/
public void bindId(DataBind dataBind, Object value) throws SQLException;
/**
* Bind the id value to a SqlUpdate statement.
*/
public void bindId(DefaultSqlUpdate sqlUpdate, Object value);
public void addIdInBindValue(SpiExpressionRequest request, Object value);
/**
* Return the sql for binding the id using an IN clause.
*/
public String getBindIdInSql(String baseTableAlias);
/**
* Return the binding expression (like "?" or "(?,?)")for the Id.
*/
public String getIdInValueExpr(int size);
/**
* Same as getIdInValueExpr but for delete by id.
*/
public String getIdInValueExprDelete(int size);
public void buildSelectExpressionChain(String prefix, List<String> selectChain);
/**
* Read the id value from the result set and set it to the bean also returning
* it.
*/
public Object readSet(DbReadContext ctx, Object bean) throws SQLException;
/**
* Ignore the appropriate number of scalar properties for this id.
*/
public void loadIgnore(DbReadContext ctx);
/**
* Read the id value from the result set and return it.
*/
public Object read(DbReadContext ctx) throws SQLException;
/**
* Append to the select clause.
*/
public void appendSelect(DbSqlContext ctx, boolean subQuery);
/**
* Return the sql for binding the id to. This includes table alias and columns
* that make up the id.
*/
public String getBindIdSql(String baseTableAlias);
/**
* Return the id properties in flat form.
*/
public BeanProperty[] getProperties();
/**
* Cast or convert the Id value if necessary and optionally set it.
* <p>
* The Id value is not assumed to be the correct type so it is converted to
* the correct type. Typically this is because we could get a Integer, Long or
* BigDecimal depending on the JDBC driver and situation.
* </p>
* <p>
* If the bean is not null, then the value is set to the bean.
* </p>
*/
public Object convertSetId(Object idValue, Object bean);
}
@@ -6,11 +6,6 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.persistence.PersistenceException;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
@@ -99,23 +94,6 @@ public final class IdBinderEmbedded implements IdBinder {
return sb.toString();
}
public void createLdapNameById(LdapName name, Object id) throws InvalidNameException {
for (int i = 0; i < props.length; i++) {
Object v = props[i].getValue(id);
Rdn rdn = new Rdn(props[i].getDbColumn(), v);
name.add(rdn);
}
}
public void createLdapNameByBean(LdapName name, Object bean) throws InvalidNameException {
Object id = embIdProperty.getValue(bean);
createLdapNameById(name, id);
}
public BeanDescriptor<?> getIdBeanDescriptor() {
return idDesc;
}
@@ -228,42 +206,6 @@ public final class IdBinderEmbedded implements IdBinder {
return idInValueSql;
}
/**
* Convert the lucene string term value into embedded id.
*/
public Object readTerm(String idTermValue) {
String[] split = idTermValue.split("|");
if (split.length != props.length){
String msg = "Failed to split ["+idTermValue+"] using | for id.";
throw new PersistenceException(msg);
}
Object embId = idDesc.createBean();
for (int i = 0; i < props.length; i++) {
Object v = props[i].getScalarType().parse(split[i]);
props[i].setValue(embId, v);
}
return embId;
}
/**
* Write the embedded id as a Lucene string term value.
*/
public String writeTerm(Object idValue) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
Object v = props[i].getValue(idValue);
String formatValue = props[i].getScalarType().format(v);
if (i > 0){
sb.append("|");
}
sb.append(formatValue);
}
return sb.toString();
}
public Object[] getIdValues(Object bean) {
bean = embIdProperty.getValue(bean);
Object[] bindvalues = new Object[props.length];
@@ -6,9 +6,6 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
@@ -21,132 +18,118 @@ import com.avaje.ebeaninternal.server.type.DataBind;
*/
public final class IdBinderEmpty implements IdBinder {
private static final String bindIdSql = "";
private static final BeanProperty[] properties = new BeanProperty[0];
public IdBinderEmpty() {
private static final String bindIdSql = "";
}
public void initialise(){
}
public Object readTerm(String idTermValue) {
return null;
}
public String writeTerm(Object idValue) {
return null;
}
public String getOrderBy(String pathPrefix, boolean ascending){
return pathPrefix;
}
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
}
public void createLdapNameById(LdapName name, Object id) throws InvalidNameException {
}
public void createLdapNameByBean(LdapName name, Object bean) throws InvalidNameException {
}
public int getPropertyCount() {
return 0;
}
public String getIdProperty() {
return null;
}
private static final BeanProperty[] properties = new BeanProperty[0];
public BeanProperty findBeanProperty(String dbColumnName) {
return null;
}
public boolean isComplexId(){
return true;
}
public IdBinderEmpty() {
}
public String getDefaultOrderBy() {
// this should never happen?
return "";
}
public BeanProperty[] getProperties() {
return properties;
}
public void initialise() {
public String getBindIdSql(String baseTableAlias) {
return bindIdSql;
}
public String getAssocOneIdExpr(String prefix, String operator){
return null;
}
public String getAssocIdInExpr(String prefix) {
return null;
}
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
}
public String getIdInValueExprDelete(int size) {
return getIdInValueExpr(size);
}
public String getIdInValueExpr(int size) {
return "";
}
}
public String getBindIdInSql(String baseTableAlias) {
return null;
}
public Object[] getIdValues(Object bean){
return null;
}
public Object[] getBindValues(Object idValue){
return new Object[]{idValue};
}
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
}
public void bindId(DataBind dataBind, Object value) throws SQLException {
}
public void loadIgnore(DbReadContext ctx) {
}
public String getOrderBy(String pathPrefix, boolean ascending) {
return pathPrefix;
}
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
}
public int getPropertyCount() {
return 0;
}
public String getIdProperty() {
return null;
}
public BeanProperty findBeanProperty(String dbColumnName) {
return null;
}
public boolean isComplexId() {
return true;
}
public String getDefaultOrderBy() {
// this should never happen?
return "";
}
public BeanProperty[] getProperties() {
return properties;
}
public String getBindIdSql(String baseTableAlias) {
return bindIdSql;
}
public String getAssocOneIdExpr(String prefix, String operator) {
return null;
}
public String getAssocIdInExpr(String prefix) {
return null;
}
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
}
public String getIdInValueExprDelete(int size) {
return getIdInValueExpr(size);
}
public String getIdInValueExpr(int size) {
return "";
}
public String getBindIdInSql(String baseTableAlias) {
return null;
}
public Object[] getIdValues(Object bean) {
return null;
}
public Object[] getBindValues(Object idValue) {
return new Object[] { idValue };
}
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
}
public void bindId(DataBind dataBind, Object value) throws SQLException {
}
public void loadIgnore(DbReadContext ctx) {
}
public Object readSet(DbReadContext ctx, Object bean) throws SQLException {
return null;
}
public Object read(DbReadContext ctx) throws SQLException {
return null;
}
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
}
public Object convertSetId(Object idValue, Object bean) {
return idValue;
}
public Object readData(DataInput dataOutput) throws IOException {
return null;
}
public void writeData(DataOutput dataOutput, Object idValue) throws IOException {
}
public Object readSet(DbReadContext ctx, Object bean) throws SQLException {
return null;
}
public Object read(DbReadContext ctx) throws SQLException {
return null;
}
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
}
public Object convertSetId(Object idValue, Object bean){
return idValue;
}
public Object readData(DataInput dataOutput) throws IOException {
return null;
}
public void writeData(DataOutput dataOutput, Object idValue) throws IOException {
}
}
@@ -8,9 +8,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.persistence.PersistenceException;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
@@ -83,24 +80,6 @@ public final class IdBinderMultiple implements IdBinder {
return sb.toString();
}
public void createLdapNameById(LdapName name, Object id) throws InvalidNameException {
if (id instanceof Map<?,?> == false){
throw new RuntimeException("Expecting a Map for concatinated key");
}
Map<?,?> mapId = (Map<?,?>)id;
for (int i = 0; i < props.length; i++) {
Object v = mapId.get(props[i].getName());
if (v == null){
throw new RuntimeException("No value in Map for key "+props[i].getName());
}
Rdn rdn = new Rdn(props[i].getDbColumn(), v);
name.add(rdn);
}
}
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
@@ -109,19 +88,11 @@ public final class IdBinderMultiple implements IdBinder {
}
}
public void createLdapNameByBean(LdapName name, Object bean) throws InvalidNameException {
for (int i = 0; i < props.length; i++) {
Object v = props[i].getValue(bean);
Rdn rdn = new Rdn(props[i].getDbColumn(), v);
name.add(rdn);
}
}
public int getPropertyCount() {
return props.length;
}
public int getPropertyCount() {
return props.length;
}
public String getIdProperty() {
return idProperties;
@@ -229,40 +200,6 @@ public final class IdBinderMultiple implements IdBinder {
}
}
public Object readTerm(String idTermValue) {
String[] split = idTermValue.split("|");
if (split.length != props.length){
String msg = "Failed to split ["+idTermValue+"] using | for id.";
throw new PersistenceException(msg);
}
Map<String, Object> uidMap = new LinkedHashMap<String, Object>();
for (int i = 0; i < props.length; i++) {
Object v = props[i].getScalarType().parse(split[i]);
uidMap.put(props[i].getName(), v);
}
return uidMap;
}
@SuppressWarnings("unchecked")
public String writeTerm(Object idValue) {
Map<String, ?> uidMap = (Map<String, ?>) idValue;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
Object v = uidMap.get(props[i].getName());
String formatValue = props[i].getScalarType().format(v);
if (i > 0){
sb.append("|");
}
sb.append(formatValue);
}
return sb.toString();
}
public Object readData(DataInput dataInput) throws IOException {
LinkedHashMap<String,Object> map = new LinkedHashMap<String, Object>();
@@ -6,10 +6,6 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.core.InternString;
@@ -48,14 +44,6 @@ public final class IdBinderSimple implements IdBinder {
// do nothing
}
public Object readTerm(String idTermValue) {
return scalarType.parse(idTermValue);
}
public String writeTerm(Object idValue) {
return scalarType.format(idValue);
}
public String getOrderBy(String pathPrefix, boolean ascending){
StringBuilder sb = new StringBuilder();
@@ -73,16 +61,6 @@ public final class IdBinderSimple implements IdBinder {
idProperty.buildSelectExpressionChain(prefix, selectChain);
}
public void createLdapNameById(LdapName name, Object id) throws InvalidNameException {
Rdn rdn = new Rdn(idProperty.getDbColumn(), id);
name.add(rdn);
}
public void createLdapNameByBean(LdapName name, Object bean) throws InvalidNameException {
Object id = idProperty.getValue(bean);
createLdapNameById(name, id);
}
/**
* Returns 1.
@@ -13,7 +13,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.Query.UseIndex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.annotation.ConcurrencyMode;
import com.avaje.ebean.config.TableName;
import com.avaje.ebean.config.dbplatform.IdGenerator;
@@ -22,7 +24,6 @@ import com.avaje.ebean.event.BeanFinder;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.meta.MetaAutoFetchStatistic;
import com.avaje.ebeaninternal.server.core.CacheOptions;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistController;
@@ -34,8 +35,6 @@ import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.reflect.BeanReflect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Describes Beans including their deployment information.
@@ -58,8 +57,6 @@ public class DeployBeanDescriptor<T> {
private static final Logger logger = LoggerFactory.getLogger(DeployBeanDescriptor.class);
private static final String META_BEAN_PREFIX = MetaAutoFetchStatistic.class.getName().substring(0, 20);
/**
* Map of BeanProperty Linked so as to preserve order.
*/
@@ -151,8 +148,6 @@ public class DeployBeanDescriptor<T> {
*/
private BeanFinder<T> beanFinder;
private UseIndex useIndex;
/**
* The table joins for this bean. Server side only.
*/
@@ -181,20 +176,6 @@ public class DeployBeanDescriptor<T> {
return Modifier.isAbstract(beanType.getModifiers());
}
/**
* Return the default UseIndex strategy.
*/
public UseIndex getUseIndex() {
return useIndex;
}
/**
* Set the default UseIndex strategy.
*/
public void setUseIndex(UseIndex useIndex) {
this.useIndex = useIndex;
}
public boolean isScalaObject() {
Class<?>[] interfaces = beanType.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
@@ -247,9 +228,6 @@ public class DeployBeanDescriptor<T> {
*/
public boolean checkReadAndWriteMethods() {
if (isMeta()) {
return true;
}
boolean missingMethods = false;
Iterator<DeployBeanProperty> it = propMap.values().iterator();
@@ -289,22 +267,11 @@ public class DeployBeanDescriptor<T> {
public EntityType getEntityType() {
if (entityType == null) {
entityType = isMeta() ? EntityType.META : EntityType.ORM;
entityType = EntityType.ORM;
}
return entityType;
}
/**
* Return true if this is a Meta entity bean.
* <p>
* The Meta entity beans are not based on real tables but get meta information
* from memory such as all the entity bean meta data.
* </p>
*/
private boolean isMeta() {
return beanType.getName().startsWith(META_BEAN_PREFIX);
}
public void add(DRawSqlMeta rawSqlMeta) {
rawSqlMetas.put(rawSqlMeta.getName(), rawSqlMeta);
if ("default".equals(rawSqlMeta.getName())) {
@@ -788,26 +755,6 @@ public class DeployBeanDescriptor<T> {
return selectClause.substring(0, selectClause.length() - 1);
}
/**
* Return an Array of properties to include in default fetch (for LDAP).
*/
public String[] getDefaultSelectDbArray(Set<String> defaultSelect) {
ArrayList<String> list = new ArrayList<String>();
for (DeployBeanProperty p : propMap.values()) {
if (defaultSelect != null) {
if (defaultSelect.contains(p.getName())) {
// properties in defaultSelect
list.add(p.getDbColumn());
}
} else if (!p.isTransient() && p.isDbRead()) {
// non transient db properties
list.add(p.getDbColumn());
}
}
return list.toArray(new String[list.size()]);
}
/**
* Parse the include separating by comma or semicolon.
*/
@@ -6,10 +6,7 @@ import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import com.avaje.ebean.Query.UseIndex;
import com.avaje.ebean.annotation.CacheStrategy;
import com.avaje.ebean.annotation.EntityConcurrencyMode;
import com.avaje.ebean.annotation.NamedUpdate;
@@ -54,18 +51,6 @@ public class AnnotationClass extends AnnotationParser {
}
}
private boolean isXmlElement(Class<?> cls) {
XmlRootElement rootElement = cls.getAnnotation(XmlRootElement.class);
if (rootElement != null) {
return true;
}
XmlType xmlType = cls.getAnnotation(XmlType.class);
if (xmlType != null) {
return true;
}
return false;
}
private void read(Class<?> cls) {
Entity entity = cls.getAnnotation(Entity.class);
@@ -77,9 +62,6 @@ public class AnnotationClass extends AnnotationParser {
} else {
descriptor.setName(entity.name());
}
} else if (isXmlElement(cls)) {
descriptor.setName(cls.getSimpleName());
descriptor.setEntityType(EntityType.XMLELEMENT);
}
Embeddable embeddable = cls.getAnnotation(Embeddable.class);
@@ -152,11 +134,6 @@ public class AnnotationClass extends AnnotationParser {
cacheOptions.setNaturalKey(propName);
}
}
if (!UseIndex.DEFAULT.equals(cacheStrategy.useIndex())) {
// a specific text index strategy has been defined
descriptor.setUseIndex(cacheStrategy.useIndex());
}
}
private void readNamedQueries(NamedQueries namedQueries) {
@@ -14,51 +14,39 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue;
*/
public abstract class AbstractExpression implements SpiExpression {
private static final long serialVersionUID = 4072786211853856174L;
protected final String propName;
protected final FilterExprPath pathPrefix;
protected AbstractExpression(FilterExprPath pathPrefix, String propName) {
this.pathPrefix = pathPrefix;
this.propName = propName;
}
private static final long serialVersionUID = 4072786211853856174L;
public String getPropertyName() {
if (pathPrefix == null){
return propName;
} else {
String path = pathPrefix.getPath();
if (path == null || path.length() == 0){
return propName;
} else {
return path+"."+propName;
}
}
}
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
protected final String propName;
String propertyName = getPropertyName();
if (propertyName != null){
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propertyName);
if (elProp != null) {
if (elProp.containsFormulaWithJoin()) {
// for findRowCount query select clause
manyWhereJoin.addFormulaWithJoin(propertyName);
}
if (elProp.containsMany()){
// for findRowCount we join to a many property
protected AbstractExpression(String propName) {
this.propName = propName;
}
public String getPropertyName() {
return propName;
}
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
String propertyName = getPropertyName();
if (propertyName != null) {
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propertyName);
if (elProp != null) {
if (elProp.containsFormulaWithJoin()) {
// for findRowCount query select clause
manyWhereJoin.addFormulaWithJoin(propertyName);
}
if (elProp.containsMany()) {
// for findRowCount we join to a many property
manyWhereJoin.add(elProp);
}
}
}
}
protected ElPropertyValue getElProp(SpiExpressionRequest request) {
String propertyName = getPropertyName();
return request.getBeanDescriptor().getElGetValue(propertyName);
}
}
}
}
protected ElPropertyValue getElProp(SpiExpressionRequest request) {
String propertyName = getPropertyName();
return request.getBeanDescriptor().getElGetValue(propertyName);
}
}
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.expression;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import com.avaje.ebean.event.BeanQueryRequest;
@@ -20,24 +19,12 @@ class AllEqualsExpression implements SpiExpression {
private final Map<String, Object> propMap;
private final FilterExprPath pathPrefix;
AllEqualsExpression(FilterExprPath pathPrefix, Map<String, Object> propMap) {
this.pathPrefix = pathPrefix;
AllEqualsExpression(Map<String, Object> propMap) {
this.propMap = propMap;
}
protected String name(String propName) {
if (pathPrefix == null) {
return propName;
} else {
String path = pathPrefix.getPath();
if (path == null || path.length() == 0) {
return propName;
} else {
return path + "." + propName;
}
}
return propName;
}
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -127,7 +114,7 @@ class AllEqualsExpression implements SpiExpression {
int hc = 31;
for (Object value : propMap.values()) {
hc = hc * 31 + Objects.hashCode(value);
hc = hc * 31 + (value == null ? 0 : value.hashCode());
}
return hc;
@@ -15,8 +15,8 @@ class BetweenExpression extends AbstractExpression {
private final Object valueLow;
BetweenExpression(FilterExprPath pathPrefix, String propertyName, Object valLo, Object valHigh) {
super(pathPrefix, propertyName);
BetweenExpression(String propertyName, Object valLo, Object valHigh) {
super(propertyName);
this.valueLow = valLo;
this.valueHigh = valHigh;
}
@@ -10,8 +10,6 @@ import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
/**
* Between expression where a value is between two properties.
*
* @author rbygrave
*/
class BetweenPropertyExpression implements SpiExpression {
@@ -19,29 +17,18 @@ class BetweenPropertyExpression implements SpiExpression {
private static final String BETWEEN = " between ";
private final FilterExprPath pathPrefix;
private final String lowProperty;
private final String highProperty;
private final Object value;
BetweenPropertyExpression(FilterExprPath pathPrefix, String lowProperty, String highProperty, Object value) {
this.pathPrefix = pathPrefix;
BetweenPropertyExpression(String lowProperty, String highProperty, Object value) {
this.lowProperty = lowProperty;
this.highProperty = highProperty;
this.value = value;
}
protected String name(String propName) {
if (pathPrefix == null) {
return propName;
} else {
String path = pathPrefix.getPath();
if (path == null || path.length() == 0) {
return propName;
} else {
return path + "." + propName;
}
}
return propName;
}
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -11,8 +11,8 @@ class CaseInsensitiveEqualExpression extends AbstractExpression {
private final String value;
CaseInsensitiveEqualExpression(FilterExprPath pathPrefix, String propertyName, String value) {
super(pathPrefix, propertyName);
CaseInsensitiveEqualExpression(String propertyName, String value) {
super(propertyName);
this.value = value.toLowerCase();
}
@@ -66,8 +66,6 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
*/
private ArrayList<SpiExpression> list;
private final FilterExprPath pathPrefix;
/**
* Construct the query by example expression.
*
@@ -78,8 +76,7 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
* @param likeType
* the type of Like wild card used
*/
public DefaultExampleExpression(FilterExprPath pathPrefix, Object entity, boolean caseInsensitive, LikeType likeType) {
this.pathPrefix = pathPrefix;
public DefaultExampleExpression(Object entity, boolean caseInsensitive, LikeType likeType) {
this.entity = entity;
this.caseInsensitive = caseInsensitive;
this.likeType = likeType;
@@ -217,13 +214,13 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
if (beanProperty.isScalar() && value != null) {
if (value instanceof String) {
list.add(new LikeExpression(pathPrefix, propName, (String) value, caseInsensitive, likeType));
list.add(new LikeExpression(propName, (String) value, caseInsensitive, likeType));
} else {
if (!includeZeros && isZero(value)) {
// exclude the zero values typically to weed out
// primitive int and long that initialise to 0
} else {
list.add(new SimpleExpression(pathPrefix, propName, SimpleExpression.Op.EQ, value));
list.add(new SimpleExpression(propName, SimpleExpression.Op.EQ, value));
}
}
}
@@ -21,19 +21,11 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
private static final Object[] EMPTY_ARRAY = new Object[] {};
private final FilterExprPath prefix = null;
public DefaultExpressionFactory() {
//this();//null);
}
// public DefaultExpressionFactory(FilterExprPath prefix) {
// this.prefix = prefix;
// }
public ExpressionFactory createExpressionFactory(){//FilterExprPath prefix) {
public ExpressionFactory createExpressionFactory(){
return this;
//return new DefaultExpressionFactory(prefix);
}
public String getLang() {
@@ -47,7 +39,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
if (value == null) {
return isNull(propertyName);
}
return new SimpleExpression(prefix, propertyName, SimpleExpression.Op.EQ, value);
return new SimpleExpression(propertyName, SimpleExpression.Op.EQ, value);
}
/**
@@ -57,7 +49,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
if (value == null) {
return isNotNull(propertyName);
}
return new SimpleExpression(prefix, propertyName, SimpleExpression.Op.NOT_EQ, value);
return new SimpleExpression(propertyName, SimpleExpression.Op.NOT_EQ, value);
}
/**
@@ -68,7 +60,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
if (value == null) {
return isNull(propertyName);
}
return new CaseInsensitiveEqualExpression(prefix, propertyName, value);
return new CaseInsensitiveEqualExpression(propertyName, value);
}
/**
@@ -76,7 +68,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression between(String propertyName, Object value1, Object value2) {
return new BetweenExpression(prefix, propertyName, value1, value2);
return new BetweenExpression(propertyName, value1, value2);
}
/**
@@ -84,7 +76,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression betweenProperties(String lowProperty, String highProperty, Object value) {
return new BetweenPropertyExpression(prefix, lowProperty, highProperty, value);
return new BetweenPropertyExpression(lowProperty, highProperty, value);
}
/**
@@ -92,7 +84,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression gt(String propertyName, Object value) {
return new SimpleExpression(prefix, propertyName, SimpleExpression.Op.GT, value);
return new SimpleExpression(propertyName, SimpleExpression.Op.GT, value);
}
/**
@@ -101,7 +93,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression ge(String propertyName, Object value) {
return new SimpleExpression(prefix, propertyName, SimpleExpression.Op.GT_EQ, value);
return new SimpleExpression(propertyName, SimpleExpression.Op.GT_EQ, value);
}
/**
@@ -109,7 +101,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression lt(String propertyName, Object value) {
return new SimpleExpression(prefix, propertyName, SimpleExpression.Op.LT, value);
return new SimpleExpression(propertyName, SimpleExpression.Op.LT, value);
}
/**
@@ -117,7 +109,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression le(String propertyName, Object value) {
return new SimpleExpression(prefix, propertyName, SimpleExpression.Op.LT_EQ, value);
return new SimpleExpression(propertyName, SimpleExpression.Op.LT_EQ, value);
}
/**
@@ -125,7 +117,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression isNull(String propertyName) {
return new NullExpression(prefix, propertyName, false);
return new NullExpression(propertyName, false);
}
/**
@@ -133,14 +125,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
public Expression isNotNull(String propertyName) {
return new NullExpression(prefix, propertyName, true);
return new NullExpression(propertyName, true);
}
/**
* Case insensitive {@link #exampleLike(Object)}
*/
public ExampleExpression iexampleLike(Object example) {
return new DefaultExampleExpression(prefix, example, true, LikeType.RAW);
return new DefaultExampleExpression(example, true, LikeType.RAW);
}
/**
@@ -148,14 +140,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* LikeType.RAW (you need to add you own wildcards % and _).
*/
public ExampleExpression exampleLike(Object example) {
return new DefaultExampleExpression(prefix, example, false, LikeType.RAW);
return new DefaultExampleExpression(example, false, LikeType.RAW);
}
/**
* Create the query by Example expression specifying more options.
*/
public ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType) {
return new DefaultExampleExpression(prefix, example, caseInsensitive, likeType);
return new DefaultExampleExpression(example, caseInsensitive, likeType);
}
/**
@@ -163,7 +155,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* characters % (percentage) and _ (underscore).
*/
public Expression like(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, false, LikeType.RAW);
return new LikeExpression(propertyName, value, false, LikeType.RAW);
}
/**
@@ -172,14 +164,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* a lower() function to make the expression case insensitive.
*/
public Expression ilike(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, true, LikeType.RAW);
return new LikeExpression(propertyName, value, true, LikeType.RAW);
}
/**
* Starts With - property like value%.
*/
public Expression startsWith(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, false, LikeType.STARTS_WITH);
return new LikeExpression(propertyName, value, false, LikeType.STARTS_WITH);
}
/**
@@ -187,14 +179,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* lower() function to make the expression case insensitive.
*/
public Expression istartsWith(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, true, LikeType.STARTS_WITH);
return new LikeExpression(propertyName, value, true, LikeType.STARTS_WITH);
}
/**
* Ends With - property like %value.
*/
public Expression endsWith(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, false, LikeType.ENDS_WITH);
return new LikeExpression(propertyName, value, false, LikeType.ENDS_WITH);
}
/**
@@ -202,14 +194,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* function to make the expression case insensitive.
*/
public Expression iendsWith(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, true, LikeType.ENDS_WITH);
return new LikeExpression(propertyName, value, true, LikeType.ENDS_WITH);
}
/**
* Contains - property like %value%.
*/
public Expression contains(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, false, LikeType.CONTAINS);
return new LikeExpression(propertyName, value, false, LikeType.CONTAINS);
}
/**
@@ -217,28 +209,28 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* function to make the expression case insensitive.
*/
public Expression icontains(String propertyName, String value) {
return new LikeExpression(prefix, propertyName, value, true, LikeType.CONTAINS);
return new LikeExpression(propertyName, value, true, LikeType.CONTAINS);
}
/**
* In - property has a value in the array of values.
*/
public Expression in(String propertyName, Object[] values) {
return new InExpression(prefix, propertyName, values);
return new InExpression(propertyName, values);
}
/**
* In - using a subQuery.
*/
public Expression in(String propertyName, Query<?> subQuery) {
return new InQueryExpression(prefix, propertyName, (SpiQuery<?>) subQuery);
return new InQueryExpression(propertyName, (SpiQuery<?>) subQuery);
}
/**
* In - property has a value in the collection of values.
*/
public Expression in(String propertyName, Collection<?> values) {
return new InExpression(prefix, propertyName, values);
return new InExpression(propertyName, values);
}
/**
@@ -269,7 +261,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* a map keyed by property names.
*/
public Expression allEq(Map<String, Object> propertyMap) {
return new AllEqualsExpression(prefix, propertyMap);
return new AllEqualsExpression(propertyMap);
}
/**
@@ -13,13 +13,13 @@ class InExpression extends AbstractExpression {
private final Object[] values;
InExpression(FilterExprPath pathPrefix, String propertyName, Collection<?> coll) {
super(pathPrefix, propertyName);
InExpression(String propertyName, Collection<?> coll) {
super(propertyName);
values = coll.toArray(new Object[coll.size()]);
}
InExpression(FilterExprPath pathPrefix, String propertyName, Object[] array) {
super(pathPrefix, propertyName);
InExpression(String propertyName, Object[] array) {
super(propertyName);
this.values = array;
}
@@ -22,8 +22,8 @@ class InQueryExpression extends AbstractExpression {
private transient CQuery<?> compiledSubQuery;
public InQueryExpression(FilterExprPath pathPrefix, String propertyName, SpiQuery<?> subQuery) {
super(pathPrefix, propertyName);
public InQueryExpression(String propertyName, SpiQuery<?> subQuery) {
super(propertyName);
this.subQuery = subQuery;
}
@@ -14,7 +14,6 @@ import com.avaje.ebean.Junction;
import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PagingList;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
@@ -375,18 +374,10 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
return exprList.select(properties);
}
public com.avaje.ebean.Query<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
return exprList.setBackgroundFetchAfter(backgroundFetchAfter);
}
public com.avaje.ebean.Query<T> setFirstRow(int firstRow) {
return exprList.setFirstRow(firstRow);
}
public com.avaje.ebean.Query<T> setListener(QueryListener<T> queryListener) {
return exprList.setListener(queryListener);
}
public com.avaje.ebean.Query<T> setMapKey(String mapKey) {
return exprList.setMapKey(mapKey);
}
@@ -16,8 +16,8 @@ class LikeExpression extends AbstractExpression {
private final LikeType type;
LikeExpression(FilterExprPath pathPrefix, String propertyName, String value, boolean caseInsensitive, LikeType type) {
super(pathPrefix, propertyName);
LikeExpression(String propertyName, String value, boolean caseInsensitive, LikeType type) {
super(propertyName);
this.caseInsensitive = caseInsensitive;
this.type = type;
this.val = value;
@@ -43,7 +43,8 @@ final class NotExpression implements SpiExpression {
}
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
queryAutoFetchHash(builder);
builder.add(NotExpression.class);
exp.queryPlanHash(request, builder);
}
public int queryBindHash() {
@@ -15,8 +15,8 @@ class NullExpression extends AbstractExpression {
private final boolean notNull;
NullExpression(FilterExprPath pathPrefix, String propertyName, boolean notNull) {
super(pathPrefix, propertyName);
NullExpression(String propertyName, boolean notNull) {
super(propertyName);
this.notNull = notNull;
}
@@ -33,8 +33,8 @@ public class SimpleExpression extends AbstractExpression {
private final Object value;
public SimpleExpression(FilterExprPath pathPrefix, String propertyName, Op type, Object value) {
super(pathPrefix, propertyName);
public SimpleExpression(String propertyName, Op type, Object value) {
super(propertyName);
this.type = type;
this.value = value;
}
@@ -597,12 +597,35 @@ public class DataSourcePool implements DataSource {
*/
protected void returnConnection(PooledConnection pooledConnection) {
if (poolListener != null) {
poolListener.onBeforeReturnConnection(pooledConnection);
}
queue.returnPooledConnection(pooledConnection);
// return a normal 'good' connection
returnTheConnection(pooledConnection, false);
}
/**
* This is a bad connection and must be removed from the pool's busy list and fully closed.
*/
protected void returnConnectionForceClose(PooledConnection pooledConnection) {
returnTheConnection(pooledConnection, true);
}
/**
* Return connection. If forceClose is true then this is a bad connection that
* must be removed and closed fully.
*/
private void returnTheConnection(PooledConnection pooledConnection, boolean forceClose) {
if (poolListener != null && !forceClose) {
poolListener.onBeforeReturnConnection(pooledConnection);
}
queue.returnPooledConnection(pooledConnection, forceClose);
if (forceClose) {
// Got a bad connection so check the pool
checkDataSource();
}
}
/**
* Collect statistics of a connection that is fully closing
*/
@@ -508,9 +508,8 @@ public class PooledConnection extends ConnectionDelegator {
if (hadErrors) {
if (!pool.validateConnection(this)) {
// the connection is BAD, close it and test the pool
closeConnectionFully(false);
pool.checkDataSource();
// the connection is BAD, remove it, close it and test the pool
pool.returnConnectionForceClose(this);
return;
}
}
@@ -535,10 +534,9 @@ public class PooledConnection extends ConnectionDelegator {
pool.returnConnection(this);
} catch (Exception ex) {
// the connection is BAD, close it and test the pool
// the connection is BAD, remove it, close it and test the pool
logger.warn("Error when trying to return connection to pool, closing fully.", ex);
closeConnectionFully(false);
pool.checkDataSource();
pool.returnConnectionForceClose(this);
}
}
@@ -238,7 +238,7 @@ public class PooledConnectionQueue {
/**
* Return a PooledConnection.
*/
protected void returnPooledConnection(PooledConnection c) {
protected void returnPooledConnection(PooledConnection c, boolean forceClose) {
final ReentrantLock lock = this.lock;
lock.lock();
@@ -246,7 +246,7 @@ public class PooledConnectionQueue {
if (!busyList.remove(c)) {
logger.error("Connection [{}] not found in BusyList? ", c);
}
if (c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) {
if (forceClose || c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) {
c.closeConnectionFully(false);
} else {
@@ -28,8 +28,9 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
super(parent, desc, path, defaultBatchSize, queryProps);
this.currentBuffer = createBuffer(firstBatchSize);
this.bufferList = queryFetch ? new ArrayList<DLoadBeanContext.LoadBuffer>() : null;
// bufferList only required when using query joins (queryFetch)
this.bufferList = (!queryFetch) ? null : new ArrayList<DLoadBeanContext.LoadBuffer>();
this.currentBuffer = createBuffer(firstBatchSize);
}
protected void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
@@ -51,11 +52,11 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
protected void register(EntityBeanIntercept ebi){
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext());
if (currentBuffer.add(ebi)) {
// the currentBuffer is full so create another one
if (currentBuffer.isFull()) {
currentBuffer = createBuffer(secondaryBatchSize);
}
currentBuffer.add(ebi);
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext());
}
private LoadBuffer createBuffer(int size) {
@@ -98,22 +99,29 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
*/
public static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
private final PersistenceContext persistenceContext;
private final DLoadBeanContext context;
private final int batchSize;
private final List<EntityBeanIntercept> list;
public LoadBuffer(DLoadBeanContext context, int batchSize) {
this.context = context;
// set the persistence context as at this moment in
// case it changes as part of a findIterate etc
this.persistenceContext = context.getPersistenceContext();
this.batchSize = batchSize;
this.list = new ArrayList<EntityBeanIntercept>(batchSize);
}
public boolean isFull() {
return batchSize == list.size();
}
/**
* Return true if the buffer is full.
*/
public boolean add(EntityBeanIntercept ebi) {
public void add(EntityBeanIntercept ebi) {
list.add(ebi);
return batchSize == list.size();
}
@Override
@@ -138,7 +146,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
@Override
public PersistenceContext getPersistenceContext() {
return context.getPersistenceContext();
return persistenceContext;
}
@Override
@@ -52,12 +52,14 @@ public class DLoadContext implements LoadContext {
private List<OrmQueryProperties> secQuery;
public DLoadContext(SpiEbeanServer ebeanServer, BeanDescriptor<?> rootDescriptor, Boolean readOnly, SpiQuery<?> query) {
public DLoadContext(OrmQueryRequest<?> request) {
this.ebeanServer = ebeanServer;
this.persistenceContext = request.getPersistenceContext();
this.ebeanServer = request.getServer();
this.defaultBatchSize = ebeanServer.getLazyLoadBatchSize();
this.rootDescriptor = rootDescriptor;
this.readOnly = readOnly;
this.rootDescriptor = request.getBeanDescriptor();
SpiQuery<?> query = request.getQuery();
this.readOnly = query.isReadOnly();
this.excludeBeanCache = Boolean.FALSE.equals(query.isUseBeanCache());
this.useAutofetchManager = query.getAutoFetchManager() != null;
@@ -17,70 +17,71 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
public class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
protected final BeanPropertyAssocMany<?> property;
private List<LoadBuffer> bufferList;
private LoadBuffer currentBuffer;
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property,
String path, int defaultBatchSize, OrmQueryProperties queryProps) {
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property, String path, int defaultBatchSize,
OrmQueryProperties queryProps) {
this.property = property;
this.bufferList = new ArrayList<DLoadManyContext.LoadBuffer>();
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
this.property = property;
// bufferList only required when using query joins (queryFetch)
this.bufferList = (!queryFetch) ? null : new ArrayList<DLoadManyContext.LoadBuffer>();
this.currentBuffer = createBuffer(firstBatchSize);
}
}
private LoadBuffer createBuffer(int size) {
LoadBuffer buffer = new LoadBuffer(this, size);
bufferList.add(buffer);
if (bufferList != null) {
bufferList.add(buffer);
}
return buffer;
}
public void configureQuery(SpiQuery<?> query){
// propagate the readOnly state
if (parent.isReadOnly() != null){
query.setReadOnly(parent.isReadOnly());
}
query.setParentNode(objectGraphNode);
if (queryProps != null){
queryProps.configureBeanQuery(query);
}
if (parent.isUseAutofetchManager()){
query.setAutofetch(true);
}
}
public BeanPropertyAssocMany<?> getBeanProperty() {
return property;
}
public void configureQuery(SpiQuery<?> query) {
public BeanDescriptor<?> getBeanDescriptor() {
return desc;
}
// propagate the readOnly state
if (parent.isReadOnly() != null) {
query.setReadOnly(parent.isReadOnly());
}
query.setParentNode(objectGraphNode);
public String getName() {
return parent.getEbeanServer().getName();
}
if (queryProps != null) {
queryProps.configureBeanQuery(query);
}
public void register(BeanCollection<?> bc){
bc.setLoader(0, currentBuffer);
if (currentBuffer.add(bc)) {
// the currentBuffer is full so create another one
if (parent.isUseAutofetchManager()) {
query.setAutofetch(true);
}
}
public BeanPropertyAssocMany<?> getBeanProperty() {
return property;
}
public BeanDescriptor<?> getBeanDescriptor() {
return desc;
}
public String getName() {
return parent.getEbeanServer().getName();
}
public void register(BeanCollection<?> bc) {
if (currentBuffer.isFull()) {
currentBuffer = createBuffer(secondaryBatchSize);
}
}
currentBuffer.add(bc);
bc.setLoader(0, currentBuffer);
}
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all){
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all) {
if (!queryFetch) {
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
@@ -89,33 +90,38 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) {
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest.getTransaction(), requestedBatchSize, false, false, false);
parent.getEbeanServer().loadMany(req);
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest.getTransaction(), requestedBatchSize,
false, false, false);
parent.getEbeanServer().loadMany(req);
if (!queryProps.isQueryFetchAll()) {
// Stop - only fetch the first batch ... the rest will be lazy loaded
break;
}
}
}
// this is only run once - secondary query is a one shot deal
this.bufferList = null;
}
}
}
}
/**
* A buffer for batch loading bean collections on a given path.
* Supports batch lazy loading and secondary query loading.
* A buffer for batch loading bean collections on a given path. Supports batch lazy loading and
* secondary query loading.
*/
public static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
private final PersistenceContext persistenceContext;
private final DLoadManyContext context;
private final int batchSize;
private final List<BeanCollection<?>> list;
public LoadBuffer(DLoadManyContext context, int batchSize) {
this.context = context;
// set the persistence context as at this moment in
// case it changes as part of a findIterate etc
this.persistenceContext = context.getPersistenceContext();
this.batchSize = batchSize;
this.list = new ArrayList<BeanCollection<?>>(batchSize);
}
@@ -123,11 +129,17 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
/**
* Return true if the buffer is full.
*/
public boolean add(BeanCollection<?> bc) {
list.add(bc);
public boolean isFull() {
return batchSize == list.size();
}
/**
* Return true if the buffer is full.
*/
public void add(BeanCollection<?> bc) {
list.add(bc);
}
@Override
public List<BeanCollection<?>> getBatch() {
return list;
@@ -137,22 +149,22 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
public BeanPropertyAssocMany<?> getBeanProperty() {
return context.property;
}
@Override
public ObjectGraphNode getObjectGraphNode() {
return context.objectGraphNode;
}
@Override
public void configureQuery(SpiQuery<?> query){
public void configureQuery(SpiQuery<?> query) {
context.configureQuery(query);
}
@Override
public String getName() {
return context.serverName;
}
@Override
public BeanDescriptor<?> getBeanDescriptor() {
return context.desc;
@@ -160,9 +172,9 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
@Override
public PersistenceContext getPersistenceContext() {
return context.getPersistenceContext();
return persistenceContext;
}
@Override
public String getFullPath() {
return context.fullPath;
@@ -182,9 +194,10 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
return;
}
}
// Should reduce the list by checking each beanCollection in the L2 first before executing the query
// Should reduce the list by checking each beanCollection in the L2 first before executing
// the query
LoadManyRequest req = new LoadManyRequest(this, null, batchSize, true, onlyIds, useCache);
context.parent.getEbeanServer().loadMany(req);
}
@@ -72,17 +72,11 @@ public final class DefaultPersister implements Persister {
private final BeanDescriptorManager beanDescriptorManager;
// private final boolean defaultUpdateNullProperties;
// private final boolean defaultDeleteMissingChildren;
public DefaultPersister(SpiEbeanServer server, Binder binder, BeanDescriptorManager descMgr, PstmtBatch pstmtBatch) {
this.server = server;
this.beanDescriptorManager = descMgr;
this.persistExecute = new DefaultPersistExecute(binder, pstmtBatch);
// this.defaultUpdateNullProperties = server.isDefaultUpdateNullProperties();
// this.defaultDeleteMissingChildren = server.isDefaultDeleteMissingChildren();
}
/**
@@ -508,7 +502,7 @@ public final class DefaultPersister implements Persister {
SqlUpdate sqlDelete = manys[i].deleteByParentId(id, idList);
executeSqlUpdate(sqlDelete, t);
} else {
// we need to fetch the Id's to delete (recurse or notify L2 cache/lucene)
// we need to fetch the Id's to delete (recurse or notify L2 cache)
List<Object> childIds = manys[i].findIdsByParentId(id, idList, t, null);
if (!childIds.isEmpty()) {
delete(targetDesc, null, childIds, t);
@@ -770,7 +764,14 @@ public final class DefaultPersister implements Persister {
// increase depth for batching order
t.depth(+1);
for (Object removedBean : modifyRemovals) {
deleteRecurse(removedBean, t);
if (removedBean instanceof EntityBean) {
EntityBean eb = (EntityBean)removedBean;
if (eb._ebean_getIntercept().isLoaded()) {
// only delete if the bean was loaded meaning that
// it is know to exist in the DB
deleteRecurse(removedBean, t);
}
}
}
t.depth(-1);
}
@@ -47,12 +47,16 @@ public class FactoryBaseProperties {
for (int i = 0; i < props.length; i++) {
if(DmlMode.WHERE.equals(mode) && !withLobs && !props[i].isDbUpdatable()) {
// skip non-updatable column from where clause
} else {
Bindable item = factoryProperty.create(props[i], mode, withLobs);
if (item != null) {
list.add(item);
} else {
// null where readOnly (Secondary tables) or Lob exclusion
}
}
}
}
@@ -14,7 +14,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.EntityBean;
@@ -24,7 +23,6 @@ import com.avaje.ebean.bean.NodeUsageListener;
import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.LoadContext;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
@@ -41,7 +39,6 @@ import com.avaje.ebeaninternal.server.deploy.DbReadContext;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.DataReader;
@@ -135,8 +132,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
private final SpiQuery<T> query;
private final QueryListener<T> queryListener;
private Map<String, String> currentPathMap;
private String currentPrefix;
@@ -189,8 +184,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
*/
private final ElPropertyValue manyPropertyEl;
private final int backgroundFetchAfter;
private final int maxRowsLimit;
/**
@@ -198,8 +191,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
*/
private boolean hasHitBackgroundFetchAfter;
private final PersistenceContext persistenceContext;
private DataReader dataReader;
/**
@@ -276,20 +267,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
this.desc = request.getBeanDescriptor();
this.predicates = predicates;
this.queryListener = query.getListener();
if (queryListener == null) {
// normal, use the one from the transaction
this.persistenceContext = request.getPersistenceContext();
} else {
// 'Row Level Transaction Context'...
// local transaction context that will be reset
// after each 'master' bean is sent to the listener
this.persistenceContext = new DefaultPersistenceContext();
}
this.maxRowsLimit = query.getMaxRows() > 0 ? query.getMaxRows() : GLOBAL_ROW_LIMIT;
this.backgroundFetchAfter = query.getBackgroundFetchAfter() > 0 ? query
.getBackgroundFetchAfter() : Integer.MAX_VALUE;
this.help = createHelp(request);
this.collection = (BeanCollection<T>) (help != null ? help.createEmpty(false) : null);
@@ -386,6 +364,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
if (forwardOnlyHint) {
// Use forward only hints for large resultset processing (Issue 56, MySql specific)
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
pstmt.setFetchSize(Integer.MIN_VALUE);
} else {
pstmt = conn.prepareStatement(sql);
}
@@ -442,7 +421,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
* Return the persistence context.
*/
public PersistenceContext getPersistenceContext() {
return persistenceContext;
return request.getPersistenceContext();
}
public void setLoadedBean(Object bean, Object id, Object lazyLoadParentId) {
@@ -465,7 +444,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
if (lazyLoadParentId != null) {
if (!lazyLoadParentId.equals(this.lazyLoadParentId)) {
// get the appropriate parent bean from the persistence context
this.lazyLoadParentBean = persistenceContext.get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
this.lazyLoadParentBean = getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
this.lazyLoadParentId = lazyLoadParentId;
}
@@ -563,12 +542,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
return false;
}
if (inForeground && loadedBeanCount >= backgroundFetchAfter) {
hasHitBackgroundFetchAfter = true;
collection.setFinishedFetch(false);
return false;
}
if (!manyIncluded) {
// simple query... no details...
return readRow();
@@ -686,13 +659,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
private void readTheRows(boolean inForeground) throws SQLException {
while (hasNextBean(inForeground)) {
if (queryListener != null) {
queryListener.process(getLoadedBean());
} else {
// add to the list/set/map
help.add(collection, getLoadedBean());
}
// add to the list/set/map
help.add(collection, getLoadedBean());
}
}
@@ -73,7 +73,6 @@ public class CQueryFetchIds {
private int rowCount;
private final int maxRows;
private final int bgFetchAfter;
/**
* Create the Sql select based on the request.
@@ -86,7 +85,6 @@ public class CQueryFetchIds {
this.query = request.getQuery();
this.sql = sql;
this.maxRows = query.getMaxRows();
this.bgFetchAfter = query.getBackgroundFetchAfter();
query.setGeneratedSql(sql);
@@ -184,9 +182,6 @@ public class CQueryFetchIds {
hasMoreRows = rset.next();
break;
} else if (bgFetchAfter > 0 && rowCount >= bgFetchAfter) {
useBackgroundToContinueFetch = true;
break;
}
}
@@ -21,7 +21,6 @@ import com.avaje.ebean.OrderBy.Property;
import com.avaje.ebean.PagingList;
import com.avaje.ebean.Query;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.RawSql;
import com.avaje.ebean.bean.BeanCollectionTouched;
@@ -31,7 +30,6 @@ import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.ObjectGraphOrigin;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebean.meta.MetaAutoFetchStatistic;
import com.avaje.ebeaninternal.api.BindParams;
import com.avaje.ebeaninternal.api.HashQuery;
import com.avaje.ebeaninternal.api.HashQueryPlan;
@@ -69,8 +67,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
* Used to add beans to the PersistanceContext prior to query.
*/
private transient ArrayList<EntityBean> contextAdditions;
private transient QueryListener<T> queryListener;
/**
* For lazy loading of ManyToMany we need to add a join to the intersection
@@ -90,9 +86,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
* The name of the query.
*/
private String name;
private UseIndex useIndex;
private Type type;
private Mode mode = Mode.NORMAL;
@@ -145,11 +139,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
private boolean futureFetch;
private List<Object> partialIds;
/**
* The rows after which the fetch continues in a bg thread.
*/
private int backgroundFetchAfter;
private int timeout = -1;
@@ -317,14 +306,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
public MetaAutoFetchStatistic getMetaAutoFetchStatistic() {
if (parentNode != null && server != null){
ObjectGraphOrigin origin = parentNode.getOriginQueryPoint();
return server.find(MetaAutoFetchStatistic.class, origin.getKey());
}
return null;
}
/**
* Return true if the where expressions contains a many property.
@@ -448,7 +429,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
copy.additionalWhere = additionalWhere;
copy.additionalHaving = additionalHaving;
copy.distinct = distinct;
copy.backgroundFetchAfter = backgroundFetchAfter;
copy.timeout = timeout;
copy.mapKey = mapKey;
copy.id = id;
@@ -493,18 +473,9 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
this.type = type;
}
public UseIndex getUseIndex() {
return useIndex;
}
public DefaultOrmQuery<T> setUseIndex(UseIndex useIndex) {
this.useIndex = useIndex;
return this;
}
public String getLoadDescription() {
return loadDescription;
}
public String getLoadDescription() {
return loadDescription;
}
public String getLoadMode() {
return loadMode;
@@ -661,7 +632,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
builder.add((type == null ? 0 : type.ordinal()+1));
builder.add(useIndex).add(autoFetchTuned).add(distinct).add(query);
builder.add(autoFetchTuned).add(distinct).add(query);
builder.add(firstRow).add(maxRows).add(orderBy).add(forUpdate);
builder.add(rawWhereClause).add(additionalWhere).add(additionalHaving);
builder.add(mapKey);
@@ -1036,26 +1007,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return this;
}
/**
* Return the findListener is one has been set.
*/
public QueryListener<T> getListener() {
return queryListener;
}
/**
* Set a FindListener. This is designed for large fetches where lots are
* rows are to be processed and instead of returning all the rows they are
* processed one at a time.
* <p>
* Note that the returning List Set or Map will be empty.
* </p>
*/
public DefaultOrmQuery<T> setListener(QueryListener<T> queryListener) {
this.queryListener = queryListener;
return this;
}
public Class<T> getBeanType() {
return beanType;
}
@@ -1132,15 +1083,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return this;
}
public int getBackgroundFetchAfter() {
return backgroundFetchAfter;
}
public DefaultOrmQuery<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
this.backgroundFetchAfter = backgroundFetchAfter;
return this;
}
public Object getId() {
return id;
}
@@ -1255,23 +1197,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return whereExpressions;
}
/**
* Return true if using background fetching or a queryListener.
*/
public boolean createOwnTransaction() {
if (futureFetch){
// the future fetches have already created
// their own transaction
return false;
}
if (backgroundFetchAfter > 0 || queryListener != null) {
// run in own transaction as we can't know how long
// the background fetching will continue etc
return true;
}
return false;
}
public String getGeneratedSql() {
return generatedSql;
}
@@ -5,6 +5,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.Monitor;
@@ -124,7 +126,7 @@ public final class DefaultPersistenceContext implements PersistenceContext {
private ClassContext getClassContext(Class<?> beanType) {
String clsName = beanType.getName();
String clsName = getBeanBaseType(beanType).getName();
ClassContext classMap = typeCache.get(clsName);
if (classMap == null) {
classMap = new ClassContext();
@@ -132,6 +134,16 @@ public final class DefaultPersistenceContext implements PersistenceContext {
}
return classMap;
}
private Class<?> getBeanBaseType(Class<?> beanType) {
Class<?> parent = beanType.getSuperclass();
while (parent != null && parent.isAnnotationPresent(Entity.class)) {
beanType = parent;
parent = parent.getSuperclass();
}
return beanType;
}
private static class ClassContext {
@@ -10,7 +10,7 @@ import com.avaje.ebeaninternal.server.core.PersistRequest;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
/**
* Beans deleted by Id used for updating L2 Cache and Lucene indexes.
* Beans deleted by Id used for updating L2 Cache.
*/
public final class DeleteByIdMap {
@@ -593,12 +593,14 @@ public class JdbcTransaction implements SpiTransaction {
}
connection.commit();
}
// these will not throw an exception
deactivate();
notifyCommit();
} catch (Exception e) {
throw new RollbackException(e);
} finally {
// these will not throw an exception
deactivate();
notifyCommit();
}
}
@@ -634,12 +636,13 @@ public class JdbcTransaction implements SpiTransaction {
try {
connection.rollback();
} catch (Exception ex) {
throw new PersistenceException(ex);
} finally {
// these will not throw an exception
deactivate();
notifyRollback(cause);
} catch (Exception ex) {
throw new PersistenceException(ex);
}
}
@@ -28,8 +28,7 @@ import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
/**
* Manages transactions.
* <p>
* Keeps the Cache, Cluster and Lucene indexes in synch when transactions are
* committed.
* Keeps the Cache and Cluster in synch when transactions are committed.
* </p>
*/
public class TransactionManager {
@@ -426,7 +425,7 @@ public class TransactionManager {
}
} catch (Exception ex) {
String m = "NotifyOfCommit failed. Cache/Lucene potentially not notified.";
String m = "NotifyOfCommit failed. L2 Cache potentially not notified.";
logger.error(m, ex);
}
}
@@ -61,15 +61,6 @@ public class ScalarTypeUtilDate {
public java.util.Date parseDateTime(long systemTimeMillis) {
return new java.util.Date(systemTimeMillis);
}
public Object luceneFromIndexValue(Object value) {
Long l = (Long)value;
return new java.util.Date(l);
}
public Object luceneToIndexValue(Object value) {
return ((java.util.Date)value).getTime();
}
}
public static class DateType extends ScalarTypeBaseDate<java.util.Date> {
@@ -10,7 +10,6 @@ import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -26,10 +25,6 @@ import org.slf4j.LoggerFactory;
import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebeaninternal.api.ClassUtil;
import com.avaje.ebeaninternal.server.util.ClassPathReader;
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
import com.avaje.ebeaninternal.server.util.DefaultClassPathReader;
/**
* Can search the class path for classes using a ClassPathSearchMatcher. A
@@ -45,8 +40,8 @@ public class ClassPathSearch {
private ClassLoader classLoader;
private Object[] classPaths;
private List<Object> classPath = new ArrayList<Object>();
private ClassPathSearchFilter filter;
private ClassPathSearchMatcher matcher;
@@ -79,16 +74,27 @@ public class ClassPathSearch {
classPathReader = (ClassPathReader) ClassUtil.newInstance(cn, this.getClass());
}
classPaths = classPathReader.readPath(classLoader);
Object[] rawClassPaths = classPathReader.readPath(classLoader);
if (classPaths == null || classPaths.length == 0) {
String msg = "ClassPath is EMPTY using ClassPathReader [" + classPathReader + "]";
logger.warn(msg);
if (rawClassPaths == null || rawClassPaths.length == 0) {
logger.warn("ClassPath is EMPTY using ClassPathReader [" + classPathReader + "]");
return;
}
for (int i = 0; i < rawClassPaths.length; i++) {
// check for a jarfile with a manifest classpath (e.g. maven surefire)
List<URI> classPathFromManifest = getClassPathFromManifest(rawClassPaths[i]);
if (classPathFromManifest.isEmpty()) {
classPath.add(rawClassPaths[i]);
} else {
classPath.addAll(classPathFromManifest);
}
}
boolean debug = GlobalProperties.getBoolean("ebean.debug.classpath", false);
if (debug || logger.isTraceEnabled()) {
logger.info("Classpath " + Arrays.toString(classPaths));
if (logger.isDebugEnabled()) {
for (Object entry : classPath) {
logger.debug("Classpath Entry: {}",entry);
}
}
} catch (Exception e) {
@@ -133,47 +139,52 @@ public class ClassPathSearch {
*/
public List<Class<?>> findClasses() throws IOException {
if (classPaths == null || classPaths.length == 0) {
if (classPath.isEmpty()) {
// returning an empty list
return matchList;
}
for (int i = 0; i < classPaths.length; i++) {
int classPathSize = classPath.size();
for (int i = 0; i < classPathSize; i++) {
ClassPathElement element = getClassPathElement(classPaths[i]);
ClassPathElement element = getClassPathElement(classPath.get(i));
if (element.isDirectory()) {
scanDirectory(element);
} else if (element.isJarOrWar()) {
// search name including the ! offset if it is there
if (filter.isSearchJar(element.getJarNameWithOffset())) {
if (classPathSize == 1 || filter.isSearchJar(element.getJarNameWithOffset())) {
scanJar(element);
}
} else {
String msg = "Error: expected classPath entry [" + element
+ "] to be a directory or a .jar file but it is not either of those?";
logger.error(msg);
logger.error("Error: expected classPath entry [" + element+ "] to be a directory or a .jar file but it is not either of those?");
}
}
if (matchList.isEmpty()) {
String msg = "No Entities found in ClassPath using ClassPathReader [" + classPathReader + "] Classpath Searched["
+ Arrays.toString(classPaths) + "]";
logger.warn(msg);
logger.warn("No Entities found in ClassPath using ClassPathReader [" + classPathReader + "] Classpath Searched[" + classPath + "]");
}
return matchList;
}
private ClassPathElement getClassPathElement(Object classPathEntry) {
private ClassPathElement getClassPathElement(Object classPathEntry) throws MalformedURLException {
if (!URL.class.isInstance(classPathEntry)) {
URL fileUrl = null;
if (URI.class.isInstance(classPathEntry)) {
fileUrl = ((URI)classPathEntry).toURL();
} else if (!URL.class.isInstance(classPathEntry)) {
// assumed to be a file path
return new ClassPathElement(classPathEntry.toString());
} else {
fileUrl = (URL) classPathEntry;
}
URL fileUrl = (URL) classPathEntry;
if (!fileUrl.getPath().contains("!")) {
return new ClassPathElement(new File(fileUrl.getFile()));
}
@@ -371,6 +382,34 @@ public class ClassPathSearch {
}
}
/**
* If URL and actually a jarfile with manifest return the derived classpath.
*/
private static List<URI> getClassPathFromManifest(Object classPathElement) {
try {
if (classPathElement instanceof URL) {
File file = new File(((URL)classPathElement).getFile());
if (file.isDirectory()) {
return Collections.emptyList();
}
JarFile jarFile = new JarFile(file);
try {
return getClassPathFromManifest(file, jarFile.getManifest());
} finally {
jarFile.close();
}
}
return Collections.emptyList();
} catch (IOException e) {
return Collections.emptyList();
}
}
/**
* If a jarfile with a manifest claspath return that.
*/
private static List<URI> getClassPathFromManifest(File jarFile, Manifest manifest) {
if (manifest == null) {
@@ -11,9 +11,9 @@ public class ClassPathSearchFilter {
private static final String COM_AVAJE_EBEANINTERNAL_SERVER_BEAN = "com.avaje.ebeaninternal.server.bean";
private static final String COM_AVAJE_EBEAN_META = "com.avaje.ebean.meta";
private static final String COM_AVAJE_EBEAN_META = "com.avaje.ebean.meta";
private boolean defaultPackageMatch = true;
private boolean defaultPackageMatch = true;
private boolean defaultJarMatch = false;
@@ -121,7 +121,7 @@ public class ClassPathSearchFilter {
* Add a jar to explicitly exclude in the search.
*/
public void excludeJar(String jarName) {
includeJarSet.add(jarName);
excludeJarSet.add(jarName);
}
/**
@@ -129,7 +129,6 @@ public class ClassPathSearchFilter {
*/
public void includeJar(String jarName) {
includeJarSet.add(jarName);
}
/**
@@ -17,7 +17,6 @@ import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PagingList;
import com.avaje.ebean.Query;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
@@ -42,7 +41,6 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
protected transient ExpressionFactory expr;
private final String exprLang;
private final String listAndStart;
private final String listAndEnd;
private final String listAndJoin;
@@ -59,20 +57,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
this.list = list;
this.query = query;
this.expr = expr;
this.exprLang = expr.getLang();
this.parentExprList = parentExprList;
if ("ldap".equals(exprLang)) {
// Language is LDAP
listAndStart = "(&";
listAndEnd = ")";
listAndJoin = "";
} else {
listAndStart = "";
listAndEnd = "";
listAndJoin = " and ";
}
this.listAndStart = "";
this.listAndEnd = "";
this.listAndJoin = " and ";
}
public SpiExpressionList<?> trimPath(int prefixTrim) {
@@ -223,18 +212,10 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.setMaxRows(maxRows);
}
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
return query.setBackgroundFetchAfter(backgroundFetchAfter);
}
public Query<T> setMapKey(String mapKey) {
return query.setMapKey(mapKey);
}
public Query<T> setListener(QueryListener<T> queryListener) {
return query.setListener(queryListener);
}
public Query<T> setUseCache(boolean useCache) {
return query.setUseCache(useCache);
}
@@ -27,14 +27,6 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
this.deployParser = deployParser;
}
// public DefaultExpressionRequest(SpiOrmQueryRequest<?> queryRequest, LIndex
// index) {
// this.queryRequest = queryRequest;
// this.beanDescriptor = queryRequest.getBeanDescriptor();
// this.deployParser = null;
// this.luceneIndex = index;
// }
public DefaultExpressionRequest(BeanDescriptor<?> beanDescriptor) {
this.beanDescriptor = beanDescriptor;
this.queryRequest = null;
@@ -14,7 +14,6 @@ import com.avaje.ebean.FutureRowCount;
import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PagingList;
import com.avaje.ebean.Query;
import com.avaje.ebean.QueryListener;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
@@ -128,18 +127,10 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
throw new PersistenceException(notAllowedMessage);
}
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
return rootQuery.setBackgroundFetchAfter(backgroundFetchAfter);
}
public Query<T> setFirstRow(int firstRow) {
return rootQuery.setFirstRow(firstRow);
}
public Query<T> setListener(QueryListener<T> queryListener) {
return rootQuery.setListener(queryListener);
}
public Query<T> setMapKey(String mapKey) {
return rootQuery.setMapKey(mapKey);
}
@@ -10,7 +10,7 @@ public class BaseTestCase {
static {
logger.debug("... preStart");
if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent","debug=0")) {
if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent","debug=0;packages=com.avaje.tests.**")) {
logger.info("avaje-ebeanorm-agent not found in classpath - not dynamically loaded");
}
}
@@ -47,6 +47,7 @@ public class ClassPathSearchTests {
ClassPathSearchFilter filter = new ClassPathSearchFilter();
filter.includePackage("com.avaje.ebeaninternal.server");
filter.includeJar("WEB-INF");
filter.setDefaultJarMatch(false);
ClassPathSearch search = new ClassPathSearch(cl, filter, new ClassPathSearchMatcher() {
@Override
@@ -1,63 +0,0 @@
package com.avaje.tests.basic;
import junit.framework.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.tests.model.basic.Order;
import com.avaje.tests.model.basic.ResetBasicData;
public class TestBackgroundFetchAfter extends BaseTestCase {
@Test
public void testWrtJoin() {
ResetBasicData.reset();
SpiEbeanServer server = (SpiEbeanServer)Ebean.getServer(null);
boolean h2Db = "h2".equals(server.getDatabasePlatform().getName());
// limit not in sql as join to many
Query<Order> q = Ebean.find(Order.class)
.fetch("details")
.setBackgroundFetchAfter(3)
.setMaxRows(10);
q.findList();
String sql = q.getGeneratedSql();
if (h2Db){
Assert.assertTrue(sql.indexOf("limit") == -1);
}
// allows limit use as no join to many
q = Ebean.find(Order.class)
.setBackgroundFetchAfter(3)
.setMaxRows(10);
q.findList();
sql = q.getGeneratedSql();
if (h2Db){
Assert.assertTrue(sql.indexOf("limit") > -1);
}
// allows limit use as join to one (not many)
q = Ebean.find(Order.class)
.fetch("customer")
.setBackgroundFetchAfter(3)
.setMaxRows(10);
q.findList();
sql = q.getGeneratedSql();
if (h2Db){
Assert.assertTrue(sql.indexOf("limit") > -1);
}
}
}
@@ -0,0 +1,48 @@
package com.avaje.tests.cascade;
import javax.persistence.OptimisticLockException;
import junit.framework.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.basic.TSDetail;
import com.avaje.tests.model.basic.TSMaster;
public class TestPrivateOwnedIgnoreTransientOrphan extends BaseTestCase {
@Test
public void test(){
/** new object **/
TSMaster master0 = new TSMaster();
/** recovered after first save **/
TSMaster master1 = null;
/** recovered after transient child ignored **/
TSMaster master2 = null;
Ebean.save(master0);
master1 = Ebean.find(master0.getClass(), master0.getId());
// Add then remove a bean that was never saved (to the DB)
master1.getDetails().add(new TSDetail());
master1.getDetails().clear();
try{
Ebean.save(master1);
} catch (OptimisticLockException exception) {
// Occured when the "unsaved" bean was wrongly being deleted
Assert.fail("Optimistic lock exception wrongly thrown: " + exception.getMessage());
return;
}
master2 = master1 = Ebean.find(master1.getClass(), master1.getId());
Assert.assertTrue(master2.getDetails().isEmpty());
}
}
@@ -2,6 +2,7 @@ package com.avaje.tests.model.basic;
import java.util.UUID;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@@ -14,7 +15,7 @@ public class UUTwo {
String name;
@ManyToOne
@ManyToOne(cascade=CascadeType.PERSIST)
UUOne master;
public UUID getId() {
@@ -0,0 +1,10 @@
package com.avaje.tests.model.inheritexposedtype;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue( "photo" )
public class IXPhoto extends IXResource {
}
@@ -0,0 +1,46 @@
package com.avaje.tests.model.inheritexposedtype;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class IXResource {
@Id
UUID id;
@Column(insertable=false, updatable=false)
String dtype;
String name;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getDtype() {
return dtype;
}
public void setDtype(String dtype) {
this.dtype = dtype;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,26 @@
package com.avaje.tests.model.inheritexposedtype.test;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.inheritexposedtype.IXPhoto;
public class TestInheritExposeDtype extends BaseTestCase {
@Test
public void test() {
IXPhoto p = new IXPhoto();
p.setName("the name");
Ebean.save(p);
// update
p.setName("new name");
Ebean.save(p);
// delete
Ebean.delete(p);
}
}
@@ -0,0 +1,42 @@
package com.avaje.tests.model.inheritmany;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class IMRelated {
@Id
Long id;
String name;
@ManyToOne(optional=false)
IMRoot owner;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IMRoot getOwner() {
return owner;
}
public void setOwner(IMRoot owner) {
this.owner = owner;
}
}
@@ -0,0 +1,37 @@
package com.avaje.tests.model.inheritmany;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class IMRoot {
@Id
Long id;
@OneToMany(mappedBy="owner")
List<IMRelated> related;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<IMRelated> getRelated() {
return related;
}
public void setRelated(List<IMRelated> related) {
this.related = related;
}
}
@@ -0,0 +1,20 @@
package com.avaje.tests.model.inheritmany;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue("ONE")
public class IMRootOne extends IMRoot {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,32 @@
package com.avaje.tests.model.inheritmany;
import java.util.Date;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue("TWO")
public class IMRootTwo extends IMRoot {
String title;
Date whenTitle;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getWhenTitle() {
return whenTitle;
}
public void setWhenTitle(Date whenTitle) {
this.whenTitle = whenTitle;
}
}
@@ -6,7 +6,6 @@ import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.ebean.Query.UseIndex;
import com.avaje.tests.model.basic.Customer;
import com.avaje.tests.model.basic.ResetBasicData;
@@ -21,7 +20,7 @@ public class TestExprNestedDisjunction extends BaseTestCase {
java.sql.Date onAfter = java.sql.Date.valueOf("2009-08-31");
Query<Customer> q = Ebean.find(Customer.class).setUseIndex(UseIndex.NO).where().disjunction()
Query<Customer> q = Ebean.find(Customer.class).where().disjunction()
.conjunction().startsWith("name", "r").eq("anniversary", onAfter).endJunction()
.conjunction().eq("status", Customer.Status.ACTIVE).gt("id", 0).endJunction().orderBy()
.asc("name");
@@ -0,0 +1,29 @@
package com.avaje.tests.query.other;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.Expression;
import com.avaje.ebean.Query;
import com.avaje.tests.model.basic.Customer;
public class TestSubQueryBinding extends BaseTestCase {
@Test
public void test() {
EbeanServer server = Ebean.getServer(null);
Query<Customer> someCustomerIds = server.find(Customer.class).select("id").where().lt("id", 5).query();
Expression someCustIdsExpression = server.getExpressionFactory().in("id", someCustomerIds);
Query<Customer> query = server.find(Customer.class).where().like("name", "Rob%").not(someCustIdsExpression).query();
query.findList();
}
}
@@ -0,0 +1,67 @@
package com.avaje.tests.update;
import org.junit.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebean.text.json.JsonWriteOptions;
import com.avaje.tests.model.basic.UUOne;
import com.avaje.tests.model.basic.UUTwo;
public class TestJsonStatelessUpdate extends BaseTestCase {
@Test
public void test() {
UUOne one = new UUOne();
one.setName("oneName");
Ebean.save(one);
UUTwo two = new UUTwo();
two.setMaster(one);
two.setName("twoName");
Ebean.save(two);
UUTwo twoX = Ebean.find(UUTwo.class, two.getId());
JsonContext jsonContext = Ebean.createJsonContext();
JsonWriteOptions writeOptions = JsonWriteOptions.parsePath("(id,name,master(*))");
String jsonString = jsonContext.toJsonString(twoX, true, writeOptions);
System.out.println(jsonString);
jsonString = jsonString.replace("twoName", "twoNameModified");
jsonString = jsonString.replace("oneName", "oneNameModified");
UUTwo two2 = jsonContext.toBean(UUTwo.class, jsonString);
Assert.assertEquals(twoX.getId(), two2.getId());
Assert.assertEquals("twoNameModified", two2.getName());
Assert.assertEquals("oneNameModified", two2.getMaster().getName());
// The update below cascades to also save "master" and that fails
// as it thinks it should INSERT master rather than UPDATE master
// Ebean.update(two2);
// The following is a workaround, to explicitly update master first
// so then Ebean doesn't try to save it when two2 is updated
Ebean.beginTransaction();
try {
UUOne master = two2.getMaster();
Ebean.update(master);
Ebean.update(two2);
} finally {
Ebean.endTransaction();
}
}
}
@@ -0,0 +1,73 @@
package org.avaje.test.model.inheritmany.test;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.tests.model.inheritmany.IMRelated;
import com.avaje.tests.model.inheritmany.IMRoot;
import com.avaje.tests.model.inheritmany.IMRootOne;
import com.avaje.tests.model.inheritmany.IMRootTwo;
public class TestInheritWithMany extends BaseTestCase {
@Test
public void test() {
EbeanServer server = Ebean.getServer(null);
Assert.assertNotNull(server);
SpiEbeanServer spiServer = (SpiEbeanServer)server;
BeanDescriptor<IMRoot> beanDescriptor = spiServer.getBeanDescriptor(IMRoot.class);
InheritInfo inheritInfo = beanDescriptor.getInheritInfo();
Assert.assertNotNull(inheritInfo);
IMRootOne one = new IMRootOne();
one.setName("One Name");
server.save(one);
add(one, "aaa");
add(one, "bbb");
IMRootTwo two = new IMRootTwo();
two.setTitle("Two Title");
server.save(two);
add(two, "ccc");
add(two, "ddd");
List<IMRoot> list = server.find(IMRoot.class).select("id").findList();
for (IMRoot imRoot : list) {
// lazy load the related OneToMany which is related to a non-leaf
List<IMRelated> related = imRoot.getRelated();
for (IMRelated imRelated : related) {
imRelated.getName();
}
}
}
private void add(IMRoot owner, String string) {
IMRelated relate = new IMRelated();
relate.setName(string);
relate.setOwner(owner);
EbeanServer server = Ebean.getServer(null);
server.save(relate);
}
}