git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1191 f203690c-595d-4dc9-a70b-905162fa7fd2tags/jackcess-2.2.0
@@ -17,22 +17,55 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess.expr; | |||
import javax.script.Bindings; | |||
import com.healthmarketscience.jackcess.Database; | |||
/** | |||
* The EvalContext allows for customization of the expression evaluation | |||
* context for a given {@link Database} instance. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public interface EvalConfig | |||
{ | |||
/** | |||
* @return the currently configured TemporalConfig | |||
*/ | |||
public TemporalConfig getTemporalConfig(); | |||
/** | |||
* Sets the TemporalConfig for use when evaluating expressions. The default | |||
* date/time formatting is US based, so this may need to be modified when | |||
* interacting with {@link Database} instances from other locales. | |||
*/ | |||
public void setTemporalConfig(TemporalConfig temporal); | |||
/** | |||
* @return the currently configured FunctionLookup | |||
*/ | |||
public FunctionLookup getFunctionLookup(); | |||
/** | |||
* Sets the {@link Function} provider to use during expression evaluation. | |||
* The Functions supported by the default FunctionLookup are documented in | |||
* {@link com.healthmarketscience.jackcess#expr}. Custom Functions can be | |||
* implemented and provided to the expression evaluation engine by installing | |||
* a custom FunctionLookup instance (which would presumably wrap and | |||
* delegate to the default FunctionLookup instance for any default | |||
* implementations). | |||
*/ | |||
public void setFunctionLookup(FunctionLookup lookup); | |||
/** | |||
* @return the currently configured Bindings | |||
*/ | |||
public Bindings getBindings(); | |||
/** | |||
* Allows for passing custom information into expression evaluation. | |||
* Currently, none of the default implementations make use of the Bindings. | |||
* However, in the future, customization parameters could potentially be | |||
* supported via custom Bindings. Additionally, custom Function instances | |||
* could be passed external information via custom Bindings. | |||
*/ | |||
public void setBindings(Bindings bindings); | |||
} |
@@ -20,26 +20,66 @@ import java.text.SimpleDateFormat; | |||
import javax.script.Bindings; | |||
/** | |||
* EvalContext encapsulates all shared state for expression parsing and | |||
* evaluation. It provides a bridge between the expression execution engine | |||
* and the current Database. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public interface EvalContext | |||
{ | |||
/** | |||
* @return the currently configured TemporalConfig (from the | |||
* {@link EvalConfig}) | |||
*/ | |||
public TemporalConfig getTemporalConfig(); | |||
/** | |||
* @return an appropriately configured (i.e. TimeZone and other date/time | |||
* flags) SimpleDateFormat for the given format. | |||
*/ | |||
public SimpleDateFormat createDateFormat(String formatStr); | |||
/** | |||
* @param seed the seed for the random value, following the rules for the | |||
* "Rnd" function | |||
* @return a random value for the given seed following the statefulness | |||
* rules for the "Rnd" function | |||
*/ | |||
public float getRandom(Integer seed); | |||
/** | |||
* @return the expected type of the result value for the current expression | |||
* evaluation (for "default value" and "calculated" expressions) | |||
*/ | |||
public Value.Type getResultType(); | |||
/** | |||
* @return the value of the "current" column (for "field validator" | |||
* expressions) | |||
*/ | |||
public Value getThisColumnValue(); | |||
/** | |||
* @return the value of the entity identified by the given identifier (for | |||
* "calculated" and "row validator" expressions) | |||
*/ | |||
public Value getIdentifierValue(Identifier identifier); | |||
/** | |||
* @return the currently configured Bindings (from the {@link EvalConfig}) | |||
*/ | |||
public Bindings getBindings(); | |||
/** | |||
* @return the value of the current key from the currently configured | |||
* {@link Bindings} | |||
*/ | |||
public Object get(String key); | |||
/** | |||
* Sets the value of the given key to the given value in the currently | |||
* configured {@link Bindings}. | |||
*/ | |||
public void put(String key, Object value); | |||
} |
@@ -19,10 +19,8 @@ package com.healthmarketscience.jackcess.expr; | |||
import java.util.Collection; | |||
/** | |||
* FIXME, doc me and my friend | |||
* | |||
* An Expression is an executable handle to an Access expression. While the | |||
* expression framework is implemented as separate from the core database | |||
* expression framework is implemented separately from the core database | |||
* functionality, most usage of Expressions will happen indirectly within the | |||
* context of normal database operations. Thus, most users will not ever | |||
* directly interact with an Expression instance. That said, Expressions may | |||
@@ -32,13 +30,38 @@ import java.util.Collection; | |||
*/ | |||
public interface Expression | |||
{ | |||
/** | |||
* Evaluates the expression and returns the result. | |||
* | |||
* @param ctx the context within which to evaluate the expression | |||
* | |||
* @return the result of the expression evaluation | |||
*/ | |||
public Object eval(EvalContext ctx); | |||
/** | |||
* @return a detailed string which indicates how the expression was | |||
* interpreted by the expression evaluation engine. | |||
*/ | |||
public String toDebugString(); | |||
/** | |||
* @return the original, unparsed expression string. By contrast, the {@link | |||
* Object#toString} result may return a value which has been cleaned | |||
* up with respect to the original expression. | |||
*/ | |||
public String toRawString(); | |||
/** | |||
* @return {@code true} if this is a constant expression. A constant | |||
* expression will always return the same result when invoked and | |||
* has no side effect. | |||
*/ | |||
public boolean isConstant(); | |||
/** | |||
* Adds any Identifiers from this expression to the given collection. | |||
*/ | |||
public void collectIdentifiers(Collection<Identifier> identifiers); | |||
} |
@@ -17,12 +17,31 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess.expr; | |||
/** | |||
* A Function provides an invokable handle to external functionality to an | |||
* expression. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public interface Function | |||
public interface Function | |||
{ | |||
/** | |||
* @return the name of this function | |||
*/ | |||
public String getName(); | |||
/** | |||
* Evaluates this function within the given context with the given | |||
* parameters. | |||
* | |||
* @return the result of the function evaluation | |||
*/ | |||
public Value eval(EvalContext ctx, Value... params); | |||
/** | |||
* @return {@code true} if this function is a "pure" function, {@code false} | |||
* otherwise. A pure function will always return the same result | |||
* for a given set of parameters and has no side effects. | |||
*/ | |||
public boolean isPure(); | |||
} |
@@ -17,10 +17,17 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess.expr; | |||
/** | |||
* A FunctionLookup provides a source for {@link Function} instances used | |||
* during expression evaluation. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public interface FunctionLookup | |||
{ | |||
/** | |||
* @return the function for the given function name, or {@code null} if none | |||
* exists. Note that Access function names are treated in a case | |||
* insensitive manner. | |||
*/ | |||
public Function getFunction(String name); | |||
} |
@@ -19,15 +19,23 @@ package com.healthmarketscience.jackcess.expr; | |||
import org.apache.commons.lang.ObjectUtils; | |||
/** | |||
* identifies a database entity (e.g. the name of a database field). An | |||
* Identify must have an object name, but the collection name and property | |||
* name are optional. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public class Identifier | |||
public class Identifier | |||
{ | |||
private final String _collectionName; | |||
private final String _objectName; | |||
private final String _propertyName; | |||
public Identifier(String objectName) | |||
{ | |||
this(null, objectName, null); | |||
} | |||
public Identifier(String collectionName, String objectName, String propertyName) | |||
{ | |||
_collectionName = collectionName; | |||
@@ -35,17 +43,17 @@ public class Identifier | |||
_propertyName = propertyName; | |||
} | |||
public String getCollectionName() | |||
public String getCollectionName() | |||
{ | |||
return _collectionName; | |||
} | |||
public String getObjectName() | |||
public String getObjectName() | |||
{ | |||
return _objectName; | |||
} | |||
public String getPropertyName() | |||
public String getPropertyName() | |||
{ | |||
return _propertyName; | |||
} | |||
@@ -62,7 +70,7 @@ public class Identifier | |||
} | |||
Identifier oi = (Identifier)o; | |||
return (ObjectUtils.equals(_objectName, oi._objectName) && | |||
ObjectUtils.equals(_collectionName, oi._collectionName) && | |||
ObjectUtils.equals(_propertyName, oi._propertyName)); |
@@ -17,6 +17,11 @@ limitations under the License. | |||
package com.healthmarketscience.jackcess.expr; | |||
/** | |||
* A TemporalConfig encapsulates date/time formatting options for expression | |||
* evaluation. The default {@link #US_TEMPORAL_CONFIG} instance provides US | |||
* specific locale configuration. Databases which have been built for other | |||
* locales can utilize custom implementations of TemporalConfig in order to | |||
* evaluate expressions correctly. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
@@ -26,6 +31,7 @@ public class TemporalConfig | |||
public static final String US_TIME_FORMAT_12 = "h:mm:ss a"; | |||
public static final String US_TIME_FORMAT_24 = "H:mm:ss"; | |||
/** default implementation which is configured for the US locale */ | |||
public static final TemporalConfig US_TEMPORAL_CONFIG = new TemporalConfig( | |||
US_DATE_FORMAT, US_TIME_FORMAT_12, US_TIME_FORMAT_24, '/', ':'); | |||
@@ -37,6 +43,24 @@ public class TemporalConfig | |||
private final String _dateTimeFormat12; | |||
private final String _dateTimeFormat24; | |||
/** | |||
* Instantiates a new TemporalConfig with the given configuration. Note | |||
* that the date/time format variants will be created by concatenating the | |||
* relevant date and time formats, separated by a single space, e.g. "<date> | |||
* <time>". | |||
* | |||
* @param dateFormat the date (no time) format | |||
* @param timeFormat12 the 12 hour time format | |||
* @param timeFormat24 the 24 hour time format | |||
* @param dateSeparator the primary separator used to separate elements in | |||
* the date format. this is used to identify the | |||
* components of date/time string. | |||
* @param timeSeparator the primary separator used to separate elements in | |||
* the time format (both 12 hour and 24 hour). this is | |||
* used to identify the components of a date/time | |||
* string. This value should differ from the | |||
* dateSeparator. | |||
*/ | |||
public TemporalConfig(String dateFormat, String timeFormat12, | |||
String timeFormat24, char dateSeparator, | |||
char timeSeparator) |
@@ -20,11 +20,17 @@ import java.math.BigDecimal; | |||
import java.util.Date; | |||
/** | |||
* Wrapper for a typed primitive value used within the expression evaluation | |||
* engine. Note that the "Null" value is represented by an actual Value | |||
* instance with the type of {@link Type#NULL}. Also note that all the | |||
* conversion methods will throw an {@link EvalException} if the conversion is | |||
* not supported for the current value. | |||
* | |||
* @author James Ahlborn | |||
*/ | |||
public interface Value | |||
public interface Value | |||
{ | |||
/** the types supported within the expression evaluation engine */ | |||
public enum Type | |||
{ | |||
NULL, STRING, DATE, TIME, DATE_TIME, LONG, DOUBLE, BIG_DEC; | |||
@@ -60,22 +66,49 @@ public interface Value | |||
} | |||
} | |||
/** | |||
* @return the type of this value | |||
*/ | |||
public Type getType(); | |||
/** | |||
* @return the raw primitive value | |||
*/ | |||
public Object get(); | |||
/** | |||
* @return {@code true} if this value represents a "Null" value, | |||
* {@code false} otherwise. | |||
*/ | |||
public boolean isNull(); | |||
/** | |||
* @return this primitive value converted to a boolean | |||
*/ | |||
public boolean getAsBoolean(); | |||
/** | |||
* @return this primitive value converted to a String | |||
*/ | |||
public String getAsString(); | |||
/** | |||
* @return this primitive value converted to a Date | |||
*/ | |||
public Date getAsDateTime(EvalContext ctx); | |||
/** | |||
* @return this primitive value converted (rounded) to an int | |||
*/ | |||
public Integer getAsLongInt(); | |||
/** | |||
* @return this primitive value converted (rounded) to a double | |||
*/ | |||
public Double getAsDouble(); | |||
/** | |||
* @return this primitive value converted to a BigDecimal | |||
*/ | |||
public BigDecimal getAsBigDecimal(); | |||
} |
@@ -19,10 +19,16 @@ limitations under the License. | |||
* the 2.2.0 release). This functionality is currently disabled by default | |||
* but can be globally enabled via the system property | |||
* "com.healthmarketscience.jackcess.enableExpressionEvaluation" or | |||
* selectively enabled on a per database basis using {@link com.healthmarketscience.jackcess.Database#setEvaluateExpressions(Boolean)}. Expressions can be used in a | |||
* number of different places within an Access database. | |||
*<p/> | |||
* When enabled, Jackcess supports the following usage: | |||
* selectively enabled on a per database basis using {@link com.healthmarketscience.jackcess.Database#setEvaluateExpressions(Boolean)}. | |||
* <p/> | |||
* The expression evaluation engine implementation does its best to follow all | |||
* the warts and idiosyncracies of Access expression evaluation (both those | |||
* that are documented as well as those discovered through experimentation). | |||
* These include such things as value conversions, "Null" handling, rounding | |||
* rules, and implicit interpretations of expression in certain contexts. | |||
* <p/> | |||
* Expressions can be used in a number of different places within an Access | |||
* database. When enabled, Jackcess supports the following usage: | |||
* <ul> | |||
* <li><b>Default Values:</b> When a row is added which has a | |||
* {@code null} value for a field which has a default value | |||
@@ -48,19 +54,37 @@ limitations under the License. | |||
* <h2>Supporting Classes</h2> | |||
* <p/> | |||
* The classes in this package make up the public api for expression handling | |||
* in Jackcess. They geneerally fall into two categoreies: | |||
* in Jackcess. They generally fall into two categories: | |||
* <p/> | |||
* <h3>General Use Classes</h3> | |||
* <p/> | |||
* <ul> | |||
* <li>{@link EvalConfig} allows for customization of the expression | |||
* evaluation context for a given {@link com.healthmarketscience.jackcess.Database} instance.</li> | |||
* <li>{@link TemporalConfig} encapsulates date/time formatting options for | |||
* expression evaluation.</li> | |||
* <li>{@link FunctionLookup} provides a source for {@link Function} instances | |||
* used during expression evaluation.</li> | |||
* <li>{@link EvalException} wrapper exception thrown for failures which occur | |||
* during expression evaluation.</li> | |||
* <li>{@link ParseException} wrapper exception thrown for failures which | |||
* occur during expression parsing.</li> | |||
* </ul> | |||
* <p/> | |||
* <h3>Advanced Use Classes</h3> | |||
* <p/> | |||
* <ul> | |||
* <li>{@link EvalContext} encapsulates all shared state for expression | |||
* parsing and evaluation.</li> | |||
* <li>{@link Expression} provides an executable handle to an actual | |||
* Access expression.</li> | |||
* <li>{@link Function} provides an invokable handle to external functionality | |||
* to an expression.</li> | |||
* <li>{@link Identifier} identifies a database entity (e.g. the name of a | |||
* database field).</li> | |||
* <li>{@link Value} represents a typed primitive value.</li> | |||
* </ul> | |||
* <p/> | |||
* <p/> | |||
* <h2>Function Support</h2> | |||
* <p/> | |||
* Jackcess supports many of the standard Access functions. The following |
@@ -19,16 +19,17 @@ | |||
for more info. | |||
</p> | |||
<subsection name="Expression Evaluation"> | |||
<subsection name="Expression Evaluation (FIXME)"> | |||
<p> | |||
Have you ever wished that Jackcess could handle field "default | |||
values" (or other expressions)? Wish no longer! The 2.2.0 version | |||
of Jackcess has finally landed a beta version of expression | |||
evaluation. See the <a href="apidocs/com/healthmarketscience/jackcess/expr/package-summary.html#package_description">expr package</a> javadocs for more details. | |||
values" (or other expressins)? Wish no longer! Experimental | |||
support for expression evaluation has finally landed in the 2.2.0 | |||
release. See the <a href="apidocs/com/healthmarketscience/jackcess/expr/package-summary.html#package_description">expression package</a> | |||
javadocs for more details. | |||
</p> | |||
</subsection> | |||
<subsection name="Brand New License!"> | |||
<subsection name="Brand New License! (2015-04-16)"> | |||
<p> | |||
Due to the generosity of Health Market Science and the efforts of | |||
the <a href="https://tika.apache.org/">Apache Tika project</a>, the | |||
@@ -37,7 +38,7 @@ | |||
</p> | |||
</subsection> | |||
<subsection name="All New: Jackcess 2.0"> | |||
<subsection name="All New: Jackcess 2.0 (2013-08-26)"> | |||
<p> | |||
<b>New crunchy outside, same yummy filling!</b> | |||
</p> |