10.1. Compiling DNAL Source

The DNALCompiler class compiles DNAL source from a file, input stream, or string.

public interface DNALCompiler {
   CompilerOptions getCompilerOptions();
   void registryRuleFactory(RuleFactory factory);
   DataSet compile(String path);
   DataSet compile(String path, OuputGenerator visitor);
   DataSet compile(InputStream stream);
   DataSet compile(InputStream stream, OutputGenerator visitor);
   DataSet compileString(String input);
   DataSet compileString(String input, OuputGenerator visitor);
   List getErrors();
   void clearErrors();
}

After checking the input source is valid DNAL, the compiler builds an in-memory representation of the types and values.  Each value is then validated using the validation rules defined for its type. If compilation is successful, a DataSet is returned.  Also, if an OuputGenerator was supplied, then the types and/or values are rendered to it.

If any errors occur, the compiler stops and returns NULL.  Use getErrors to retrieve the errors.  The compiler will not produce any output if there are errors.

DNALCompiler is single use only.  Create a new instance for each compile.

10.2 DValue

Values in a DataSet are represented by immutable DValue objects.  DValue is a thin-wrapper around a Java object such as a Boolean or String.

public interface DValue {
  int asInt();
  double asNumber();
  long asLong();
  String asString();
  boolean asBoolean();
  Date asDate();
  List asList();
  Map asMap();
  DStructHelper asStruct();
  //..

10.3 DataSet

DataSet is an set of DNAL types and values.  It is guaranteed to be 100% valid. That is, its values have passed their validation rules.  Also, if a field is not marked optional, then it is guaranteed to be not NULL.

public interface DataSet {
  DValue getValue(String varName);
   T getAsBean(String varName, Class clazz);
  void registerBeanLoader(BeanLoader loader);
  Transaction createTransaction();
  DataSet cloneEmptyDataSet();
  //...
}

Each value defined by a let statement in the DNAL source is called a top-level value and can be retrieved by calling getValue.  It returns a DValue object which has methods to retrieve the value as a Java int, boolean, String, List, etc.

A BeanLoader converts a DVAL struct value into a Java bean.  Use registerBeanLoader to register the bean loader, and then getAsBean to get the value as a fully-populated bean.

Note.  A reflection-based loader is also available.  DNALLoader can load values into a DataSet from Java beans.

10.3.1 Are DataSets immutable?

The DataSet interface does not have any methods for modifying its data.  Its contents are immutable types (DType) and immutable values (DValue).  Does this mean that DataSet is immutable?  Yes, DNAL is not an execution language; it is a data language.  It represents values frozen in time.  Also, immutable values have many advantages in programming, such as thread safety.

However, there are times when modifying a dataset can be useful, and the DVAL API provides a controlled mechanism to do this.  It will be discussed in Transactions below.

10.3.2 Cloning a DataSet

createEmptyDataSet  is an efficient way to create a copy of a dataset.  It contains the types of the parent dataset, but no values.  This can be useful in conjunction with transactions (see Transactions below).

10.4 Transactions

 Once a DataSet has been created, the only way to modify its data is to use a Transaction. The createTransaction method returns a Transaction object to you can use to add additional values to the dataset.  (Note. In the current version of DNAL, transactions only support the “add” action.  “update” and “delete” will be available in a future release).
public interface Transaction {
 void add(String name, DValue dval);
 boolean commit();
 //...

The add method adds a new top-level value.  It is equivalent to a let statement in DNAL. The values in the transaction are stored inside the Transaction until the commit method is called. commit validates all the values according the the validation rules of their DNAL type. Committing a transaction, like a database transaction, is all or nothing. Either all the values in the Transaction get added to the DataSet or none of them do.

10.4.1 Using DNAL for Data Validation

You can DNAL to validate data arriving at an application. For example, validating an HTML form that is submitted to an application.  Define a struct type in DNAL that represents the fields of the form and their validation rules. Compile this DNAL source into a DataSet once at startup.  In the controller method that handles the form submission, create a temporary DataSet using cloneEmptyDataSet.  Use a Transaction to add the form’s bean to the dataset. If Transaction’s commit method fails, get the validation errors using getValErrorList.

10.5 Custom Rules

Custom rules are implemented by Java classes that implement the NRule interface. Register the rule with the DNALCompiler registerRuleFactory method.