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);
}
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);
}
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
*/
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);
}
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();
}
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);
}
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;
_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;
}
}
Identifier oi = (Identifier)o;
-
+
return (ObjectUtils.equals(_objectName, oi._objectName) &&
ObjectUtils.equals(_collectionName, oi._collectionName) &&
ObjectUtils.equals(_propertyName, oi._propertyName));
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
*/
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, '/', ':');
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)
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;
}
}
-
+ /**
+ * @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();
}
* 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
* <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
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
</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>