diff --git a/src/main/java/com/avaje/ebean/annotation/CacheStrategy.java b/src/main/java/com/avaje/ebean/annotation/CacheStrategy.java index 240fcb411..e2a00b2a4 100644 --- a/src/main/java/com/avaje/ebean/annotation/CacheStrategy.java +++ b/src/main/java/com/avaje/ebean/annotation/CacheStrategy.java @@ -1,58 +1,58 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.avaje.ebean.Query; - -/** - * Specify the default cache use specific entity type. - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface CacheStrategy { - - /** - * When set to true the bean cache will be used unless explicitly stated not - * to in a query via {@link Query#setUseCache(boolean)}. - */ - boolean useBeanCache() default true; - - /** - * A single property that is a natural unique identifier for the bean. - *
- * When a findUnique query is used with this property as the sole expression - * then there will be a lookup into the L2 natural key cache. - *
- */ - String naturalKey() default ""; - - /** - * When set to true the beans returned from a query will default to be - * readOnly. - *- * If the bean is readOnly and has no relationships then it may be sharable. - *
- *- * If you try to modify a readOnly bean it will throw an - * IllegalStateException. - *
- */ - boolean readOnly() default false; - - /** - * Specify a query that can be used to warm the cache. - *- * All the beans fetched by this query will be loaded into the bean cache and - * the query itself will be loaded into the query cache. - *
- *- * The warming query will typically be executed at startup time after a short - * delay (defaults to a 30 seconds delay). - *
- */ - String warmingQuery() default ""; - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.avaje.ebean.Query; + +/** + * Specify the default cache use specific entity type. + */ +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface CacheStrategy { + + /** + * When set to true the bean cache will be used unless explicitly stated not + * to in a query via {@link Query#setUseCache(boolean)}. + */ + boolean useBeanCache() default true; + + /** + * A single property that is a natural unique identifier for the bean. + *+ * When a findUnique query is used with this property as the sole expression + * then there will be a lookup into the L2 natural key cache. + *
+ */ + String naturalKey() default ""; + + /** + * When set to true the beans returned from a query will default to be + * readOnly. + *+ * If the bean is readOnly and has no relationships then it may be sharable. + *
+ *+ * If you try to modify a readOnly bean it will throw an + * IllegalStateException. + *
+ */ + boolean readOnly() default false; + + /** + * Specify a query that can be used to warm the cache. + *+ * All the beans fetched by this query will be loaded into the bean cache and + * the query itself will be loaded into the query cache. + *
+ *+ * The warming query will typically be executed at startup time after a short + * delay (defaults to a 30 seconds delay). + *
+ */ + String warmingQuery() default ""; + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/CacheTuning.java b/src/main/java/com/avaje/ebean/annotation/CacheTuning.java index b03d11050..2e5f5065d 100644 --- a/src/main/java/com/avaje/ebean/annotation/CacheTuning.java +++ b/src/main/java/com/avaje/ebean/annotation/CacheTuning.java @@ -1,47 +1,47 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specify cache tuning for a specific entity type. - *- * If this is not specified then the system default settings are used. - *
- */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface CacheTuning { - - /** - * The maximum size for the cache. - *- * This defaults to 0 which means unlimited. - *
- */ - int maxSize() default 0; - - /** - * The maximum time (in seconds) that a cache entry is allowed to stay in the - * cache when it has not been accessed. - *- * This defaults to 0 which means unlimited. - *
- */ - int maxIdleSecs() default 0; - - /** - * The maximum time (in seconds) a cache entry is allowed to stay in the - * cache. - *- * This is not generally required as the cache entries are automatically - * evicted when related data changes are committed. - *
- *- * This defaults to 0 which means unlimited. - *
- */ - int maxSecsToLive() default 0; -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specify cache tuning for a specific entity type. + *+ * If this is not specified then the system default settings are used. + *
+ */ +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface CacheTuning { + + /** + * The maximum size for the cache. + *+ * This defaults to 0 which means unlimited. + *
+ */ + int maxSize() default 0; + + /** + * The maximum time (in seconds) that a cache entry is allowed to stay in the + * cache when it has not been accessed. + *+ * This defaults to 0 which means unlimited. + *
+ */ + int maxIdleSecs() default 0; + + /** + * The maximum time (in seconds) a cache entry is allowed to stay in the + * cache. + *+ * This is not generally required as the cache entries are automatically + * evicted when related data changes are committed. + *
+ *+ * This defaults to 0 which means unlimited. + *
+ */ + int maxSecsToLive() default 0; +}; diff --git a/src/main/java/com/avaje/ebean/annotation/CreatedTimestamp.java b/src/main/java/com/avaje/ebean/annotation/CreatedTimestamp.java index 0d688cd93..abb89788b 100644 --- a/src/main/java/com/avaje/ebean/annotation/CreatedTimestamp.java +++ b/src/main/java/com/avaje/ebean/annotation/CreatedTimestamp.java @@ -1,31 +1,31 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * For a timestamp property that is set to the datetime when the entity is - * created/inserted. - *- * An alternative to using this annotation would be to use insertable=false, - * updateable=false with @Column and have the DB insert the current time - * (default value on the DB column is SYSTIME etc). - *
- *- * The downside to this approach is that the inserted entity does not have the - * timestamp value after the insert has occurred. You need to fetch the entity - * back to get the inserted timestamp if you want to used it. - *
- * - *- * @Column(insertable = false, updateable = false) - * Timestamp cretimestamp; - *- */ -@Target({ ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface CreatedTimestamp { - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * For a timestamp property that is set to the datetime when the entity is + * created/inserted. + *
+ * An alternative to using this annotation would be to use insertable=false, + * updateable=false with @Column and have the DB insert the current time + * (default value on the DB column is SYSTIME etc). + *
+ *+ * The downside to this approach is that the inserted entity does not have the + * timestamp value after the insert has occurred. You need to fetch the entity + * back to get the inserted timestamp if you want to used it. + *
+ * + *+ * @Column(insertable = false, updateable = false) + * Timestamp cretimestamp; + *+ */ +@Target({ ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface CreatedTimestamp { + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/EmbeddedColumns.java b/src/main/java/com/avaje/ebean/annotation/EmbeddedColumns.java index 7393bb5eb..88feaca5c 100644 --- a/src/main/java/com/avaje/ebean/annotation/EmbeddedColumns.java +++ b/src/main/java/com/avaje/ebean/annotation/EmbeddedColumns.java @@ -1,31 +1,31 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specify property name to db column mapping for Embedded beans. - *
- * This is designed to be easier to use than the AttributeOverride annotation in - * standard JPA. - *
- */ -@Target({ ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface EmbeddedColumns { - - /** - * A list of property names mapped to DB columns. - *
- * For example currency=IN_CURR, amount=IN_AMOUNT
- *
- * Where currency and amount are properties and IN_CURR and IN_AMOUNT are the - * respective DB columns these properties will be mapped to. - *
- */ - String columns() default ""; - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specify property name to db column mapping for Embedded beans. + *+ * This is designed to be easier to use than the AttributeOverride annotation in + * standard JPA. + *
+ */ +@Target({ ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface EmbeddedColumns { + + /** + * A list of property names mapped to DB columns. + *
+ * For example currency=IN_CURR, amount=IN_AMOUNT
+ *
+ * Where currency and amount are properties and IN_CURR and IN_AMOUNT are the + * respective DB columns these properties will be mapped to. + *
+ */ + String columns() default ""; + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/Encrypted.java b/src/main/java/com/avaje/ebean/annotation/Encrypted.java index b6c2aff78..a0999f817 100644 --- a/src/main/java/com/avaje/ebean/annotation/Encrypted.java +++ b/src/main/java/com/avaje/ebean/annotation/Encrypted.java @@ -1,24 +1,24 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specify that the property is stored in encrypted form. - */ -@Target({ ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Encrypted { - - /** - * When true try to use DB encryption rather than local java encryption. - */ - boolean dbEncryption() default true; - - /** - * Used to specify the DB column length. - */ - int dbLength() default 0; -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specify that the property is stored in encrypted form. + */ +@Target({ ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Encrypted { + + /** + * When true try to use DB encryption rather than local java encryption. + */ + boolean dbEncryption() default true; + + /** + * Used to specify the DB column length. + */ + int dbLength() default 0; +}; diff --git a/src/main/java/com/avaje/ebean/annotation/EnumMapping.java b/src/main/java/com/avaje/ebean/annotation/EnumMapping.java index 8556527fb..617c052f9 100644 --- a/src/main/java/com/avaje/ebean/annotation/EnumMapping.java +++ b/src/main/java/com/avaje/ebean/annotation/EnumMapping.java @@ -1,90 +1,90 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * For mapping the values of an Enum to and from Database values. - *- * Also refer to the {@link EnumValue} approach which probably the preferred now - * (preferred over using this EnumMapping annotation). - *
- *- * Both of the approaches defined in the JPA have significant problems!!! - *
- *- * Using the ordinal value is VERY RISKY because that depends on the compile - * order of the enum values. Aka if you change the order of the enum values you - * have changed their ordinal values and now your DB values are WRONG - a HUGE - * disaster!!!. - *
- *- * Using the String values of enums is fairly restrictive because in a Database - * these values are usually truncated into short codes (e.g. "A" short for - * "ACTIVE") so space used in the database is minimised. Making your enum names - * match the database values would give them very short less meaningful names - - * not a great solution. - *
- *- * You can use this annotation to control the mapping of your enums to database - * values. - *
- *- * The design of this using nameValuePairs is not optimal for safety or - * refactoring so if you have a better solution I'm all ears. The other - * solutions would probably involve modifying each enumeration with a method - * which may be ok. - *
- *- * An example mapping the UserState enum. - *
- * - *
- * ...
- * @EnumMapping(nameValuePairs="NEW=N, ACTIVE=A, INACTIVE=I")
- * public enum UserState {
- * NEW,
- * ACTIVE,
- * INACTIVE;
- * }
- *
- *
- * @see EnumValue
- */
-@Target({ ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface EnumMapping {
-
- /**
- * A comma delimited list of name=value pairs.
- * - * e.g. "ACTIVE=A, INACTIVE=I, NEW=N". - *
- *- * Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and - * "N" are the database values. - *
- *- * This is not really an optimal approach so if you have a better one I'm all - * ears - thanks. - *
- */ - String nameValuePairs(); - - /** - * Defaults to mapping values to database VARCHAR type. If this is set to true - * then the values will be converted to INTEGER and mapped to the database - * integer type. - *- * e.g. "ACTIVE=1, INACTIVE=0, NEW=2". - *
- */ - boolean integerType() default false; - - /** - * The length of DB column if mapping to string values. - */ - int length() default 0; -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * For mapping the values of an Enum to and from Database values. + *+ * Also refer to the {@link EnumValue} approach which probably the preferred now + * (preferred over using this EnumMapping annotation). + *
+ *+ * Both of the approaches defined in the JPA have significant problems!!! + *
+ *+ * Using the ordinal value is VERY RISKY because that depends on the compile + * order of the enum values. Aka if you change the order of the enum values you + * have changed their ordinal values and now your DB values are WRONG - a HUGE + * disaster!!!. + *
+ *+ * Using the String values of enums is fairly restrictive because in a Database + * these values are usually truncated into short codes (e.g. "A" short for + * "ACTIVE") so space used in the database is minimised. Making your enum names + * match the database values would give them very short less meaningful names - + * not a great solution. + *
+ *+ * You can use this annotation to control the mapping of your enums to database + * values. + *
+ *+ * The design of this using nameValuePairs is not optimal for safety or + * refactoring so if you have a better solution I'm all ears. The other + * solutions would probably involve modifying each enumeration with a method + * which may be ok. + *
+ *+ * An example mapping the UserState enum. + *
+ * + *
+ * ...
+ * @EnumMapping(nameValuePairs="NEW=N, ACTIVE=A, INACTIVE=I")
+ * public enum UserState {
+ * NEW,
+ * ACTIVE,
+ * INACTIVE;
+ * }
+ *
+ *
+ * @see EnumValue
+ */
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnumMapping {
+
+ /**
+ * A comma delimited list of name=value pairs.
+ * + * e.g. "ACTIVE=A, INACTIVE=I, NEW=N". + *
+ *+ * Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and + * "N" are the database values. + *
+ *+ * This is not really an optimal approach so if you have a better one I'm all + * ears - thanks. + *
+ */ + String nameValuePairs(); + + /** + * Defaults to mapping values to database VARCHAR type. If this is set to true + * then the values will be converted to INTEGER and mapped to the database + * integer type. + *+ * e.g. "ACTIVE=1, INACTIVE=0, NEW=2". + *
+ */ + boolean integerType() default false; + + /** + * The length of DB column if mapping to string values. + */ + int length() default 0; +}; diff --git a/src/main/java/com/avaje/ebean/annotation/EnumValue.java b/src/main/java/com/avaje/ebean/annotation/EnumValue.java index de4422e74..9d39d3aaa 100644 --- a/src/main/java/com/avaje/ebean/annotation/EnumValue.java +++ b/src/main/java/com/avaje/ebean/annotation/EnumValue.java @@ -1,46 +1,46 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Enables you to specify a value to use to persist for an enum value. - * - *
- * public enum Status {
- * @EnumValue("N")
- * NEW,
- *
- * @EnumValue("A")
- * ACTIVE,
- *
- * @EnumValue("I")
- * INACTIVE,
- * }
- *
- *
- * - * This is an alternative to using the JPA standard approach or Ebean's - * {@link EnumMapping} annotation. - *
- *- * Note that if all the EnumValue values are parsable as Integers then Ebean - * will persist and fetch them as integers - otherwise they will be persisted - * and fetched as strings. - *
- */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface EnumValue { - - /** - * Specify the value to persist for a specific enum value. - *- * If all the values are parsable as Integers then Ebean will persist and - * fetch them as integers rather than strings. - *
- */ - String value(); -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Enables you to specify a value to use to persist for an enum value. + * + *
+ * public enum Status {
+ * @EnumValue("N")
+ * NEW,
+ *
+ * @EnumValue("A")
+ * ACTIVE,
+ *
+ * @EnumValue("I")
+ * INACTIVE,
+ * }
+ *
+ *
+ * + * This is an alternative to using the JPA standard approach or Ebean's + * {@link EnumMapping} annotation. + *
+ *+ * Note that if all the EnumValue values are parsable as Integers then Ebean + * will persist and fetch them as integers - otherwise they will be persisted + * and fetched as strings. + *
+ */ +@Target({ ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface EnumValue { + + /** + * Specify the value to persist for a specific enum value. + *+ * If all the values are parsable as Integers then Ebean will persist and + * fetch them as integers rather than strings. + *
+ */ + String value(); +}; diff --git a/src/main/java/com/avaje/ebean/annotation/Formula.java b/src/main/java/com/avaje/ebean/annotation/Formula.java index 915cf0deb..a512b90f4 100644 --- a/src/main/java/com/avaje/ebean/annotation/Formula.java +++ b/src/main/java/com/avaje/ebean/annotation/Formula.java @@ -1,103 +1,103 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.avaje.ebean.Query; - -/** - * Assign to a property to be based on a SQL formula. - *- * This is typically a SQL Literal value, SQL case statement, SQL function or - * similar. - *
- *- * Any property based on a formula becomes a read only property. - *
- *- * You may also put use the Transient annotation with the Formula annotation. - * The effect of the Transient annotation in this case is that the formula will - * NOT be included in queries by default - you have to explicitly include - * it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}. - * You may want to do this if the Formula is relatively expensive and only want - * it included in the query when you explicitly state it. - *
- * - *
- * // On the Order "master" bean
- * // ... a formula using the Order details
- * // ... sum(order_qty*unit_price)
- * @Transient
- * @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id")
- * Double totalAmount;
- *
- *
- * - * As the totalAmount formula is also Transient it is not included by default in - * queries - it needs to be explicitly included. - *
- * - *
- * // find by Id
- * Order o1 = Ebean.find(Order.class)
- * .select("id, totalAmount")
- * .setId(1).findUnique();
- *
- * // find list ... using totalAmount in the where clause
- * List<Order> list = Ebean.find(Order.class)
- * .select("id, totalAmount")
- * .where()
- * .eq("status", Order.Status.NEW)
- * .gt("totalAmount", 10)
- * .findList();
- *
- * // as a join from customer
- * List<Customer> l0 = Ebean.find(Customer.class)
- * .select("id, name")
- * .join("orders", "status, totalAmount")
- * .where()
- * .gt("id", 0)
- * .gt("orders.totalAmount", 10)
- * .findList();
- *
- *
- */
-@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Formula {
-
- /**
- * The SQL to be used in the SELECT part of the SQL to populate a property.
- */
- String select();
-
- /**
- * OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
- * formula.
- * - * This is commonly used to join a 'dynamic view' to support aggregation such - * as count, sum etc. - *
- *- * The join string should start with either "left outer join" or "join". - *
- * - *- * You will almost certainly use the "${ta}" as a place holder for the table - * alias of the table you are joining back to (the "base table" of the entity - * bean). - *
- *- * The example below is used to support a total count of topics created by a - * user. - *
- * - *
- * join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
- *
- */
- String join() default "";
-
-};
+package com.avaje.ebean.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.avaje.ebean.Query;
+
+/**
+ * Assign to a property to be based on a SQL formula.
+ * + * This is typically a SQL Literal value, SQL case statement, SQL function or + * similar. + *
+ *+ * Any property based on a formula becomes a read only property. + *
+ *+ * You may also put use the Transient annotation with the Formula annotation. + * The effect of the Transient annotation in this case is that the formula will + * NOT be included in queries by default - you have to explicitly include + * it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}. + * You may want to do this if the Formula is relatively expensive and only want + * it included in the query when you explicitly state it. + *
+ * + *
+ * // On the Order "master" bean
+ * // ... a formula using the Order details
+ * // ... sum(order_qty*unit_price)
+ * @Transient
+ * @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id")
+ * Double totalAmount;
+ *
+ *
+ * + * As the totalAmount formula is also Transient it is not included by default in + * queries - it needs to be explicitly included. + *
+ * + *
+ * // find by Id
+ * Order o1 = Ebean.find(Order.class)
+ * .select("id, totalAmount")
+ * .setId(1).findUnique();
+ *
+ * // find list ... using totalAmount in the where clause
+ * List<Order> list = Ebean.find(Order.class)
+ * .select("id, totalAmount")
+ * .where()
+ * .eq("status", Order.Status.NEW)
+ * .gt("totalAmount", 10)
+ * .findList();
+ *
+ * // as a join from customer
+ * List<Customer> l0 = Ebean.find(Customer.class)
+ * .select("id, name")
+ * .join("orders", "status, totalAmount")
+ * .where()
+ * .gt("id", 0)
+ * .gt("orders.totalAmount", 10)
+ * .findList();
+ *
+ *
+ */
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Formula {
+
+ /**
+ * The SQL to be used in the SELECT part of the SQL to populate a property.
+ */
+ String select();
+
+ /**
+ * OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
+ * formula.
+ * + * This is commonly used to join a 'dynamic view' to support aggregation such + * as count, sum etc. + *
+ *+ * The join string should start with either "left outer join" or "join". + *
+ * + *+ * You will almost certainly use the "${ta}" as a place holder for the table + * alias of the table you are joining back to (the "base table" of the entity + * bean). + *
+ *+ * The example below is used to support a total count of topics created by a + * user. + *
+ * + *
+ * join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
+ *
+ */
+ String join() default "";
+
+};
diff --git a/src/main/java/com/avaje/ebean/annotation/NamedUpdate.java b/src/main/java/com/avaje/ebean/annotation/NamedUpdate.java
index 82ede2e27..ccc614eb4 100644
--- a/src/main/java/com/avaje/ebean/annotation/NamedUpdate.java
+++ b/src/main/java/com/avaje/ebean/annotation/NamedUpdate.java
@@ -1,37 +1,37 @@
-package com.avaje.ebean.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * An Update statement for a particular entity bean type.
- * - * The update can either be a sql insert,update or delete statement with tables - * and columns etc or the equivalent statement but with table names and columns - * expressed as bean types and bean properties. - *
- */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface NamedUpdate { - - /** - * The name of the update. - */ - String name(); - - /** - * The insert, update or delete statement. - */ - String update(); - - /** - * Set this to false if you do not want the cache to be notified. If true the - * cache will invalidate appropriate objects from the cache (after a - * successful transaction commit). - */ - boolean notifyCache() default true; - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An Update statement for a particular entity bean type. + *+ * The update can either be a sql insert,update or delete statement with tables + * and columns etc or the equivalent statement but with table names and columns + * expressed as bean types and bean properties. + *
+ */ +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface NamedUpdate { + + /** + * The name of the update. + */ + String name(); + + /** + * The insert, update or delete statement. + */ + String update(); + + /** + * Set this to false if you do not want the cache to be notified. If true the + * cache will invalidate appropriate objects from the cache (after a + * successful transaction commit). + */ + boolean notifyCache() default true; + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/NamedUpdates.java b/src/main/java/com/avaje/ebean/annotation/NamedUpdates.java index b753d8d5a..8b9daf804 100644 --- a/src/main/java/com/avaje/ebean/annotation/NamedUpdates.java +++ b/src/main/java/com/avaje/ebean/annotation/NamedUpdates.java @@ -1,20 +1,20 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Holds an array of named Update statements for a particular entity bean type. - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface NamedUpdates { - - /** - * An array of named updates. - */ - NamedUpdate[] value(); - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Holds an array of named Update statements for a particular entity bean type. + */ +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface NamedUpdates { + + /** + * An array of named updates. + */ + NamedUpdate[] value(); + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/PrivateOwned.java b/src/main/java/com/avaje/ebean/annotation/PrivateOwned.java index b5406d871..719add194 100644 --- a/src/main/java/com/avaje/ebean/annotation/PrivateOwned.java +++ b/src/main/java/com/avaje/ebean/annotation/PrivateOwned.java @@ -1,34 +1,34 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specify that the elements of a OneToMany are private owned. - *- * This means that if they are removed from the List/Set/Map they will be - * deleted when their parent object is saved. - *
- *- * This could also be described as deleting orphans - in that beans removed from - * the List/Set/Map will be deleted automatically when the parent bean is saved. - * They are considered 'orphans' when they have been removed from the collection - * in that they are no longer associated/linked to their parent bean. - *
- */ -@Target({ ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface PrivateOwned { - - /** - * Set this to false if you don't want cascade REMOVE on this relationship. - *- * That is, by default PrivateOwned implicitly adds a cascade REMOVE to the - * relationship and if you don't want that you need to set this to false. - *
- */ - boolean cascadeRemove() default true; - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specify that the elements of a OneToMany are private owned. + *+ * This means that if they are removed from the List/Set/Map they will be + * deleted when their parent object is saved. + *
+ *+ * This could also be described as deleting orphans - in that beans removed from + * the List/Set/Map will be deleted automatically when the parent bean is saved. + * They are considered 'orphans' when they have been removed from the collection + * in that they are no longer associated/linked to their parent bean. + *
+ */ +@Target({ ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface PrivateOwned { + + /** + * Set this to false if you don't want cascade REMOVE on this relationship. + *+ * That is, by default PrivateOwned implicitly adds a cascade REMOVE to the + * relationship and if you don't want that you need to set this to false. + *
+ */ + boolean cascadeRemove() default true; + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/Sql.java b/src/main/java/com/avaje/ebean/annotation/Sql.java index eecbc2eb4..71f776350 100644 --- a/src/main/java/com/avaje/ebean/annotation/Sql.java +++ b/src/main/java/com/avaje/ebean/annotation/Sql.java @@ -1,24 +1,24 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specify explicit sql for multiple select statements. Need to use this if you - * have more than one SqlSelect for a given bean. - *- * FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete. - *
- */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Sql { - - /** - * The sql select statements. - */ - SqlSelect[] select() default { @SqlSelect }; - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specify explicit sql for multiple select statements. Need to use this if you + * have more than one SqlSelect for a given bean. + *+ * FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete. + *
+ */ +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Sql { + + /** + * The sql select statements. + */ + SqlSelect[] select() default { @SqlSelect }; + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/SqlSelect.java b/src/main/java/com/avaje/ebean/annotation/SqlSelect.java index 04acb88a9..218b35cb5 100644 --- a/src/main/java/com/avaje/ebean/annotation/SqlSelect.java +++ b/src/main/java/com/avaje/ebean/annotation/SqlSelect.java @@ -1,298 +1,298 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.avaje.ebean.Query; - -/** - * Specify an explicit sql select statement to use for querying an entity bean. - *- * The reason for using explicit sql is that you want better control over the - * exact sql or sql that Ebean does not generate for you (such as group by, - * union, intersection, window functions, recursive queries). - *
- *- * An example of two sql select queries deployed on the ReportTopic entity bean. - * The first one has no name specified so it becomes the default query. The - * second query extends the first adding a where clause with a named parameter. - *
- * - *
- * ...
- * @Entity
- * @Sql(select = {
- * @SqlSelect(query =
- * "select t.id, t.title, count(p.id) as score "+
- * "from f_topic t "+
- * "join f_topic_post p on p.topic_id = t.id "+
- * "group by t.id, t.title"),
- * @SqlSelect(
- * name = "with.title",
- * extend = "default",
- * debug = true,
- * where = "title like :likeTitle")
- * })
- * public class ReportTopic
- * @Id Integer id;
- * String title;
- * Double score;
- * ...
- *
- *
- * - * An example using the first "default" query. - *
- * - *
- *
- * List<ReportTopic> list =
- * Ebean.find(ReportTopic.class)
- * .having().gt("score", 0)
- * .findList();
- *
- *
- *
- * - * The resulting sql, note the having clause has been added. - *
- * - *- * select t.id, t.title, count(p.id) as score - * from f_topic t join f_topic_post p on p.topic_id = t.id - * group by t.id, t.title - * having count(p.id) > ? - *- * - *
- * An example using the second query. Note the named parameter "likeTitle" must - * be set. - *
- * - *
- * List<ReportTopic> list =
- * Ebean.find(ReportTopic.class, "with.title")
- * .set("likeTitle", "a%")
- * .findList();
- *
- *
- * - * Ebean tries to parse the sql in the query to determine 4 things - *
- * If Ebean is unable to parse out this information (perhaps because the sql - * contains multiple select from keywords etc) then you need to manually specify - * it. - *
- *- * Insert ${where} or ${andWhere} into the location where Ebean can insert any - * expressions added to the where clause. Use ${andWhere} if the sql already has - * the WHERE keyword and Ebean will instead start with a AND keyword. - *
- *- * Insert ${having} or ${andHaving} into the location where Ebean can insert any - * expressions added to the having clause. Use ${andHaving} if the sql already - * has a HAVING keyword and Ebean will instead start with a AND keyword. - *
- *- * Use the columnMapping property if Ebean is unable to determine the columns - * and map them to bean properties. - *
- *- * Example with ${andWhere} & ${having}. - *
- * - *
- * @SqlSelect(
- * name = "explicit.where",
- * query =
- * "select t.id, t.title, count(p.id) as score "+
- * "from f_topic t, f_topic_post p "+
- * "where p.topic_id = t.id ${andWhere} "+
- * "group by t.id, t.title ${having}"),
- *
- */
-@Target({ ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-@Deprecated
-public @interface SqlSelect {
-
- /**
- * The name of the query. If left blank this is assumed to be the default
- * query for this bean type.
- * - * This will default to "default" and in that case becomes the default query - * used for the bean. - *
- */ - String name() default "default"; - - /** - * The tableAlias used when adding where expressions to the query. - */ - String tableAlias() default ""; - - /** - * The sql select statement. - *- * If this query extends another then this string is appended to the - * parent query string. Often when using extend you will leave the - * query part blank and just specify a where and/or having clauses. - *
- *- * This sql CAN NOT contain named parameters. You have to put these - * in the separate where and/or having sections. - *
- *- * Ebean automatically tries to determine the location in the sql string for - * putting in additional where or having clauses. If Ebean is unable to - * successfully determine this then you have to explicitly specify these - * locations by including - * ${where} or ${andWhere} and ${having} or ${andHaving} in the sql. - *
- *
- * ${where} location of where clause (and will add WHERE ... )
- * Use this when there is no where clause in the sql. If expressions are added
- * to the where clause Ebean will put them in at this location starting with
- * the WHERE keyword.
- *
- *
- * ${andWhere}
- * Use this instead of ${where} if there IS an existing where clause in the
- * sql. Ebean will add the expressions starting with the AND keyword.
- *
- * ${having} location of having clause (and will add HAVING... )
- *
- * ${andHaving}
- * Use this instead of ${having} when there IS an existing HAVING clause.
- * Ebean will add the expressions starting with the AND keyword.
- *
- * You can include one of ${where} OR ${andWhere} but not both. - *
- *- * You can include one of ${having} OR ${andHaving} but not both. - *
- */ - String query() default ""; - - /** - * Specify the name of a sql-select query that this one 'extends'. - *- * When a query is extended the sql query contents are appended together. The - * where and having clauses are NOT appended but overridden. - *
- */ - String extend() default ""; - - /** - * Specify a where clause typically containing named parameters. - *- * If a where clause is specified with named parameters then they will need to - * be set on the query via {@link Query#setParameter(String, Object)}. - *
- *- * In the example below the query specifies a where clause that includes a - * named parameter "likeTitle". - *
- * - *
- * ...
- * @Entity
- * @Sql(select = {
- * ...
- * @SqlSelect(
- * name = "with.title",
- * extend = "default",
- * debug = true,
- * where = "title like :likeTitle")
- * })
- * public class ReportTopic
- * ...
- *
- *
- * - * Example use of the above named query. - *
- * - *
- *
- * Query<ReportTopic> query0 = Ebean.createQuery(ReportTopic.class, "with.title");
- *
- * query0.set("likeTitle", "Bana%");
- *
- * List<ReportTopic> list0 = query0.findList();
- *
- *
- */
- String where() default "";
-
- /**
- * Specify a having clause typically containing named parameters.
- * - * If a having clause is specified with named parameters then they will need - * to be set on the query via {@link Query#setParameter(String, Object)}. - *
- */ - String having() default ""; - - /** - * (Optional) Explicitly specify column to property mapping. - *- * This is required when Ebean is unable to parse the sql. This could occur if - * the sql contains multiple select keywords etc. - *
- *- * Specify the columns and property names they map to in the format. - *
- * - *- * column1 propertyName1, column2 propertyName2, ... - *- * - *
- * Optionally put a AS keyword between the column and property. - *
- * - *- * // the AS keyword is optional - * column1 AS propertyName1, column2 propertyName2, ... - *- * - *
- * column should contain the table alias if there is one - *
- *- * propertyName should match the property name. - *
- * - *- * Example mapping 5 columns to properties. - *
- * - *- * columnMapping="t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue", - *- * - *
- * Without this set Ebean will parse the sql looking for the select clause and - * try to map the columns to property names. It is expected that Ebean will - * not be able to successfully parse some sql and for those cases you should - * specify the column to property mapping explicitly. - *
- * - */ - String columnMapping() default ""; - - /** - * Set this to true to have debug output when Ebean parses the sql-select. - */ - boolean debug() default false; -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.avaje.ebean.Query; + +/** + * Specify an explicit sql select statement to use for querying an entity bean. + *+ * The reason for using explicit sql is that you want better control over the + * exact sql or sql that Ebean does not generate for you (such as group by, + * union, intersection, window functions, recursive queries). + *
+ *+ * An example of two sql select queries deployed on the ReportTopic entity bean. + * The first one has no name specified so it becomes the default query. The + * second query extends the first adding a where clause with a named parameter. + *
+ * + *
+ * ...
+ * @Entity
+ * @Sql(select = {
+ * @SqlSelect(query =
+ * "select t.id, t.title, count(p.id) as score "+
+ * "from f_topic t "+
+ * "join f_topic_post p on p.topic_id = t.id "+
+ * "group by t.id, t.title"),
+ * @SqlSelect(
+ * name = "with.title",
+ * extend = "default",
+ * debug = true,
+ * where = "title like :likeTitle")
+ * })
+ * public class ReportTopic
+ * @Id Integer id;
+ * String title;
+ * Double score;
+ * ...
+ *
+ *
+ * + * An example using the first "default" query. + *
+ * + *
+ *
+ * List<ReportTopic> list =
+ * Ebean.find(ReportTopic.class)
+ * .having().gt("score", 0)
+ * .findList();
+ *
+ *
+ *
+ * + * The resulting sql, note the having clause has been added. + *
+ * + *+ * select t.id, t.title, count(p.id) as score + * from f_topic t join f_topic_post p on p.topic_id = t.id + * group by t.id, t.title + * having count(p.id) > ? + *+ * + *
+ * An example using the second query. Note the named parameter "likeTitle" must + * be set. + *
+ * + *
+ * List<ReportTopic> list =
+ * Ebean.find(ReportTopic.class, "with.title")
+ * .set("likeTitle", "a%")
+ * .findList();
+ *
+ *
+ * + * Ebean tries to parse the sql in the query to determine 4 things + *
+ * If Ebean is unable to parse out this information (perhaps because the sql + * contains multiple select from keywords etc) then you need to manually specify + * it. + *
+ *+ * Insert ${where} or ${andWhere} into the location where Ebean can insert any + * expressions added to the where clause. Use ${andWhere} if the sql already has + * the WHERE keyword and Ebean will instead start with a AND keyword. + *
+ *+ * Insert ${having} or ${andHaving} into the location where Ebean can insert any + * expressions added to the having clause. Use ${andHaving} if the sql already + * has a HAVING keyword and Ebean will instead start with a AND keyword. + *
+ *+ * Use the columnMapping property if Ebean is unable to determine the columns + * and map them to bean properties. + *
+ *+ * Example with ${andWhere} & ${having}. + *
+ * + *
+ * @SqlSelect(
+ * name = "explicit.where",
+ * query =
+ * "select t.id, t.title, count(p.id) as score "+
+ * "from f_topic t, f_topic_post p "+
+ * "where p.topic_id = t.id ${andWhere} "+
+ * "group by t.id, t.title ${having}"),
+ *
+ */
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Deprecated
+public @interface SqlSelect {
+
+ /**
+ * The name of the query. If left blank this is assumed to be the default
+ * query for this bean type.
+ * + * This will default to "default" and in that case becomes the default query + * used for the bean. + *
+ */ + String name() default "default"; + + /** + * The tableAlias used when adding where expressions to the query. + */ + String tableAlias() default ""; + + /** + * The sql select statement. + *+ * If this query extends another then this string is appended to the + * parent query string. Often when using extend you will leave the + * query part blank and just specify a where and/or having clauses. + *
+ *+ * This sql CAN NOT contain named parameters. You have to put these + * in the separate where and/or having sections. + *
+ *+ * Ebean automatically tries to determine the location in the sql string for + * putting in additional where or having clauses. If Ebean is unable to + * successfully determine this then you have to explicitly specify these + * locations by including + * ${where} or ${andWhere} and ${having} or ${andHaving} in the sql. + *
+ *
+ * ${where} location of where clause (and will add WHERE ... )
+ * Use this when there is no where clause in the sql. If expressions are added
+ * to the where clause Ebean will put them in at this location starting with
+ * the WHERE keyword.
+ *
+ *
+ * ${andWhere}
+ * Use this instead of ${where} if there IS an existing where clause in the
+ * sql. Ebean will add the expressions starting with the AND keyword.
+ *
+ * ${having} location of having clause (and will add HAVING... )
+ *
+ * ${andHaving}
+ * Use this instead of ${having} when there IS an existing HAVING clause.
+ * Ebean will add the expressions starting with the AND keyword.
+ *
+ * You can include one of ${where} OR ${andWhere} but not both. + *
+ *+ * You can include one of ${having} OR ${andHaving} but not both. + *
+ */ + String query() default ""; + + /** + * Specify the name of a sql-select query that this one 'extends'. + *+ * When a query is extended the sql query contents are appended together. The + * where and having clauses are NOT appended but overridden. + *
+ */ + String extend() default ""; + + /** + * Specify a where clause typically containing named parameters. + *+ * If a where clause is specified with named parameters then they will need to + * be set on the query via {@link Query#setParameter(String, Object)}. + *
+ *+ * In the example below the query specifies a where clause that includes a + * named parameter "likeTitle". + *
+ * + *
+ * ...
+ * @Entity
+ * @Sql(select = {
+ * ...
+ * @SqlSelect(
+ * name = "with.title",
+ * extend = "default",
+ * debug = true,
+ * where = "title like :likeTitle")
+ * })
+ * public class ReportTopic
+ * ...
+ *
+ *
+ * + * Example use of the above named query. + *
+ * + *
+ *
+ * Query<ReportTopic> query0 = Ebean.createQuery(ReportTopic.class, "with.title");
+ *
+ * query0.set("likeTitle", "Bana%");
+ *
+ * List<ReportTopic> list0 = query0.findList();
+ *
+ *
+ */
+ String where() default "";
+
+ /**
+ * Specify a having clause typically containing named parameters.
+ * + * If a having clause is specified with named parameters then they will need + * to be set on the query via {@link Query#setParameter(String, Object)}. + *
+ */ + String having() default ""; + + /** + * (Optional) Explicitly specify column to property mapping. + *+ * This is required when Ebean is unable to parse the sql. This could occur if + * the sql contains multiple select keywords etc. + *
+ *+ * Specify the columns and property names they map to in the format. + *
+ * + *+ * column1 propertyName1, column2 propertyName2, ... + *+ * + *
+ * Optionally put a AS keyword between the column and property. + *
+ * + *+ * // the AS keyword is optional + * column1 AS propertyName1, column2 propertyName2, ... + *+ * + *
+ * column should contain the table alias if there is one + *
+ *+ * propertyName should match the property name. + *
+ * + *+ * Example mapping 5 columns to properties. + *
+ * + *+ * columnMapping="t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue", + *+ * + *
+ * Without this set Ebean will parse the sql looking for the select clause and + * try to map the columns to property names. It is expected that Ebean will + * not be able to successfully parse some sql and for those cases you should + * specify the column to property mapping explicitly. + *
+ * + */ + String columnMapping() default ""; + + /** + * Set this to true to have debug output when Ebean parses the sql-select. + */ + boolean debug() default false; +}; diff --git a/src/main/java/com/avaje/ebean/annotation/UpdateMode.java b/src/main/java/com/avaje/ebean/annotation/UpdateMode.java index 847fff403..ddb4d8ef0 100644 --- a/src/main/java/com/avaje/ebean/annotation/UpdateMode.java +++ b/src/main/java/com/avaje/ebean/annotation/UpdateMode.java @@ -1,34 +1,34 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specify the update mode for the specific entity type. - *- * Control whether all 'loaded' properties are included in an Update or whether - * just properties that have changed will be included in the update. - *
- *- * Note that the default can be set via ebean.properties. - *
- * - *- * ## Set to update all loaded properties - * ebean.updateChangesOnly=false - *- */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface UpdateMode { - - /** - * Set to false if you want to include all the 'loaded' properties in the - * update. Otherwise, just the properties that have changed will be included - * in the update. - */ - boolean updateChangesOnly() default true; - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specify the update mode for the specific entity type. + *
+ * Control whether all 'loaded' properties are included in an Update or whether + * just properties that have changed will be included in the update. + *
+ *+ * Note that the default can be set via ebean.properties. + *
+ * + *+ * ## Set to update all loaded properties + * ebean.updateChangesOnly=false + *+ */ +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface UpdateMode { + + /** + * Set to false if you want to include all the 'loaded' properties in the + * update. Otherwise, just the properties that have changed will be included + * in the update. + */ + boolean updateChangesOnly() default true; + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/UpdatedTimestamp.java b/src/main/java/com/avaje/ebean/annotation/UpdatedTimestamp.java index f5c8d89a7..3082faa10 100644 --- a/src/main/java/com/avaje/ebean/annotation/UpdatedTimestamp.java +++ b/src/main/java/com/avaje/ebean/annotation/UpdatedTimestamp.java @@ -1,16 +1,16 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * For a timestamp property that is set to the datetime when the entity was last - * updated. - */ -@Target({ ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface UpdatedTimestamp { - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * For a timestamp property that is set to the datetime when the entity was last + * updated. + */ +@Target({ ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface UpdatedTimestamp { + +}; diff --git a/src/main/java/com/avaje/ebean/annotation/Where.java b/src/main/java/com/avaje/ebean/annotation/Where.java index 138ef33c2..77b3c330a 100644 --- a/src/main/java/com/avaje/ebean/annotation/Where.java +++ b/src/main/java/com/avaje/ebean/annotation/Where.java @@ -1,51 +1,51 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Add an Literal to add to the where clause when a many property (List, Set or - * Map) is loaded or refreshed. - * - *
- * // on a OneToMany property... - * - * @OneToMany - * @Where(clause = "deleted='y'") - * List<Topic> topics; - *- * - *
- * Note that you can include "${ta}" as a place holder for the table alias if - * you need to include the table alias in the clause. - *
- * - *
- * // ... including the ${ta} table alias placeholder...
- *
- * @OneToMany
- * @Where(clause = "${ta}.deleted='y'")
- * List<Topic> topics;
- *
- *
- * - * This will be added to the where clause when lazy loading the OneToMany - * property or when there is a join to that OneToMany property. - *
- */ -@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Where { - - /** - * The clause added to the lazy load query. - *- * Note that you can include "${ta}" as a place holder for the table alias if - * you need to include the table alias in the clause. - *
- */ - String clause(); - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Add an Literal to add to the where clause when a many property (List, Set or + * Map) is loaded or refreshed. + * + *+ * // on a OneToMany property... + * + * @OneToMany + * @Where(clause = "deleted='y'") + * List<Topic> topics; + *+ * + *
+ * Note that you can include "${ta}" as a place holder for the table alias if + * you need to include the table alias in the clause. + *
+ * + *
+ * // ... including the ${ta} table alias placeholder...
+ *
+ * @OneToMany
+ * @Where(clause = "${ta}.deleted='y'")
+ * List<Topic> topics;
+ *
+ *
+ * + * This will be added to the where clause when lazy loading the OneToMany + * property or when there is a join to that OneToMany property. + *
+ */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Where { + + /** + * The clause added to the lazy load query. + *+ * Note that you can include "${ta}" as a place holder for the table alias if + * you need to include the table alias in the clause. + *
+ */ + String clause(); + +}; diff --git a/src/main/java/com/avaje/ebean/bean/BeanCollection.java b/src/main/java/com/avaje/ebean/bean/BeanCollection.java index a421dc5f5..b915f1862 100644 --- a/src/main/java/com/avaje/ebean/bean/BeanCollection.java +++ b/src/main/java/com/avaje/ebean/bean/BeanCollection.java @@ -1,201 +1,201 @@ -package com.avaje.ebean.bean; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Set; - -import com.avaje.ebean.ExpressionList; - -/** - * Lazy loading capable Maps, Lists and Sets. - *- * This also includes the ability to listen for additions and removals to or - * from the Map Set or List. The purpose of gathering the additions and removals - * is to support persisting ManyToMany objects. The additions and removals - * become inserts and deletes from the intersection table. - *
- *- * Technically this is NOT an extension of - * java.util.Collection. The reason being that java.util.Map is not a - * Collection. I realise this makes this name confusing so I apologise for that. - *
- */ -public interface BeanCollection- * This is done as part of bean refresh. - */ - void reset(EntityBean ownerBean, String propertyName); - - /** - * Return true if the collection is empty and untouched. Used to detect if a - * collection was 'cleared' deliberately or just un-initialised. - */ - boolean isEmptyAndUntouched(); - - /** - * Return the bean that owns this collection. - */ - EntityBean getOwnerBean(); - - /** - * Return the bean property name this collection represents. - */ - String getPropertyName(); - - /** - * Check after the lazy load that the underlying collection is not null - * (handle case where join to many not outer). - *
- * That is, if the collection was not loaded due to filterMany predicates etc - * then make sure the collection is set to empty. - *
- */ - boolean checkEmptyLazyLoad(); - - /** - * Return the filter (if any) that was used in building this collection. - *- * This is so that the filter can be applied on refresh. - *
- */ - ExpressionList> getFilterMany(); - - /** - * Set the filter that was used in building this collection. - */ - void setFilterMany(ExpressionList> filterMany); - - /** - * Set a listener to be notified when the BeanCollection is first touched. - */ - void setBeanCollectionTouched(BeanCollectionTouched notify); - - /** - * Return true if the collection has been registered with the batch loading context. - */ - boolean isRegisteredWithLoadContext(); - - /** - * Set the loader that will be used to lazy/query load this collection. - *- * This is effectively the batch loading context this collection is registered with. - *
- */ - void setLoader(BeanCollectionLoader beanLoader); - - /** - * Set to true if you want the BeanCollection to be treated as read only. This - * means no elements can be added or removed etc. - */ - void setReadOnly(boolean readOnly); - - /** - * Return true if the collection should be treated as readOnly and no elements - * can be added or removed etc. - */ - boolean isReadOnly(); - - /** - * Add the bean to the collection. - *- * This is disallowed for BeanMap. - *
- */ - void internalAdd(Object bean); - - /** - * Return the number of elements in the List Set or Map. - */ - int size(); - - /** - * Return true if the List Set or Map is empty. - */ - boolean isEmpty(); - - /** - * Returns the underlying collection of beans from the Set, Map or List. - */ - Collection- * For maps this returns the entrySet as we need the keys of the map. - *
- */ - Collection> getActualEntries(); - - /** - * return true if there are real rows held. Return false is this is using - * Deferred fetch to lazy load the rows and the rows have not yet been - * fetched. - */ - boolean isPopulated(); - - /** - * Return true if this is a reference (lazy loading) bean collection. This is - * the same as !isPopulated(); - */ - boolean isReference(); - - /** - * Set modify listening on or off. This is used to keep track of objects that - * have been added to or removed from the list set or map. - *- * This is required only for ManyToMany collections. The additions and - * deletions are used to insert or delete entries from the intersection table. - * Otherwise modifyListening is false. - *
- */ - void setModifyListening(ModifyListenMode modifyListenMode); - - /** - * Add an object to the additions list. - *- * This will potentially end up as an insert into a intersection table for a - * ManyToMany. - *
- */ - void modifyAddition(E bean); - - /** - * Add an object to the deletions list. - *- * This will potentially end up as an delete from an intersection table for a - * ManyToMany. - *
- */ - void modifyRemoval(Object bean); - - /** - * Return the list of objects added to the list set or map. These will used to - * insert rows into the intersection table of a ManyToMany. - */ - Set+ * This also includes the ability to listen for additions and removals to or + * from the Map Set or List. The purpose of gathering the additions and removals + * is to support persisting ManyToMany objects. The additions and removals + * become inserts and deletes from the intersection table. + *
+ *+ * Technically this is NOT an extension of + * java.util.Collection. The reason being that java.util.Map is not a + * Collection. I realise this makes this name confusing so I apologise for that. + *
+ */ +public interface BeanCollection+ * This is done as part of bean refresh. + */ + void reset(EntityBean ownerBean, String propertyName); + + /** + * Return true if the collection is empty and untouched. Used to detect if a + * collection was 'cleared' deliberately or just un-initialised. + */ + boolean isEmptyAndUntouched(); + + /** + * Return the bean that owns this collection. + */ + EntityBean getOwnerBean(); + + /** + * Return the bean property name this collection represents. + */ + String getPropertyName(); + + /** + * Check after the lazy load that the underlying collection is not null + * (handle case where join to many not outer). + *
+ * That is, if the collection was not loaded due to filterMany predicates etc + * then make sure the collection is set to empty. + *
+ */ + boolean checkEmptyLazyLoad(); + + /** + * Return the filter (if any) that was used in building this collection. + *+ * This is so that the filter can be applied on refresh. + *
+ */ + ExpressionList> getFilterMany(); + + /** + * Set the filter that was used in building this collection. + */ + void setFilterMany(ExpressionList> filterMany); + + /** + * Set a listener to be notified when the BeanCollection is first touched. + */ + void setBeanCollectionTouched(BeanCollectionTouched notify); + + /** + * Return true if the collection has been registered with the batch loading context. + */ + boolean isRegisteredWithLoadContext(); + + /** + * Set the loader that will be used to lazy/query load this collection. + *+ * This is effectively the batch loading context this collection is registered with. + *
+ */ + void setLoader(BeanCollectionLoader beanLoader); + + /** + * Set to true if you want the BeanCollection to be treated as read only. This + * means no elements can be added or removed etc. + */ + void setReadOnly(boolean readOnly); + + /** + * Return true if the collection should be treated as readOnly and no elements + * can be added or removed etc. + */ + boolean isReadOnly(); + + /** + * Add the bean to the collection. + *+ * This is disallowed for BeanMap. + *
+ */ + void internalAdd(Object bean); + + /** + * Return the number of elements in the List Set or Map. + */ + int size(); + + /** + * Return true if the List Set or Map is empty. + */ + boolean isEmpty(); + + /** + * Returns the underlying collection of beans from the Set, Map or List. + */ + Collection+ * For maps this returns the entrySet as we need the keys of the map. + *
+ */ + Collection> getActualEntries(); + + /** + * return true if there are real rows held. Return false is this is using + * Deferred fetch to lazy load the rows and the rows have not yet been + * fetched. + */ + boolean isPopulated(); + + /** + * Return true if this is a reference (lazy loading) bean collection. This is + * the same as !isPopulated(); + */ + boolean isReference(); + + /** + * Set modify listening on or off. This is used to keep track of objects that + * have been added to or removed from the list set or map. + *+ * This is required only for ManyToMany collections. The additions and + * deletions are used to insert or delete entries from the intersection table. + * Otherwise modifyListening is false. + *
+ */ + void setModifyListening(ModifyListenMode modifyListenMode); + + /** + * Add an object to the additions list. + *+ * This will potentially end up as an insert into a intersection table for a + * ManyToMany. + *
+ */ + void modifyAddition(E bean); + + /** + * Add an object to the deletions list. + *+ * This will potentially end up as an delete from an intersection table for a + * ManyToMany. + *
+ */ + void modifyRemoval(Object bean); + + /** + * Return the list of objects added to the list set or map. These will used to + * insert rows into the intersection table of a ManyToMany. + */ + Set- * For maps this takes into account the map key. For List and Set this simply - * adds the bean to the underlying list or set. - *
- */ -public interface BeanCollectionAdd { - - /** - * Add a loaded bean to the collection. - */ - void addBean(EntityBean bean); -} +package com.avaje.ebean.bean; + +/** + * Interface to define the addition of a bean to the underlying collection. + *+ * For maps this takes into account the map key. For List and Set this simply + * adds the bean to the underlying list or set. + *
+ */ +public interface BeanCollectionAdd { + + /** + * Add a loaded bean to the collection. + */ + void addBean(EntityBean bean); +} diff --git a/src/main/java/com/avaje/ebean/bean/BeanCollectionLoader.java b/src/main/java/com/avaje/ebean/bean/BeanCollectionLoader.java index 25ee13860..1c80a0437 100644 --- a/src/main/java/com/avaje/ebean/bean/BeanCollectionLoader.java +++ b/src/main/java/com/avaje/ebean/bean/BeanCollectionLoader.java @@ -1,21 +1,21 @@ -package com.avaje.ebean.bean; - -/** - * Loads a entity bean collection. - *- * Typically invokes lazy loading for a single or batch of collections. - *
- */ -public interface BeanCollectionLoader { - - /** - * Return the name of the associated EbeanServer. - */ - String getName(); - - /** - * Invoke the lazy loading for this bean collection. - */ - void loadMany(BeanCollection> collection, boolean onlyIds); - -} +package com.avaje.ebean.bean; + +/** + * Loads a entity bean collection. + *+ * Typically invokes lazy loading for a single or batch of collections. + *
+ */ +public interface BeanCollectionLoader { + + /** + * Return the name of the associated EbeanServer. + */ + String getName(); + + /** + * Invoke the lazy loading for this bean collection. + */ + void loadMany(BeanCollection> collection, boolean onlyIds); + +} diff --git a/src/main/java/com/avaje/ebean/bean/BeanCollectionTouched.java b/src/main/java/com/avaje/ebean/bean/BeanCollectionTouched.java index 694c5d574..1451d9783 100644 --- a/src/main/java/com/avaje/ebean/bean/BeanCollectionTouched.java +++ b/src/main/java/com/avaje/ebean/bean/BeanCollectionTouched.java @@ -1,20 +1,20 @@ -package com.avaje.ebean.bean; - -/** - * Used to specify a listener to be notified when a BeanCollection is first - * used. - *- * To use this you can set a BeanCollectionTouched onto a BeanCollection before - * it has been used. When the BeanCollection is first used by the client code - * then the BeanCollectionTouched is notified. It can only be notified once. - *
- * - * @author rbygrave - */ -public interface BeanCollectionTouched { - - /** - * Notify the listener that the bean collection has been used. - */ - void notifyTouched(BeanCollection> c); -} +package com.avaje.ebean.bean; + +/** + * Used to specify a listener to be notified when a BeanCollection is first + * used. + *+ * To use this you can set a BeanCollectionTouched onto a BeanCollection before + * it has been used. When the BeanCollection is first used by the client code + * then the BeanCollectionTouched is notified. It can only be notified once. + *
+ * + * @author rbygrave + */ +public interface BeanCollectionTouched { + + /** + * Notify the listener that the bean collection has been used. + */ + void notifyTouched(BeanCollection> c); +} diff --git a/src/main/java/com/avaje/ebean/bean/BeanLoader.java b/src/main/java/com/avaje/ebean/bean/BeanLoader.java index d74a7b681..9f6605064 100644 --- a/src/main/java/com/avaje/ebean/bean/BeanLoader.java +++ b/src/main/java/com/avaje/ebean/bean/BeanLoader.java @@ -1,21 +1,21 @@ -package com.avaje.ebean.bean; - -/** - * Loads a entity bean. - *- * Typically invokes lazy loading for a single or batch of entity beans. - *
- */ -public interface BeanLoader { - - /** - * Return the name of the associated EbeanServer. - */ - String getName(); - - /** - * Invoke the lazy loading for this bean. - */ - void loadBean(EntityBeanIntercept ebi); - -} +package com.avaje.ebean.bean; + +/** + * Loads a entity bean. + *+ * Typically invokes lazy loading for a single or batch of entity beans. + *
+ */ +public interface BeanLoader { + + /** + * Return the name of the associated EbeanServer. + */ + String getName(); + + /** + * Invoke the lazy loading for this bean. + */ + void loadBean(EntityBeanIntercept ebi); + +} diff --git a/src/main/java/com/avaje/ebean/bean/CallStack.java b/src/main/java/com/avaje/ebean/bean/CallStack.java index 43d17ce0e..0f4b78f0c 100644 --- a/src/main/java/com/avaje/ebean/bean/CallStack.java +++ b/src/main/java/com/avaje/ebean/bean/CallStack.java @@ -1,118 +1,118 @@ -package com.avaje.ebean.bean; - -import java.io.Serializable; -import java.util.Arrays; - -/** - * Represent the call stack (stack trace elements). - *- * Used with a query to identify a CallStackQuery for AutoFetch automatic query - * tuning. - *
- *- * This is used so that a single query called from different methods can be - * tuned for each different call stack. - *
- *- * Note the call stack is trimmed to remove the common ebean internal elements. - *
- */ -public final class CallStack implements Serializable { - - private static final long serialVersionUID = -8590644046907438579L; - - private final String zeroHash; - private final String pathHash; - - private final StackTraceElement[] callStack; - - public CallStack(StackTraceElement[] callStack) { - this.callStack = callStack; - this.zeroHash = enc(callStack[0].hashCode()); - int hc = 0; - for (int i = 1; i < callStack.length; i++) { - hc = 31 * hc + callStack[i].hashCode(); - } - this.pathHash = enc(hc); - } - - public int hashCode() { - int hc = 0; - for (int i = 0; i < callStack.length; i++) { - hc = 31 * hc + callStack[i].hashCode(); - } - return hc; - } - - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof CallStack)) { - return false; - } - CallStack e = (CallStack) obj; - return Arrays.equals(callStack, e.callStack); - } - - /** - * Return the first element of the call stack. - */ - public StackTraceElement getFirstStackTraceElement() { - return callStack[0]; - } - - /** - * Return the call stack. - */ - public StackTraceElement[] getCallStack() { - return callStack; - } - - /** - * Return the hash for the first stack element. - */ - public String getZeroHash() { - return zeroHash; - } - - /** - * Return the hash for the stack elements (excluding first stack element). - */ - public String getPathHash() { - return pathHash; - } - - public String toString() { - return zeroHash + ":" + pathHash + ":" + callStack[0]; - } - - public String getOriginKey(int queryHash) { - return zeroHash + "." + enc(queryHash) + "." + pathHash; - } - - private static final int radix = 1 << 6; - private static final int mask = radix - 1; - - /** - * Convert the integer to unsigned base 64. - */ - public static String enc(int i) { - char[] buf = new char[32]; - int charPos = 32; - do { - buf[--charPos] = intToBase64[i & mask]; - i >>>= 6; - } while (i != 0); - - return new String(buf, charPos, (32 - charPos)); - } - - private static final char intToBase64[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' - }; -} +package com.avaje.ebean.bean; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * Represent the call stack (stack trace elements). + *+ * Used with a query to identify a CallStackQuery for AutoFetch automatic query + * tuning. + *
+ *+ * This is used so that a single query called from different methods can be + * tuned for each different call stack. + *
+ *+ * Note the call stack is trimmed to remove the common ebean internal elements. + *
+ */ +public final class CallStack implements Serializable { + + private static final long serialVersionUID = -8590644046907438579L; + + private final String zeroHash; + private final String pathHash; + + private final StackTraceElement[] callStack; + + public CallStack(StackTraceElement[] callStack) { + this.callStack = callStack; + this.zeroHash = enc(callStack[0].hashCode()); + int hc = 0; + for (int i = 1; i < callStack.length; i++) { + hc = 31 * hc + callStack[i].hashCode(); + } + this.pathHash = enc(hc); + } + + public int hashCode() { + int hc = 0; + for (int i = 0; i < callStack.length; i++) { + hc = 31 * hc + callStack[i].hashCode(); + } + return hc; + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof CallStack)) { + return false; + } + CallStack e = (CallStack) obj; + return Arrays.equals(callStack, e.callStack); + } + + /** + * Return the first element of the call stack. + */ + public StackTraceElement getFirstStackTraceElement() { + return callStack[0]; + } + + /** + * Return the call stack. + */ + public StackTraceElement[] getCallStack() { + return callStack; + } + + /** + * Return the hash for the first stack element. + */ + public String getZeroHash() { + return zeroHash; + } + + /** + * Return the hash for the stack elements (excluding first stack element). + */ + public String getPathHash() { + return pathHash; + } + + public String toString() { + return zeroHash + ":" + pathHash + ":" + callStack[0]; + } + + public String getOriginKey(int queryHash) { + return zeroHash + "." + enc(queryHash) + "." + pathHash; + } + + private static final int radix = 1 << 6; + private static final int mask = radix - 1; + + /** + * Convert the integer to unsigned base 64. + */ + public static String enc(int i) { + char[] buf = new char[32]; + int charPos = 32; + do { + buf[--charPos] = intToBase64[i & mask]; + i >>>= 6; + } while (i != 0); + + return new String(buf, charPos, (32 - charPos)); + } + + private static final char intToBase64[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' + }; +} diff --git a/src/main/java/com/avaje/ebean/bean/EntityBean.java b/src/main/java/com/avaje/ebean/bean/EntityBean.java index 4a077a038..81224166f 100644 --- a/src/main/java/com/avaje/ebean/bean/EntityBean.java +++ b/src/main/java/com/avaje/ebean/bean/EntityBean.java @@ -1,114 +1,114 @@ -package com.avaje.ebean.bean; - -import java.beans.PropertyChangeListener; -import java.io.Serializable; - -/** - * Bean that is aware of EntityBeanIntercept. - *- * This interface and implementation of these methods is added to Entity Beans - * via instrumentation. These methods have a funny _ebean_ prefix to avoid any - * clash with normal methods these beans would have. These methods are not for - * general application consumption. - *
- */ -public interface EntityBean extends Serializable { - - String[] _ebean_getPropertyNames(); - - String _ebean_getPropertyName(int pos); - - /** - * Return the enhancement marker value. - *- * This is the class name of the enhanced class and used to check that all - * entity classes are enhanced (specifically not just a super class). - *
- */ - String _ebean_getMarker(); - - /** - * Create and return a new entity bean instance. - */ - Object _ebean_newInstance(); - - /** - * Add a PropertyChangeListener to this bean. - */ - void addPropertyChangeListener(PropertyChangeListener listener); - - /** - * Remove a PropertyChangeListener from this bean. - */ - void removePropertyChangeListener(PropertyChangeListener listener); - - /** - * Generated method that sets the loaded state on all the embedded beans on - * this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o); - */ - void _ebean_setEmbeddedLoaded(); - - /** - * Return true if any embedded beans are new or dirty. - */ - boolean _ebean_isEmbeddedNewOrDirty(); - - /** - * Return the intercept for this object. - */ - EntityBeanIntercept _ebean_getIntercept(); - - /** - * Similar to _ebean_getIntercept() except it checks to see if the intercept - * field is null and will create it if required. - *- * This is really only required when transientInternalFields=true as an - * enhancement option. In this case the intercept field is transient and will - * be null after a bean has been deserialised. - *
- *- * This transientInternalFields=true option was to support some serialization - * frameworks that can't take into account our ebean fields. - *
- */ - EntityBeanIntercept _ebean_intercept(); - - /** - * Create a copy of this entity bean. - *- * This occurs when a bean is changed. The copy represents the bean as it was - * initially (oldValues) before any changes where made. This is used for - * optimistic concurrency control. - *
- */ - Object _ebean_createCopy(); - - /** - * Set the value of a field of an entity bean of this type. - *- * Note that using this method bypasses any interception that otherwise occurs - * on entity beans. That means lazy loading and oldValues creation. - *
- */ - void _ebean_setField(int fieldIndex, Object value); - - /** - * Set the field value with interception. - */ - void _ebean_setFieldIntercept(int fieldIndex, Object value); - - /** - * Return the value of a field from an entity bean of this type. - *- * Note that using this method bypasses any interception that otherwise occurs - * on entity beans. That means lazy loading. - *
- */ - Object _ebean_getField(int fieldIndex); - - /** - * Return the field value with interception. - */ - Object _ebean_getFieldIntercept(int fieldIndex); - -} +package com.avaje.ebean.bean; + +import java.beans.PropertyChangeListener; +import java.io.Serializable; + +/** + * Bean that is aware of EntityBeanIntercept. + *+ * This interface and implementation of these methods is added to Entity Beans + * via instrumentation. These methods have a funny _ebean_ prefix to avoid any + * clash with normal methods these beans would have. These methods are not for + * general application consumption. + *
+ */ +public interface EntityBean extends Serializable { + + String[] _ebean_getPropertyNames(); + + String _ebean_getPropertyName(int pos); + + /** + * Return the enhancement marker value. + *+ * This is the class name of the enhanced class and used to check that all + * entity classes are enhanced (specifically not just a super class). + *
+ */ + String _ebean_getMarker(); + + /** + * Create and return a new entity bean instance. + */ + Object _ebean_newInstance(); + + /** + * Add a PropertyChangeListener to this bean. + */ + void addPropertyChangeListener(PropertyChangeListener listener); + + /** + * Remove a PropertyChangeListener from this bean. + */ + void removePropertyChangeListener(PropertyChangeListener listener); + + /** + * Generated method that sets the loaded state on all the embedded beans on + * this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o); + */ + void _ebean_setEmbeddedLoaded(); + + /** + * Return true if any embedded beans are new or dirty. + */ + boolean _ebean_isEmbeddedNewOrDirty(); + + /** + * Return the intercept for this object. + */ + EntityBeanIntercept _ebean_getIntercept(); + + /** + * Similar to _ebean_getIntercept() except it checks to see if the intercept + * field is null and will create it if required. + *+ * This is really only required when transientInternalFields=true as an + * enhancement option. In this case the intercept field is transient and will + * be null after a bean has been deserialised. + *
+ *+ * This transientInternalFields=true option was to support some serialization + * frameworks that can't take into account our ebean fields. + *
+ */ + EntityBeanIntercept _ebean_intercept(); + + /** + * Create a copy of this entity bean. + *+ * This occurs when a bean is changed. The copy represents the bean as it was + * initially (oldValues) before any changes where made. This is used for + * optimistic concurrency control. + *
+ */ + Object _ebean_createCopy(); + + /** + * Set the value of a field of an entity bean of this type. + *+ * Note that using this method bypasses any interception that otherwise occurs + * on entity beans. That means lazy loading and oldValues creation. + *
+ */ + void _ebean_setField(int fieldIndex, Object value); + + /** + * Set the field value with interception. + */ + void _ebean_setFieldIntercept(int fieldIndex, Object value); + + /** + * Return the value of a field from an entity bean of this type. + *+ * Note that using this method bypasses any interception that otherwise occurs + * on entity beans. That means lazy loading. + *
+ */ + Object _ebean_getField(int fieldIndex); + + /** + * Return the field value with interception. + */ + Object _ebean_getFieldIntercept(int fieldIndex); + +} diff --git a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java index c662552a3..bbed76666 100644 --- a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java @@ -1,1060 +1,1060 @@ -package com.avaje.ebean.bean; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.Serializable; -import java.math.BigDecimal; -import java.net.URL; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import javax.persistence.EntityNotFoundException; -import javax.persistence.PersistenceException; - -import com.avaje.ebean.Ebean; -import com.avaje.ebean.ValuePair; - -/** - * This is the object added to every entity bean using byte code enhancement. - *- * This provides the mechanisms to support deferred fetching of reference beans - * and oldValues generation for concurrency checking. - *
- */ -public final class EntityBeanIntercept implements Serializable { - - private static final long serialVersionUID = -3664031775464862649L; - - private static final int STATE_NEW = 0; - private static final int STATE_REFERENCE = 1; - private static final int STATE_LOADED = 2; - - private transient NodeUsageCollector nodeUsageCollector; - - private transient PropertyChangeSupport pcs; - - private transient PersistenceContext persistenceContext; - - private transient BeanLoader beanLoader; - - private String ebeanServerName; - - /** - * The actual entity bean that 'owns' this intercept. - */ - private EntityBean owner; - - private EntityBean embeddedOwner; - private int embeddedOwnerIndex; - - /** - * One of NEW, REF, UPD. - */ - private int state; - - private boolean readOnly; - - private boolean dirty; - - /** - * Flag set to disable lazy loading - typically for SQL "report" type entity beans. - */ - private boolean disableLazyLoad; - - /** - * Flag set when lazy loading failed due to the underlying bean being deleted in the DB. - */ - private boolean lazyLoadFailure; - - /** - * Used when a bean is partially filled. - */ - private boolean[] loadedProps; - - private boolean fullyLoadedBean; - - /** - * Set of changed properties. - */ - private boolean[] changedProps; - - /** - * Flags indicating if a property is a dirty embedded bean. Used to distingush - * between an embedded bean being completely overwritten and one of its - * embedded properties being made dirty. - */ - private boolean[] embeddedDirty; - - private Object[] origValues; - - private int lazyLoadProperty = -1; - - /** - * Create a intercept with a given entity. - *- * Refer to agent ProxyConstructor. - *
- */ - public EntityBeanIntercept(Object ownerBean) { - this.owner = (EntityBean) ownerBean; - this.loadedProps = new boolean[owner._ebean_getPropertyNames().length]; - } - - /** - * Return the 'owning' entity bean. - */ - public EntityBean getOwner() { - return owner; - } - - /** - * Return the persistenceContext. - */ - public PersistenceContext getPersistenceContext() { - return persistenceContext; - } - - /** - * Set the persistenceContext. - */ - public void setPersistenceContext(PersistenceContext persistenceContext) { - this.persistenceContext = persistenceContext; - } - - /** - * Add a property change listener for this entity bean. - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - if (pcs == null) { - pcs = new PropertyChangeSupport(owner); - } - pcs.addPropertyChangeListener(listener); - } - - /** - * Add a property change listener for this entity bean for a specific - * property. - */ - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - if (pcs == null) { - pcs = new PropertyChangeSupport(owner); - } - pcs.addPropertyChangeListener(propertyName, listener); - } - - /** - * Remove a property change listener for this entity bean. - */ - public void removePropertyChangeListener(PropertyChangeListener listener) { - if (pcs != null) { - pcs.removePropertyChangeListener(listener); - } - } - - /** - * Remove a property change listener for this entity bean for a specific - * property. - */ - public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { - if (pcs != null) { - pcs.removePropertyChangeListener(propertyName, listener); - } - } - - /** - * Turn on profile collection. - */ - public void setNodeUsageCollector(NodeUsageCollector usageCollector) { - this.nodeUsageCollector = usageCollector; - } - - /** - * Return the owning bean for an embedded bean. - */ - public Object getEmbeddedOwner() { - return embeddedOwner; - } - - /** - * Return the property index (for the parent) of this embedded bean. - */ - public int getEmbeddedOwnerIndex() { - return embeddedOwnerIndex; - } - - /** - * Set the embedded beans owning bean. - */ - public void setEmbeddedOwner(EntityBean parentBean, int embeddedOwnerIndex) { - this.embeddedOwner = parentBean; - this.embeddedOwnerIndex = embeddedOwnerIndex; - } - - /** - * Set the BeanLoader with PersistenceContext. - */ - public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) { - this.beanLoader = beanLoader; - this.persistenceContext = ctx; - this.ebeanServerName = beanLoader.getName(); - } - - /** - * Set the BeanLoader. - */ - public void setBeanLoader(BeanLoader beanLoader) { - this.beanLoader = beanLoader; - this.ebeanServerName = beanLoader.getName(); - } - - public boolean isFullyLoadedBean() { - return fullyLoadedBean; - } - - public void setFullyLoadedBean(boolean fullyLoadedBean) { - this.fullyLoadedBean = fullyLoadedBean; - } - - /** - * Return true if this bean has been directly modified (it has oldValues) or - * if any embedded beans are either new or dirty (and hence need saving). - */ - public boolean isDirty() { - return dirty; - } - - /** - * Called by an embedded bean onto its owner. - */ - public void setEmbeddedDirty(int embeddedProperty) { - this.dirty = true; - setEmbeddedPropertyDirty(embeddedProperty); - } - - public void setDirty(boolean dirty) { - this.dirty = dirty; - } - - /** - * Return true if this entity bean is new and not yet saved. - */ - public boolean isNew() { - return state == STATE_NEW; - } - - /** - * Return true if the entity bean is new or dirty (and should be saved). - */ - public boolean isNewOrDirty() { - return isNew() || isDirty(); - } - - /** - * Return true if only the Id property has been loaded. - */ - public boolean hasIdOnly(int idIndex) { - for (int i = 0; i < loadedProps.length; i++) { - if (i == idIndex) { - if (!loadedProps[i]) return false; - } else if (loadedProps[i]) { - return false; - } - } - return true; - } - - /** - * Return true if the entity is a reference. - */ - public boolean isReference() { - return state == STATE_REFERENCE; - } - - /** - * Set this as a reference object. - */ - public void setReference(int idPos) { - state = STATE_REFERENCE; - if (idPos > -1) { - // For cases where properties are set on constructor - // set every non Id property to unloaded (for lazy loading) - for (int i=0; i< loadedProps.length; i++) { - if (i != idPos) { - loadedProps[i] = false; - } - } - } - } - - /** - * Return true if the bean should be treated as readOnly. If a setter method - * is called when it is readOnly an Exception is thrown. - */ - public boolean isReadOnly() { - return readOnly; - } - - /** - * Set the readOnly status. If readOnly then calls to setter methods through - * an exception. - */ - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; - } - - /** - * Return true if the entity has been loaded. - */ - public boolean isLoaded() { - return state == STATE_LOADED; - } - - /** - * Set the loaded state to true. - *- * Calls to setter methods after the bean is loaded can result in 'Old Values' - * being created to support ConcurrencyMode.ALL - *
- *- * Worth noting that this is also set after a insert/update. By doing so it - * 'resets' the bean for making further changes and saving again. - *
- */ - public void setLoaded() { - this.state = STATE_LOADED; - this.owner._ebean_setEmbeddedLoaded(); - this.lazyLoadProperty = -1; - this.origValues = null; - this.changedProps = null; - this.dirty = false; - } - - /** - * When finished loading for lazy or refresh on an already partially populated - * bean. - */ - public void setLoadedLazy() { - this.state = STATE_LOADED; - this.lazyLoadProperty = -1; - } - - /** - * Check if the lazy load succeeded. If not then mark this bean as having - * failed lazy loading due to the underlying row being deleted. - *- * We mark the bean this way rather than immediately fail as we might be batch - * lazy loading and this bean might not be used by the client code at all. - * Instead we will fail as soon as the client code tries to use this bean. - *
- */ - public void checkLazyLoadFailure() { - if (lazyLoadProperty != -1) { - this.lazyLoadFailure = true; - } - } - - /** - * Return true if the bean is marked as having failed lazy loading. - */ - public boolean isLazyLoadFailure() { - return lazyLoadFailure; - } - - /** - * Return true if lazy loading is disabled. - */ - public boolean isDisableLazyLoad() { - return disableLazyLoad; - } - - /** - * Set true to turn off lazy loading. - *- * Typically used to disable lazy loading on SQL based report beans. - *
- */ - public void setDisableLazyLoad(boolean disableLazyLoad) { - this.disableLazyLoad = disableLazyLoad; - } - - /** - * Set the loaded status for the embedded bean. - */ - public void setEmbeddedLoaded(Object embeddedBean) { - if (embeddedBean instanceof EntityBean) { - EntityBean eb = (EntityBean) embeddedBean; - eb._ebean_getIntercept().setLoaded(); - } - } - - /** - * Return true if the embedded bean is new or dirty and hence needs saving. - */ - public boolean isEmbeddedNewOrDirty(Object embeddedBean) { - - if (embeddedBean == null) { - // if it was previously set then the owning bean would - // have oldValues containing the previous embedded bean - return false; - } - if (embeddedBean instanceof EntityBean) { - return ((EntityBean) embeddedBean)._ebean_getIntercept().isNewOrDirty(); - - } else { - // non-enhanced so must assume it is new and needs to be saved - return true; - } - } - - /** - * Return the original value that was changed via an update. - */ - public Object getOrigValue(int propertyIndex) { - if (origValues == null) { - return null; - } - return origValues[propertyIndex]; - } - - /** - * Finds the index position of a given property. Returns -1 if the property - * can not be found. - */ - public int findProperty(String propertyName) { - String[] names = owner._ebean_getPropertyNames(); - for (int i = 0; i < names.length; i++) { - if (names[i].equals(propertyName)) { - return i; - } - } - return -1; - } - - /** - * Return the property name for the given property. - */ - public String getProperty(int propertyIndex) { - if (propertyIndex == -1) { - return null; - } - return owner._ebean_getPropertyName(propertyIndex); - } - - /** - * Return the number of properties.s - */ - public int getPropertyLength() { - return owner._ebean_getPropertyNames().length; - } - - /** - * Set the property to be treated as unloaded. Used for properties initialised in default - * constructor. - */ - public void setPropertyUnloaded(int propertyIndex) { - loadedProps[propertyIndex] = false; - } - - /** - * Set the property to be loaded. - */ - public void setLoadedProperty(int propertyIndex) { - loadedProps[propertyIndex] = true; - } - - /** - * Return true if the property is loaded. - */ - public boolean isLoadedProperty(int propertyIndex) { - return loadedProps[propertyIndex]; - } - - /** - * Return true if the property is considered changed. - */ - public boolean isChangedProperty(int propertyIndex) { - return (changedProps != null && changedProps[propertyIndex]); - } - - /** - * Return true if the property was changed or if it is embedded and one of its - * embedded properties is dirty. - */ - public boolean isDirtyProperty(int propertyIndex) { - return (changedProps != null && changedProps[propertyIndex] - || embeddedDirty != null && embeddedDirty[propertyIndex]); - } - - /** - * Explicitly mark a property as having been changed. - */ - public void markPropertyAsChanged(int propertyIndex) { - setChangedProperty(propertyIndex); - setDirty(true); - } - - private void setChangedProperty(int propertyIndex) { - if (changedProps == null) { - changedProps = new boolean[owner._ebean_getPropertyNames().length]; - } - changedProps[propertyIndex] = true; - } - - /** - * Set that an embedded bean has had one of its properties changed. - */ - private void setEmbeddedPropertyDirty(int propertyIndex) { - if (embeddedDirty == null) { - embeddedDirty = new boolean[owner._ebean_getPropertyNames().length]; - } - embeddedDirty[propertyIndex] = true; - } - - private void setOriginalValue(int propertyIndex, Object value) { - if (origValues == null) { - origValues = new Object[owner._ebean_getPropertyNames().length]; - } - if (origValues[propertyIndex] == null) { - origValues[propertyIndex] = value; - } - } - - /** - * For forced update on a 'New' bean set all the loaded properties to changed. - */ - public void setNewBeanForUpdate() { - - if (changedProps == null) { - changedProps = new boolean[owner._ebean_getPropertyNames().length]; - } - - for (int i=0; i< loadedProps.length; i++) { - if (loadedProps[i]) { - changedProps[i] = true; - } - } - setDirty(true); - } - - /** - * Return the set of property names for a partially loaded bean. - */ - public Set+ * This provides the mechanisms to support deferred fetching of reference beans + * and oldValues generation for concurrency checking. + *
+ */ +public final class EntityBeanIntercept implements Serializable { + + private static final long serialVersionUID = -3664031775464862649L; + + private static final int STATE_NEW = 0; + private static final int STATE_REFERENCE = 1; + private static final int STATE_LOADED = 2; + + private transient NodeUsageCollector nodeUsageCollector; + + private transient PropertyChangeSupport pcs; + + private transient PersistenceContext persistenceContext; + + private transient BeanLoader beanLoader; + + private String ebeanServerName; + + /** + * The actual entity bean that 'owns' this intercept. + */ + private EntityBean owner; + + private EntityBean embeddedOwner; + private int embeddedOwnerIndex; + + /** + * One of NEW, REF, UPD. + */ + private int state; + + private boolean readOnly; + + private boolean dirty; + + /** + * Flag set to disable lazy loading - typically for SQL "report" type entity beans. + */ + private boolean disableLazyLoad; + + /** + * Flag set when lazy loading failed due to the underlying bean being deleted in the DB. + */ + private boolean lazyLoadFailure; + + /** + * Used when a bean is partially filled. + */ + private boolean[] loadedProps; + + private boolean fullyLoadedBean; + + /** + * Set of changed properties. + */ + private boolean[] changedProps; + + /** + * Flags indicating if a property is a dirty embedded bean. Used to distingush + * between an embedded bean being completely overwritten and one of its + * embedded properties being made dirty. + */ + private boolean[] embeddedDirty; + + private Object[] origValues; + + private int lazyLoadProperty = -1; + + /** + * Create a intercept with a given entity. + *+ * Refer to agent ProxyConstructor. + *
+ */ + public EntityBeanIntercept(Object ownerBean) { + this.owner = (EntityBean) ownerBean; + this.loadedProps = new boolean[owner._ebean_getPropertyNames().length]; + } + + /** + * Return the 'owning' entity bean. + */ + public EntityBean getOwner() { + return owner; + } + + /** + * Return the persistenceContext. + */ + public PersistenceContext getPersistenceContext() { + return persistenceContext; + } + + /** + * Set the persistenceContext. + */ + public void setPersistenceContext(PersistenceContext persistenceContext) { + this.persistenceContext = persistenceContext; + } + + /** + * Add a property change listener for this entity bean. + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + if (pcs == null) { + pcs = new PropertyChangeSupport(owner); + } + pcs.addPropertyChangeListener(listener); + } + + /** + * Add a property change listener for this entity bean for a specific + * property. + */ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + if (pcs == null) { + pcs = new PropertyChangeSupport(owner); + } + pcs.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a property change listener for this entity bean. + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + if (pcs != null) { + pcs.removePropertyChangeListener(listener); + } + } + + /** + * Remove a property change listener for this entity bean for a specific + * property. + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + if (pcs != null) { + pcs.removePropertyChangeListener(propertyName, listener); + } + } + + /** + * Turn on profile collection. + */ + public void setNodeUsageCollector(NodeUsageCollector usageCollector) { + this.nodeUsageCollector = usageCollector; + } + + /** + * Return the owning bean for an embedded bean. + */ + public Object getEmbeddedOwner() { + return embeddedOwner; + } + + /** + * Return the property index (for the parent) of this embedded bean. + */ + public int getEmbeddedOwnerIndex() { + return embeddedOwnerIndex; + } + + /** + * Set the embedded beans owning bean. + */ + public void setEmbeddedOwner(EntityBean parentBean, int embeddedOwnerIndex) { + this.embeddedOwner = parentBean; + this.embeddedOwnerIndex = embeddedOwnerIndex; + } + + /** + * Set the BeanLoader with PersistenceContext. + */ + public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) { + this.beanLoader = beanLoader; + this.persistenceContext = ctx; + this.ebeanServerName = beanLoader.getName(); + } + + /** + * Set the BeanLoader. + */ + public void setBeanLoader(BeanLoader beanLoader) { + this.beanLoader = beanLoader; + this.ebeanServerName = beanLoader.getName(); + } + + public boolean isFullyLoadedBean() { + return fullyLoadedBean; + } + + public void setFullyLoadedBean(boolean fullyLoadedBean) { + this.fullyLoadedBean = fullyLoadedBean; + } + + /** + * Return true if this bean has been directly modified (it has oldValues) or + * if any embedded beans are either new or dirty (and hence need saving). + */ + public boolean isDirty() { + return dirty; + } + + /** + * Called by an embedded bean onto its owner. + */ + public void setEmbeddedDirty(int embeddedProperty) { + this.dirty = true; + setEmbeddedPropertyDirty(embeddedProperty); + } + + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + /** + * Return true if this entity bean is new and not yet saved. + */ + public boolean isNew() { + return state == STATE_NEW; + } + + /** + * Return true if the entity bean is new or dirty (and should be saved). + */ + public boolean isNewOrDirty() { + return isNew() || isDirty(); + } + + /** + * Return true if only the Id property has been loaded. + */ + public boolean hasIdOnly(int idIndex) { + for (int i = 0; i < loadedProps.length; i++) { + if (i == idIndex) { + if (!loadedProps[i]) return false; + } else if (loadedProps[i]) { + return false; + } + } + return true; + } + + /** + * Return true if the entity is a reference. + */ + public boolean isReference() { + return state == STATE_REFERENCE; + } + + /** + * Set this as a reference object. + */ + public void setReference(int idPos) { + state = STATE_REFERENCE; + if (idPos > -1) { + // For cases where properties are set on constructor + // set every non Id property to unloaded (for lazy loading) + for (int i=0; i< loadedProps.length; i++) { + if (i != idPos) { + loadedProps[i] = false; + } + } + } + } + + /** + * Return true if the bean should be treated as readOnly. If a setter method + * is called when it is readOnly an Exception is thrown. + */ + public boolean isReadOnly() { + return readOnly; + } + + /** + * Set the readOnly status. If readOnly then calls to setter methods through + * an exception. + */ + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + + /** + * Return true if the entity has been loaded. + */ + public boolean isLoaded() { + return state == STATE_LOADED; + } + + /** + * Set the loaded state to true. + *+ * Calls to setter methods after the bean is loaded can result in 'Old Values' + * being created to support ConcurrencyMode.ALL + *
+ *+ * Worth noting that this is also set after a insert/update. By doing so it + * 'resets' the bean for making further changes and saving again. + *
+ */ + public void setLoaded() { + this.state = STATE_LOADED; + this.owner._ebean_setEmbeddedLoaded(); + this.lazyLoadProperty = -1; + this.origValues = null; + this.changedProps = null; + this.dirty = false; + } + + /** + * When finished loading for lazy or refresh on an already partially populated + * bean. + */ + public void setLoadedLazy() { + this.state = STATE_LOADED; + this.lazyLoadProperty = -1; + } + + /** + * Check if the lazy load succeeded. If not then mark this bean as having + * failed lazy loading due to the underlying row being deleted. + *+ * We mark the bean this way rather than immediately fail as we might be batch + * lazy loading and this bean might not be used by the client code at all. + * Instead we will fail as soon as the client code tries to use this bean. + *
+ */ + public void checkLazyLoadFailure() { + if (lazyLoadProperty != -1) { + this.lazyLoadFailure = true; + } + } + + /** + * Return true if the bean is marked as having failed lazy loading. + */ + public boolean isLazyLoadFailure() { + return lazyLoadFailure; + } + + /** + * Return true if lazy loading is disabled. + */ + public boolean isDisableLazyLoad() { + return disableLazyLoad; + } + + /** + * Set true to turn off lazy loading. + *+ * Typically used to disable lazy loading on SQL based report beans. + *
+ */ + public void setDisableLazyLoad(boolean disableLazyLoad) { + this.disableLazyLoad = disableLazyLoad; + } + + /** + * Set the loaded status for the embedded bean. + */ + public void setEmbeddedLoaded(Object embeddedBean) { + if (embeddedBean instanceof EntityBean) { + EntityBean eb = (EntityBean) embeddedBean; + eb._ebean_getIntercept().setLoaded(); + } + } + + /** + * Return true if the embedded bean is new or dirty and hence needs saving. + */ + public boolean isEmbeddedNewOrDirty(Object embeddedBean) { + + if (embeddedBean == null) { + // if it was previously set then the owning bean would + // have oldValues containing the previous embedded bean + return false; + } + if (embeddedBean instanceof EntityBean) { + return ((EntityBean) embeddedBean)._ebean_getIntercept().isNewOrDirty(); + + } else { + // non-enhanced so must assume it is new and needs to be saved + return true; + } + } + + /** + * Return the original value that was changed via an update. + */ + public Object getOrigValue(int propertyIndex) { + if (origValues == null) { + return null; + } + return origValues[propertyIndex]; + } + + /** + * Finds the index position of a given property. Returns -1 if the property + * can not be found. + */ + public int findProperty(String propertyName) { + String[] names = owner._ebean_getPropertyNames(); + for (int i = 0; i < names.length; i++) { + if (names[i].equals(propertyName)) { + return i; + } + } + return -1; + } + + /** + * Return the property name for the given property. + */ + public String getProperty(int propertyIndex) { + if (propertyIndex == -1) { + return null; + } + return owner._ebean_getPropertyName(propertyIndex); + } + + /** + * Return the number of properties.s + */ + public int getPropertyLength() { + return owner._ebean_getPropertyNames().length; + } + + /** + * Set the property to be treated as unloaded. Used for properties initialised in default + * constructor. + */ + public void setPropertyUnloaded(int propertyIndex) { + loadedProps[propertyIndex] = false; + } + + /** + * Set the property to be loaded. + */ + public void setLoadedProperty(int propertyIndex) { + loadedProps[propertyIndex] = true; + } + + /** + * Return true if the property is loaded. + */ + public boolean isLoadedProperty(int propertyIndex) { + return loadedProps[propertyIndex]; + } + + /** + * Return true if the property is considered changed. + */ + public boolean isChangedProperty(int propertyIndex) { + return (changedProps != null && changedProps[propertyIndex]); + } + + /** + * Return true if the property was changed or if it is embedded and one of its + * embedded properties is dirty. + */ + public boolean isDirtyProperty(int propertyIndex) { + return (changedProps != null && changedProps[propertyIndex] + || embeddedDirty != null && embeddedDirty[propertyIndex]); + } + + /** + * Explicitly mark a property as having been changed. + */ + public void markPropertyAsChanged(int propertyIndex) { + setChangedProperty(propertyIndex); + setDirty(true); + } + + private void setChangedProperty(int propertyIndex) { + if (changedProps == null) { + changedProps = new boolean[owner._ebean_getPropertyNames().length]; + } + changedProps[propertyIndex] = true; + } + + /** + * Set that an embedded bean has had one of its properties changed. + */ + private void setEmbeddedPropertyDirty(int propertyIndex) { + if (embeddedDirty == null) { + embeddedDirty = new boolean[owner._ebean_getPropertyNames().length]; + } + embeddedDirty[propertyIndex] = true; + } + + private void setOriginalValue(int propertyIndex, Object value) { + if (origValues == null) { + origValues = new Object[owner._ebean_getPropertyNames().length]; + } + if (origValues[propertyIndex] == null) { + origValues[propertyIndex] = value; + } + } + + /** + * For forced update on a 'New' bean set all the loaded properties to changed. + */ + public void setNewBeanForUpdate() { + + if (changedProps == null) { + changedProps = new boolean[owner._ebean_getPropertyNames().length]; + } + + for (int i=0; i< loadedProps.length; i++) { + if (loadedProps[i]) { + changedProps[i] = true; + } + } + setDirty(true); + } + + /** + * Return the set of property names for a partially loaded bean. + */ + public Set- * The AutoFetchNode identifies the location of the bean in the object graph. - *
- *- * It has to use a weak reference so as to ensure that it does not stop the - * associated bean from being garbage collected. - *
- */ -public final class NodeUsageCollector { - - /** - * The point in the object graph for a specific query and call stack point. - */ - private final ObjectGraphNode node; - - /** - * Weak to allow garbage collection. - */ - private final WeakReference+ * The AutoFetchNode identifies the location of the bean in the object graph. + *
+ *+ * It has to use a weak reference so as to ensure that it does not stop the + * associated bean from being garbage collected. + *
+ */ +public final class NodeUsageCollector { + + /** + * The point in the object graph for a specific query and call stack point. + */ + private final ObjectGraphNode node; + + /** + * Weak to allow garbage collection. + */ + private final WeakReference- * This is the properties that are used for a given bean in the object graph. - * This information is used by autoFetch to tune queries. - *
- */ - void collectNodeUsage(NodeUsageCollector collector); -} +package com.avaje.ebean.bean; + +/** + * Collects the profile information. + */ +public interface NodeUsageListener { + + /** + * Collect node usage "profiling" information. + *+ * This is the properties that are used for a given bean in the object graph. + * This information is used by autoFetch to tune queries. + *
+ */ + void collectNodeUsage(NodeUsageCollector collector); +} diff --git a/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java b/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java index 6514f87a5..e070e43f6 100644 --- a/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java +++ b/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java @@ -1,88 +1,88 @@ -package com.avaje.ebean.bean; - -import java.io.Serializable; - -/** - * Identifies a unique node of an object graph. - *- * It represents a location relative to the root of an object graph and specific - * to a query and call stack hash. - *
- */ -public final class ObjectGraphNode implements Serializable { - - private static final long serialVersionUID = 2087081778650228996L; - - /** - * Identifies the origin. - */ - private final ObjectGraphOrigin originQueryPoint; - - /** - * The path relative to the root. - */ - private final String path; - - /** - * Create at a sub level. - */ - public ObjectGraphNode(ObjectGraphNode parent, String path) { - this.originQueryPoint = parent.getOriginQueryPoint(); - this.path = parent.getChildPath(path); - } - - /** - * Create an the root level. - */ - public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) { - this.originQueryPoint = originQueryPoint; - this.path = path; - } - - /** - * Return the origin query point. - */ - public ObjectGraphOrigin getOriginQueryPoint() { - return originQueryPoint; - } - - private String getChildPath(String childPath) { - if (path == null) { - return childPath; - } else if (childPath == null) { - return path; - } else { - return path + "." + childPath; - } - } - - /** - * Return the path relative to the root. - */ - public String getPath() { - return path; - } - - public String toString() { - return "origin:" + originQueryPoint + " path[" + path+"]"; - } - - public int hashCode() { - int hc = 31 * originQueryPoint.hashCode(); - hc = 31 * hc + (path == null ? 0 : path.hashCode()); - return hc; - } - - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof ObjectGraphNode)) { - return false; - } - - ObjectGraphNode e = (ObjectGraphNode) obj; - return ((e.path == path) || (e.path != null && e.path.equals(path))) - && e.originQueryPoint.equals(originQueryPoint); - } -} +package com.avaje.ebean.bean; + +import java.io.Serializable; + +/** + * Identifies a unique node of an object graph. + *+ * It represents a location relative to the root of an object graph and specific + * to a query and call stack hash. + *
+ */ +public final class ObjectGraphNode implements Serializable { + + private static final long serialVersionUID = 2087081778650228996L; + + /** + * Identifies the origin. + */ + private final ObjectGraphOrigin originQueryPoint; + + /** + * The path relative to the root. + */ + private final String path; + + /** + * Create at a sub level. + */ + public ObjectGraphNode(ObjectGraphNode parent, String path) { + this.originQueryPoint = parent.getOriginQueryPoint(); + this.path = parent.getChildPath(path); + } + + /** + * Create an the root level. + */ + public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) { + this.originQueryPoint = originQueryPoint; + this.path = path; + } + + /** + * Return the origin query point. + */ + public ObjectGraphOrigin getOriginQueryPoint() { + return originQueryPoint; + } + + private String getChildPath(String childPath) { + if (path == null) { + return childPath; + } else if (childPath == null) { + return path; + } else { + return path + "." + childPath; + } + } + + /** + * Return the path relative to the root. + */ + public String getPath() { + return path; + } + + public String toString() { + return "origin:" + originQueryPoint + " path[" + path+"]"; + } + + public int hashCode() { + int hc = 31 * originQueryPoint.hashCode(); + hc = 31 * hc + (path == null ? 0 : path.hashCode()); + return hc; + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ObjectGraphNode)) { + return false; + } + + ObjectGraphNode e = (ObjectGraphNode) obj; + return ((e.path == path) || (e.path != null && e.path.equals(path))) + && e.originQueryPoint.equals(originQueryPoint); + } +} diff --git a/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java b/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java index f5259f412..8b62c56ca 100644 --- a/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java +++ b/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java @@ -1,84 +1,84 @@ -package com.avaje.ebean.bean; - -import java.io.Serializable; - -/** - * Represents a "origin" of an ORM object graph. This combines the call stack - * and query plan hash. - *- * The call stack is included so that the query can have different tuned fetches - * for each unique call stack. For example, a query to fetch a customer could be - * called by three different methods and each can be treated as a separate - * origin point (and autoFetch can tune each one separately). - *
- */ -public final class ObjectGraphOrigin implements Serializable { - - private static final long serialVersionUID = 410937765287968708L; - - private final CallStack callStack; - - private final String beanType; - - private final int queryHash; - - private final String key; - - public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) { - this.callStack = callStack; - this.beanType = beanType; - this.queryHash = queryHash; - this.key = callStack.getOriginKey(queryHash); - } - - /** - * The key includes the queryPlan hash and the callStack hash. This becomes - * the unique identifier for a query point. - */ - public String getKey() { - return key; - } - - /** - * The type of bean the query is fetching. - */ - public String getBeanType() { - return beanType; - } - - /** - * The call stack involved. - */ - public CallStack getCallStack() { - return callStack; - } - - public String getFirstStackElement() { - return callStack.getFirstStackTraceElement().toString(); - } - - public String toString() { - return "key["+ key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement()+" "; - } - - public int hashCode() { - int hc = 31 * callStack.hashCode(); - hc = 31 * hc + beanType.hashCode(); - hc = 31 * hc + queryHash; - return hc; - } - - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof ObjectGraphOrigin)) { - return false; - } - - ObjectGraphOrigin e = (ObjectGraphOrigin) obj; - return e.queryHash == queryHash - && e.beanType.equals(beanType) - && e.callStack.equals(callStack); - } -} +package com.avaje.ebean.bean; + +import java.io.Serializable; + +/** + * Represents a "origin" of an ORM object graph. This combines the call stack + * and query plan hash. + *+ * The call stack is included so that the query can have different tuned fetches + * for each unique call stack. For example, a query to fetch a customer could be + * called by three different methods and each can be treated as a separate + * origin point (and autoFetch can tune each one separately). + *
+ */ +public final class ObjectGraphOrigin implements Serializable { + + private static final long serialVersionUID = 410937765287968708L; + + private final CallStack callStack; + + private final String beanType; + + private final int queryHash; + + private final String key; + + public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) { + this.callStack = callStack; + this.beanType = beanType; + this.queryHash = queryHash; + this.key = callStack.getOriginKey(queryHash); + } + + /** + * The key includes the queryPlan hash and the callStack hash. This becomes + * the unique identifier for a query point. + */ + public String getKey() { + return key; + } + + /** + * The type of bean the query is fetching. + */ + public String getBeanType() { + return beanType; + } + + /** + * The call stack involved. + */ + public CallStack getCallStack() { + return callStack; + } + + public String getFirstStackElement() { + return callStack.getFirstStackTraceElement().toString(); + } + + public String toString() { + return "key["+ key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement()+" "; + } + + public int hashCode() { + int hc = 31 * callStack.hashCode(); + hc = 31 * hc + beanType.hashCode(); + hc = 31 * hc + queryHash; + return hc; + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ObjectGraphOrigin)) { + return false; + } + + ObjectGraphOrigin e = (ObjectGraphOrigin) obj; + return e.queryHash == queryHash + && e.beanType.equals(beanType) + && e.callStack.equals(callStack); + } +} diff --git a/src/main/java/com/avaje/ebean/bean/PersistenceContext.java b/src/main/java/com/avaje/ebean/bean/PersistenceContext.java index df78875db..d6775abd4 100644 --- a/src/main/java/com/avaje/ebean/bean/PersistenceContext.java +++ b/src/main/java/com/avaje/ebean/bean/PersistenceContext.java @@ -1,110 +1,110 @@ -package com.avaje.ebean.bean; - -/** - * Holds entity beans by there type and id. - *- * This is used to ensure only one instance for a given entity type and id is - * used to build object graphs from queries and lazy loading. - *
- */ -public interface PersistenceContext { - - /** - * Put the entity bean into the PersistanceContext. - */ - void put(Object id, Object bean); - - /** - * Put the entity bean into the PersistanceContext if one is not already - * present (for this id). - *- * Returns an existing entity bean (if one is already there) and otherwise - * returns null. - *
- */ - Object putIfAbsent(Object id, Object bean); - - /** - * Return an object given its type and unique id. - */ - Object get(Class> beanType, Object uid); - - /** - * Get the bean from the persistence context also checked to see if it had - * been previously deleted (if so then you also can't hit the L2 cache to - * fetch the bean for this particular persistence context). - */ - WithOption getWithOption(Class> beanType, Object uid); - - /** - * Clear all the references. - */ - void clear(); - - /** - * Clear all the references for a given type of entity bean. - */ - void clear(Class> beanType); - - /** - * Clear the reference to a specific entity bean. - */ - void clear(Class> beanType, Object uid); - - /** - * Clear the reference as a result of an entity being deleted. - */ - void deleted(Class> beanType, Object id); - - /** - * Return the number of beans of the given type in the persistence context. - */ - int size(Class> beanType); - - /** - * Wrapper on a bean to also indicate if a bean has been deleted. - *- * If a bean has been deleted then for the same persistence context is should - * not be able to be fetched from persistence context or L2 cache. - *
- */ - class WithOption { - - /** - * The bean was previously deleted from this persistence context (can't hit - * L2 cache). - */ - public static WithOption DELETED = new WithOption(true); - - private final boolean deleted; - private final Object bean; - - private WithOption(boolean deleted) { - this.deleted = true; - this.bean = null; - } - - /** - * The bean exists in the persistence context (and not been previously deleted). - */ - public WithOption(Object bean) { - this.deleted = false; - this.bean = bean; - } - - /** - * Return true if the bean was deleted. This means you can't hit the L2 - * cache. - */ - public boolean isDeleted() { - return deleted; - } - - /** - * Return the bean (from the persistence context). - */ - public Object getBean() { - return bean; - } - } -} +package com.avaje.ebean.bean; + +/** + * Holds entity beans by there type and id. + *+ * This is used to ensure only one instance for a given entity type and id is + * used to build object graphs from queries and lazy loading. + *
+ */ +public interface PersistenceContext { + + /** + * Put the entity bean into the PersistanceContext. + */ + void put(Object id, Object bean); + + /** + * Put the entity bean into the PersistanceContext if one is not already + * present (for this id). + *+ * Returns an existing entity bean (if one is already there) and otherwise + * returns null. + *
+ */ + Object putIfAbsent(Object id, Object bean); + + /** + * Return an object given its type and unique id. + */ + Object get(Class> beanType, Object uid); + + /** + * Get the bean from the persistence context also checked to see if it had + * been previously deleted (if so then you also can't hit the L2 cache to + * fetch the bean for this particular persistence context). + */ + WithOption getWithOption(Class> beanType, Object uid); + + /** + * Clear all the references. + */ + void clear(); + + /** + * Clear all the references for a given type of entity bean. + */ + void clear(Class> beanType); + + /** + * Clear the reference to a specific entity bean. + */ + void clear(Class> beanType, Object uid); + + /** + * Clear the reference as a result of an entity being deleted. + */ + void deleted(Class> beanType, Object id); + + /** + * Return the number of beans of the given type in the persistence context. + */ + int size(Class> beanType); + + /** + * Wrapper on a bean to also indicate if a bean has been deleted. + *+ * If a bean has been deleted then for the same persistence context is should + * not be able to be fetched from persistence context or L2 cache. + *
+ */ + class WithOption { + + /** + * The bean was previously deleted from this persistence context (can't hit + * L2 cache). + */ + public static WithOption DELETED = new WithOption(true); + + private final boolean deleted; + private final Object bean; + + private WithOption(boolean deleted) { + this.deleted = true; + this.bean = null; + } + + /** + * The bean exists in the persistence context (and not been previously deleted). + */ + public WithOption(Object bean) { + this.deleted = false; + this.bean = bean; + } + + /** + * Return true if the bean was deleted. This means you can't hit the L2 + * cache. + */ + public boolean isDeleted() { + return deleted; + } + + /** + * Return the bean (from the persistence context). + */ + public Object getBean() { + return bean; + } + } +} diff --git a/src/main/java/com/avaje/ebean/cache/ServerCache.java b/src/main/java/com/avaje/ebean/cache/ServerCache.java index 6efc6898a..00a105166 100644 --- a/src/main/java/com/avaje/ebean/cache/ServerCache.java +++ b/src/main/java/com/avaje/ebean/cache/ServerCache.java @@ -1,89 +1,89 @@ -package com.avaje.ebean.cache; - -import com.avaje.ebean.EbeanServer; - -/** - * Represents part of the "L2" server side cache. - *- * This is used to cache beans or query results (bean collections). - *
- *- * There are 2 ServerCache's for each bean type. One is used as the 'bean cache' - * which holds beans of a given type. The other is the 'query cache' holding - * query results for a given type. - *
- * - * @author rbygrave - */ -public interface ServerCache { - - /** - * Just after a cache is created this init method is called. This is so that a - * cache implementation can make use of the BackgroundExecutor service to - * trim/cleanup itself or use the EbeanServer to populate itself. - *- * This method is called after the cache is constructed but before the cache - * is made available for use. - *
- */ - void init(EbeanServer ebeanServer); - - /** - * Return the configuration options for this cache. - */ - ServerCacheOptions getOptions(); - - /** - * Update the configuration options for this cache. - */ - void setOptions(ServerCacheOptions options); - - /** - * Return the value given the key. - */ - Object get(Object id); - - /** - * Put the value in the cache with a given id. - */ - Object put(Object id, Object value); - - /** - * Put the value in the cache but only if a matching value is not already in - * the cache. - */ - Object putIfAbsent(Object id, Object value); - - /** - * Remove a entry from the cache given its id. - */ - Object remove(Object id); - - /** - * Clear all entries from the cache. - *- * NOTE: Be careful using this method in that most of the time application - * code should clear BOTH the bean and query caches at the same time. This can - * be done via {@link ServerCacheManager#clear(Class)}. - *
- */ - void clear(); - - /** - * Return the number of entries in the cache. - */ - int size(); - - /** - * Return the hit ratio the cache is currently getting. - */ - int getHitRatio(); - - /** - * Return statistics for the cache. - * - * @param reset - * if true the statistics are reset. - */ - ServerCacheStatistics getStatistics(boolean reset); -} +package com.avaje.ebean.cache; + +import com.avaje.ebean.EbeanServer; + +/** + * Represents part of the "L2" server side cache. + *+ * This is used to cache beans or query results (bean collections). + *
+ *+ * There are 2 ServerCache's for each bean type. One is used as the 'bean cache' + * which holds beans of a given type. The other is the 'query cache' holding + * query results for a given type. + *
+ * + * @author rbygrave + */ +public interface ServerCache { + + /** + * Just after a cache is created this init method is called. This is so that a + * cache implementation can make use of the BackgroundExecutor service to + * trim/cleanup itself or use the EbeanServer to populate itself. + *+ * This method is called after the cache is constructed but before the cache + * is made available for use. + *
+ */ + void init(EbeanServer ebeanServer); + + /** + * Return the configuration options for this cache. + */ + ServerCacheOptions getOptions(); + + /** + * Update the configuration options for this cache. + */ + void setOptions(ServerCacheOptions options); + + /** + * Return the value given the key. + */ + Object get(Object id); + + /** + * Put the value in the cache with a given id. + */ + Object put(Object id, Object value); + + /** + * Put the value in the cache but only if a matching value is not already in + * the cache. + */ + Object putIfAbsent(Object id, Object value); + + /** + * Remove a entry from the cache given its id. + */ + Object remove(Object id); + + /** + * Clear all entries from the cache. + *+ * NOTE: Be careful using this method in that most of the time application + * code should clear BOTH the bean and query caches at the same time. This can + * be done via {@link ServerCacheManager#clear(Class)}. + *
+ */ + void clear(); + + /** + * Return the number of entries in the cache. + */ + int size(); + + /** + * Return the hit ratio the cache is currently getting. + */ + int getHitRatio(); + + /** + * Return statistics for the cache. + * + * @param reset + * if true the statistics are reset. + */ + ServerCacheStatistics getStatistics(boolean reset); +} diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java b/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java index a08f560da..88f5d6083 100644 --- a/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java +++ b/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java @@ -1,26 +1,26 @@ -package com.avaje.ebean.cache; - -import com.avaje.ebean.EbeanServer; - -/** - * Defines method for constructing caches for beans and queries. - */ -public interface ServerCacheFactory { - - /** - * Just after the ServerCacheFactory is constructed this method is called - * passing the EbeanServer. - *- * This is so that a cache implementation can utilise the EbeanServer to - * populate itself or use the BackgroundExecutor service to schedule periodic - * cache trimming/cleanup. - *
- */ - void init(EbeanServer ebeanServer); - - /** - * Create the cache for the given type with options. - */ - ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions); - -} +package com.avaje.ebean.cache; + +import com.avaje.ebean.EbeanServer; + +/** + * Defines method for constructing caches for beans and queries. + */ +public interface ServerCacheFactory { + + /** + * Just after the ServerCacheFactory is constructed this method is called + * passing the EbeanServer. + *+ * This is so that a cache implementation can utilise the EbeanServer to + * populate itself or use the BackgroundExecutor service to schedule periodic + * cache trimming/cleanup. + *
+ */ + void init(EbeanServer ebeanServer); + + /** + * Create the cache for the given type with options. + */ + ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions); + +} diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java b/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java index 5b9889971..3e08718c2 100644 --- a/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java +++ b/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java @@ -1,55 +1,55 @@ -package com.avaje.ebean.cache; - -import com.avaje.ebean.EbeanServer; - -/** - * The cache service for server side caching of beans and query results. - */ -public interface ServerCacheManager { - - /** - * This method is called just after the construction of the - * ServerCacheManager. - *- * The EbeanServer is provided so that cache implementations can make use of - * EbeanServer and BackgroundExecutor for automatically populating and - * background trimming of the cache. - *
- */ - void init(EbeanServer server); - - void setCaching(Class> beanType, boolean useCache); - - /** - * Return true if there is an active bean cache for this type of bean. - */ - boolean isBeanCaching(Class> beanType); - - /** - * Return the cache for mapping natural keys to id values. - */ - ServerCache getNaturalKeyCache(Class> beanType); - - /** - * Return the cache for beans of a particular type. - */ - ServerCache getBeanCache(Class> beanType); - - ServerCache getCollectionIdsCache(Class> beanType, String propertyName); - - /** - * Return the cache for query results of a particular type of bean. - */ - ServerCache getQueryCache(Class> beanType); - - /** - * This clears both the bean and query cache for a given type. - */ - void clear(Class> beanType); - - /** - * Clear all the caches. - */ - void clearAll(); - -} +package com.avaje.ebean.cache; + +import com.avaje.ebean.EbeanServer; + +/** + * The cache service for server side caching of beans and query results. + */ +public interface ServerCacheManager { + + /** + * This method is called just after the construction of the + * ServerCacheManager. + *+ * The EbeanServer is provided so that cache implementations can make use of + * EbeanServer and BackgroundExecutor for automatically populating and + * background trimming of the cache. + *
+ */ + void init(EbeanServer server); + + void setCaching(Class> beanType, boolean useCache); + + /** + * Return true if there is an active bean cache for this type of bean. + */ + boolean isBeanCaching(Class> beanType); + + /** + * Return the cache for mapping natural keys to id values. + */ + ServerCache getNaturalKeyCache(Class> beanType); + + /** + * Return the cache for beans of a particular type. + */ + ServerCache getBeanCache(Class> beanType); + + ServerCache getCollectionIdsCache(Class> beanType, String propertyName); + + /** + * Return the cache for query results of a particular type of bean. + */ + ServerCache getQueryCache(Class> beanType); + + /** + * This clears both the bean and query cache for a given type. + */ + void clear(Class> beanType); + + /** + * Clear all the caches. + */ + void clearAll(); + +} diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java b/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java index 181c85869..a26be30b7 100644 --- a/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java +++ b/src/main/java/com/avaje/ebean/cache/ServerCacheOptions.java @@ -1,110 +1,110 @@ -package com.avaje.ebean.cache; - -import com.avaje.ebean.annotation.CacheTuning; - -/** - * Options for controlling a cache. - */ -public class ServerCacheOptions { - - private int maxSize; - private int maxIdleSecs; - private int maxSecsToLive; - - /** - * Construct with no set options. - */ - public ServerCacheOptions() { - - } - - /** - * Create from the cacheTuning deployment annotation. - */ - public ServerCacheOptions(CacheTuning cacheTuning) { - this.maxSize = cacheTuning.maxSize(); - this.maxIdleSecs = cacheTuning.maxIdleSecs(); - this.maxSecsToLive = cacheTuning.maxSecsToLive(); - } - - /** - * Create merging default options with the deployment specified ones. - */ - public ServerCacheOptions(ServerCacheOptions d) { - this.maxSize = d.getMaxSize(); - this.maxIdleSecs = d.getMaxIdleSecs(); - this.maxSecsToLive = d.getMaxIdleSecs(); - } - - /** - * Apply any settings from the default settings that have not already been - * specifically set. - */ - public void applyDefaults(ServerCacheOptions defaults) { - if (maxSize == 0) { - maxSize = defaults.getMaxSize(); - } - if (maxIdleSecs == 0) { - maxIdleSecs = defaults.getMaxIdleSecs(); - } - if (maxSecsToLive == 0) { - maxSecsToLive = defaults.getMaxSecsToLive(); - } - } - - /** - * Return a copy of this object. - */ - public ServerCacheOptions copy() { - - ServerCacheOptions copy = new ServerCacheOptions(); - copy.maxSize = maxSize; - copy.maxIdleSecs = maxIdleSecs; - copy.maxSecsToLive = maxSecsToLive; - - return copy; - } - - /** - * Return the maximum cache size. - */ - public int getMaxSize() { - return maxSize; - } - - /** - * Set the maximum cache size. - */ - public void setMaxSize(int maxSize) { - this.maxSize = maxSize; - } - - /** - * Return the maximum idle time. - */ - public int getMaxIdleSecs() { - return maxIdleSecs; - } - - /** - * Set the maximum idle time. - */ - public void setMaxIdleSecs(int maxIdleSecs) { - this.maxIdleSecs = maxIdleSecs; - } - - /** - * Return the maximum time to live. - */ - public int getMaxSecsToLive() { - return maxSecsToLive; - } - - /** - * Set the maximum time to live. - */ - public void setMaxSecsToLive(int maxSecsToLive) { - this.maxSecsToLive = maxSecsToLive; - } - -} +package com.avaje.ebean.cache; + +import com.avaje.ebean.annotation.CacheTuning; + +/** + * Options for controlling a cache. + */ +public class ServerCacheOptions { + + private int maxSize; + private int maxIdleSecs; + private int maxSecsToLive; + + /** + * Construct with no set options. + */ + public ServerCacheOptions() { + + } + + /** + * Create from the cacheTuning deployment annotation. + */ + public ServerCacheOptions(CacheTuning cacheTuning) { + this.maxSize = cacheTuning.maxSize(); + this.maxIdleSecs = cacheTuning.maxIdleSecs(); + this.maxSecsToLive = cacheTuning.maxSecsToLive(); + } + + /** + * Create merging default options with the deployment specified ones. + */ + public ServerCacheOptions(ServerCacheOptions d) { + this.maxSize = d.getMaxSize(); + this.maxIdleSecs = d.getMaxIdleSecs(); + this.maxSecsToLive = d.getMaxIdleSecs(); + } + + /** + * Apply any settings from the default settings that have not already been + * specifically set. + */ + public void applyDefaults(ServerCacheOptions defaults) { + if (maxSize == 0) { + maxSize = defaults.getMaxSize(); + } + if (maxIdleSecs == 0) { + maxIdleSecs = defaults.getMaxIdleSecs(); + } + if (maxSecsToLive == 0) { + maxSecsToLive = defaults.getMaxSecsToLive(); + } + } + + /** + * Return a copy of this object. + */ + public ServerCacheOptions copy() { + + ServerCacheOptions copy = new ServerCacheOptions(); + copy.maxSize = maxSize; + copy.maxIdleSecs = maxIdleSecs; + copy.maxSecsToLive = maxSecsToLive; + + return copy; + } + + /** + * Return the maximum cache size. + */ + public int getMaxSize() { + return maxSize; + } + + /** + * Set the maximum cache size. + */ + public void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } + + /** + * Return the maximum idle time. + */ + public int getMaxIdleSecs() { + return maxIdleSecs; + } + + /** + * Set the maximum idle time. + */ + public void setMaxIdleSecs(int maxIdleSecs) { + this.maxIdleSecs = maxIdleSecs; + } + + /** + * Return the maximum time to live. + */ + public int getMaxSecsToLive() { + return maxSecsToLive; + } + + /** + * Set the maximum time to live. + */ + public void setMaxSecsToLive(int maxSecsToLive) { + this.maxSecsToLive = maxSecsToLive; + } + +} diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java b/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java index 60f8eb587..969418917 100644 --- a/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java +++ b/src/main/java/com/avaje/ebean/cache/ServerCacheStatistics.java @@ -1,124 +1,124 @@ -package com.avaje.ebean.cache; - -/** - * The statistics collected per cache. - *- * These can be monitored to review the effectiveness of a particular cache. - *
- * - * @author rbygrave - * - */ -public class ServerCacheStatistics { - - protected String cacheName; - - protected int maxSize; - - protected int size; - - protected int hitCount; - - protected int missCount; - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(cacheName); - sb.append(" size:").append(size); - sb.append(" hitRatio:").append(getHitRatio()); - sb.append(" hitCount:").append(hitCount); - sb.append(" missCount:").append(missCount); - sb.append(" maxSize:").append(maxSize); - return sb.toString(); - } - - /** - * Return the name of the cache. - */ - public String getCacheName() { - return cacheName; - } - - /** - * Set the name of the cache. - */ - public void setCacheName(String cacheName) { - this.cacheName = cacheName; - } - - /** - * Return the hit count. The number of successful gets. - */ - public int getHitCount() { - return hitCount; - } - - /** - * Set the hit count. - */ - public void setHitCount(int hitCount) { - this.hitCount = hitCount; - } - - /** - * Return the miss count. The number of gets that returned null. - */ - public int getMissCount() { - return missCount; - } - - /** - * Set the miss count. - */ - public void setMissCount(int missCount) { - this.missCount = missCount; - } - - /** - * Return the size of the cache. - */ - public int getSize() { - return size; - } - - /** - * Set the size of the cache. - */ - public void setSize(int size) { - this.size = size; - } - - /** - * Return the maximum size of the cache. - *- * Can be used in conjunction with the size to determine if the cache use is - * being potentially limited by its maximum size. - *
- */ - public int getMaxSize() { - return maxSize; - } - - /** - * Set the maximum size of the cache. - */ - public void setMaxSize(int maxSize) { - this.maxSize = maxSize; - } - - /** - * Returns an int from 0 to 100 (percentage) for the hit ratio. - *- * A hit ratio of 100 means every get request against the cache hits an entry. - *
- */ - public int getHitRatio() { - int totalCount = hitCount + missCount; - if (totalCount == 0) { - return 0; - } else { - return hitCount * 100 / totalCount; - } - } - -} +package com.avaje.ebean.cache; + +/** + * The statistics collected per cache. + *+ * These can be monitored to review the effectiveness of a particular cache. + *
+ * + * @author rbygrave + * + */ +public class ServerCacheStatistics { + + protected String cacheName; + + protected int maxSize; + + protected int size; + + protected int hitCount; + + protected int missCount; + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(cacheName); + sb.append(" size:").append(size); + sb.append(" hitRatio:").append(getHitRatio()); + sb.append(" hitCount:").append(hitCount); + sb.append(" missCount:").append(missCount); + sb.append(" maxSize:").append(maxSize); + return sb.toString(); + } + + /** + * Return the name of the cache. + */ + public String getCacheName() { + return cacheName; + } + + /** + * Set the name of the cache. + */ + public void setCacheName(String cacheName) { + this.cacheName = cacheName; + } + + /** + * Return the hit count. The number of successful gets. + */ + public int getHitCount() { + return hitCount; + } + + /** + * Set the hit count. + */ + public void setHitCount(int hitCount) { + this.hitCount = hitCount; + } + + /** + * Return the miss count. The number of gets that returned null. + */ + public int getMissCount() { + return missCount; + } + + /** + * Set the miss count. + */ + public void setMissCount(int missCount) { + this.missCount = missCount; + } + + /** + * Return the size of the cache. + */ + public int getSize() { + return size; + } + + /** + * Set the size of the cache. + */ + public void setSize(int size) { + this.size = size; + } + + /** + * Return the maximum size of the cache. + *+ * Can be used in conjunction with the size to determine if the cache use is + * being potentially limited by its maximum size. + *
+ */ + public int getMaxSize() { + return maxSize; + } + + /** + * Set the maximum size of the cache. + */ + public void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } + + /** + * Returns an int from 0 to 100 (percentage) for the hit ratio. + *+ * A hit ratio of 100 means every get request against the cache hits an entry. + *
+ */ + public int getHitRatio() { + int totalCount = hitCount + missCount; + if (totalCount == 0) { + return 0; + } else { + return hitCount * 100 / totalCount; + } + } + +} diff --git a/src/main/java/com/avaje/ebean/common/AbstractBeanCollection.java b/src/main/java/com/avaje/ebean/common/AbstractBeanCollection.java index 58084a6a2..ab124de4c 100644 --- a/src/main/java/com/avaje/ebean/common/AbstractBeanCollection.java +++ b/src/main/java/com/avaje/ebean/common/AbstractBeanCollection.java @@ -1,222 +1,222 @@ -package com.avaje.ebean.common; - -import java.util.Set; - -import javax.persistence.PersistenceException; - -import com.avaje.ebean.Ebean; -import com.avaje.ebean.ExpressionList; -import com.avaje.ebean.bean.BeanCollection; -import com.avaje.ebean.bean.BeanCollectionLoader; -import com.avaje.ebean.bean.BeanCollectionTouched; -import com.avaje.ebean.bean.EntityBean; - -/** - * Base class for List Set and Map implementations of BeanCollection. - * - * @author rbygrave - */ -public abstract class AbstractBeanCollection- * This is primarily for the deferred fetching function. - *
- */ - @SuppressWarnings("unchecked") - public void setActualList(List> list) { - this.list = (List- * Specifically obj does not need to be a BeanList but any list. This does not - * use the FindMany, fetchedMaxRows or finishedFetch properties in the equals - * test. - *
- */ - public boolean equals(Object obj) { - init(); - return list.equals(obj); - } - - public int hashCode() { - init(); - return list.hashCode(); - } - - // -----------------------------------------------------// - // The additional methods are here - // -----------------------------------------------------// - - // -----------------------------------------------------// - // proxy method for List - // -----------------------------------------------------// - - public void add(int index, E element) { - checkReadOnly(); - init(); - if (modifyAddListening) { - modifyAddition(element); - } - list.add(index, element); - } - - public boolean add(E o) { - checkReadOnly(); - init(); - if (modifyAddListening) { - if (list.add(o)) { - modifyAddition(o); - return true; - } else { - return false; - } - } - return list.add(o); - } - - public boolean addAll(Collection extends E> c) { - checkReadOnly(); - init(); - if (modifyAddListening) { - // all elements in c are added (no contains checking) - getModifyHolder().modifyAdditionAll(c); - } - return list.addAll(c); - } - - public boolean addAll(int index, Collection extends E> c) { - checkReadOnly(); - init(); - if (modifyAddListening) { - // all elements in c are added (no contains checking) - getModifyHolder().modifyAdditionAll(c); - } - return list.addAll(index, c); - } - - public void clear() { - checkReadOnly(); - // TODO: when clear() and not initialised could be more clever - // and fetch just the Id's - initClear(); - if (modifyRemoveListening) { - for (int i = 0; i < list.size(); i++) { - getModifyHolder().modifyRemoval(list.get(i)); - } - } - list.clear(); - } - - public boolean contains(Object o) { - init(); - return list.contains(o); - } - - public boolean containsAll(Collection> c) { - init(); - return list.containsAll(c); - } - - public E get(int index) { - init(); - return list.get(index); - } - - public int indexOf(Object o) { - init(); - return list.indexOf(o); - } - - public boolean isEmpty() { - initAsUntouched(); - return list.isEmpty(); - } - - public Iterator+ * This is primarily for the deferred fetching function. + *
+ */ + @SuppressWarnings("unchecked") + public void setActualList(List> list) { + this.list = (List+ * Specifically obj does not need to be a BeanList but any list. This does not + * use the FindMany, fetchedMaxRows or finishedFetch properties in the equals + * test. + *
+ */ + public boolean equals(Object obj) { + init(); + return list.equals(obj); + } + + public int hashCode() { + init(); + return list.hashCode(); + } + + // -----------------------------------------------------// + // The additional methods are here + // -----------------------------------------------------// + + // -----------------------------------------------------// + // proxy method for List + // -----------------------------------------------------// + + public void add(int index, E element) { + checkReadOnly(); + init(); + if (modifyAddListening) { + modifyAddition(element); + } + list.add(index, element); + } + + public boolean add(E o) { + checkReadOnly(); + init(); + if (modifyAddListening) { + if (list.add(o)) { + modifyAddition(o); + return true; + } else { + return false; + } + } + return list.add(o); + } + + public boolean addAll(Collection extends E> c) { + checkReadOnly(); + init(); + if (modifyAddListening) { + // all elements in c are added (no contains checking) + getModifyHolder().modifyAdditionAll(c); + } + return list.addAll(c); + } + + public boolean addAll(int index, Collection extends E> c) { + checkReadOnly(); + init(); + if (modifyAddListening) { + // all elements in c are added (no contains checking) + getModifyHolder().modifyAdditionAll(c); + } + return list.addAll(index, c); + } + + public void clear() { + checkReadOnly(); + // TODO: when clear() and not initialised could be more clever + // and fetch just the Id's + initClear(); + if (modifyRemoveListening) { + for (int i = 0; i < list.size(); i++) { + getModifyHolder().modifyRemoval(list.get(i)); + } + } + list.clear(); + } + + public boolean contains(Object o) { + init(); + return list.contains(o); + } + + public boolean containsAll(Collection> c) { + init(); + return list.containsAll(c); + } + + public E get(int index) { + init(); + return list.get(index); + } + + public int indexOf(Object o) { + init(); + return list.indexOf(o); + } + + public boolean isEmpty() { + initAsUntouched(); + return list.isEmpty(); + } + + public Iterator- * This is because the key values may need to be set against the details (so - * they don't need to be set twice). - *
- */ - public Collection> getActualEntries() { - return map.entrySet(); - - } - - public String toString() { - StringBuilder sb = new StringBuilder(50); - sb.append("BeanMap "); - if (isReadOnly()) { - sb.append("readOnly "); - } - if (map == null) { - sb.append("deferred "); - - } else { - sb.append("size[").append(map.size()).append("]"); - sb.append(" map").append(map); - } - return sb.toString(); - } - - /** - * Equal if obj is a Map and equal in a Map sense. - */ - public boolean equals(Object obj) { - init(); - return map.equals(obj); - } - - public int hashCode() { - init(); - return map.hashCode(); - } - - public void clear() { - checkReadOnly(); - initClear(); - if (modifyRemoveListening) { - for (K key : map.keySet()) { - E o = map.remove(key); - modifyRemoval(o); - } - } - map.clear(); - } - - public boolean containsKey(Object key) { - init(); - return map.containsKey(key); - } - - public boolean containsValue(Object value) { - init(); - return map.containsValue(value); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Set+ * This is because the key values may need to be set against the details (so + * they don't need to be set twice). + *
+ */ + public Collection> getActualEntries() { + return map.entrySet(); + + } + + public String toString() { + StringBuilder sb = new StringBuilder(50); + sb.append("BeanMap "); + if (isReadOnly()) { + sb.append("readOnly "); + } + if (map == null) { + sb.append("deferred "); + + } else { + sb.append("size[").append(map.size()).append("]"); + sb.append(" map").append(map); + } + return sb.toString(); + } + + /** + * Equal if obj is a Map and equal in a Map sense. + */ + public boolean equals(Object obj) { + init(); + return map.equals(obj); + } + + public int hashCode() { + init(); + return map.hashCode(); + } + + public void clear() { + checkReadOnly(); + initClear(); + if (modifyRemoveListening) { + for (K key : map.keySet()) { + E o = map.remove(key); + modifyRemoval(o); + } + } + map.clear(); + } + + public boolean containsKey(Object key) { + init(); + return map.containsKey(key); + } + + public boolean containsValue(Object value) { + init(); + return map.containsValue(value); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Set- * This is required for persisting ManyToMany objects. Additions and removals - * become inserts and deletes to the intersection table. - *
- */ -class ModifyCollection- * The owner is notified of the additions and removals. - *
- */ - public ModifyCollection(BeanCollection+ * This is required for persisting ManyToMany objects. Additions and removals + * become inserts and deletes to the intersection table. + *
+ */ +class ModifyCollection+ * The owner is notified of the additions and removals. + *
+ */ + public ModifyCollection(BeanCollection- * These sets of additions and deletions are used to support persisting - * ManyToMany relationships. The additions becoming inserts into the - * intersection table and the removals becoming deletes from the intersection - * table. - *
- */ -class ModifyHolder+ * These sets of additions and deletions are used to support persisting + * ManyToMany relationships. The additions becoming inserts into the + * intersection table and the removals becoming deletes from the intersection + * table. + *
+ */ +class ModifyHolder- * This is required for persisting ManyToMany objects. Additions and removals - * become inserts and deletes to the intersection table. - *
- */ -class ModifyIterator- * The owner is notified of the removals. - *
- */ - ModifyIterator(BeanCollection+ * This is required for persisting ManyToMany objects. Additions and removals + * become inserts and deletes to the intersection table. + *
+ */ +class ModifyIterator+ * The owner is notified of the removals. + *
+ */ + ModifyIterator(BeanCollection- * This is required for persisting ManyToMany objects. Additions and removals - * become inserts and deletes to the intersection table. - *
- *- * Note that this is created by a call to subList() on a BeanList. Thats its - * only purpose really. BeanList holds the actual List. - *
- */ -class ModifyList