.. _xml: Defining Rules With XML ======================================= Dealing with the definition of a rule by using Java classes and objects can be extremely complex. That's why, Atooma SDK provides an XML schema, allowing to more easily define rules according to the model described in previous sections. .. code-block:: xml :linenos: As you can see, starting from bottom of the schema, each rule has a structure defined by the following block: .. code-block:: xml :linenos: ... ... Definitions for trigger, condition checker and performer elements are similar. Let's consider for example trigger definition: .. code-block:: xml :linenos: ... ... It's easy to notice that this definition perfectly matches with details provided in section :ref:`coretriggerdef`. In particular, triggers have a list of parameters that can be statically defined within the rule or injected by using an external provider call, as reported in *trigger-parameter* element definition: .. code-block:: xml :linenos: ... ... Details on properties and external provider calls will be provided in following sections. Property Values ----------------- Let's consider definition of a simple property, as exposed in previous section: .. code-block:: xml :linenos: ... ... As reported in the XML excerpt above, values assigned to rule properties can be represented in different formats, defined through the ``literal`` attribute of ``property`` tag. A detailed description for all available literal formats is reported below: * ``binary`` - Binary sequence represented as a *Base64* string. Property value type class will be used for decoding the binary sequence, according to its own model. * ``string`` - A simple string. * ``number`` - String to be interpreted as a number, either integer or decimal. *Dot* character is used as a separator between integer and decimal parts. It's also possible to represent negative numbers by using *minus* character as a prefix for the value. * ``percent`` - String to be interpreted as an unsigned integer number, with value between *0* e *100* (included). * ``boolean`` - ``true`` or ``false``. * ``timestamp`` - String representing a timestamp with format ``yyyy/mm/dd hh:mm[:ss[.mmm]]``. Hour value is between *0* and *23*. Seconds and milliseconds are optional. In case milliseconds are specified, seconds must be reported too. * ``date`` - String representing a date with format ``yyyy/mm/dd``. * ``time`` - String representing a timestamp with format ``hh:mm[:ss[.mmm]]``. Hour value is between *0* and *23*. Seconds and milliseconds are optional. In case milliseconds are specified, seconds must be reported too. * ``duration`` - String to be interpreted as an unsigned integer number, representing a duration in seconds. * ``comparator`` - Uppercase string, representing a number comparator. Possible values are: ``LESS``, ``LESS_EQUAL``, ``EQUAL``, ``GREATER_EQUAL`` e ``GREATER``. External Provider Calls ------------------------------ Working with rules commonly requires parameters to be dynamically configured. Let's think for example about rules requesting home location. Of course, home location differs from user to user, so we cannot statically include such data within the rule definition. For such kind of scenarios, it would be extremely useful to rely on functions allowing to provide different data depending on device, user and context. This is exactly what external provider calls allow to do. Below is reported the definition of and external provider call within the XML schema: .. code-block:: xml :linenos: Exploiting a call to an external provider just requires to define a generic class (no specific extension is required) implementing a static method without parameters, as reported in following example: .. code-block:: xml :linenos: ... ... Please notice that ``className`` attribute must include also class package, so be aware in case you perform changes on packages organization. It follows a possible implementation for ``HomeLocationProvider`` class: .. code-block:: java :linenos: public class HomeLocationProvider { public static VT_Location_Wrapper getHome() { // custom logic for retrieving home location LocationWrapper home = getHomeLocation(); // returning location wrapper for home return new VT_Location_Wrapper(home); } ... } Class ``VT_Location_Wrapper`` is a wrapper class used for encapsulating ``Area`` value type into a convenient common format. It follows a sample definition: .. code-block:: java :linenos: public class VT_Area_Wrapper implements ValueTypeWrapper { public static final String VT_MODULE = "LOCATION"; public static final String VT_ID = "AREA"; private LocationWrapper value; public VT_Area_Wrapper(LocationWrapper value) { this.value = value; } @Override public Object getValue() { return buildArea(value); } private Area buildArea(LocationWrapper wrapper) { Position p = new Position(wrapper.getLatitude(), wrapper.getLongitude(), wrapper.getAddress()); List cells = new ArrayList(); // building cell position for (LocationCell location : wrapper.getCells()) { CellPosition cell = new CellPosition(); cell.setCid(location.getCid()); cell.setLac(location.getLac()); cells.add(cell); } return new Area(p, 500, cells); } } All wrapper classes must implement the interface ``ValueTypeWrapper`` and accordingly define method ``getValue``, returning value type that this wrapper belongs to. Moreover, all classes implementing ``ValueTypeWrapper`` must include a couple of static parameters: * **VT_MODULE** - The identifier of the module that this wrapper belongs to. * **VT_ID** - The identifier of the value type that this wrapper belongs to. Please notice that currently Atooma SDK defines Value Type Wrapper class for all value types defined within basic modules. .. note:: In many cases, dealing with complex value types directly within XML definition could be difficult. That's because developer has to provide a binary value encoded in Base64 format, according to serialization / deserialization strategy defined by the value type itself. Below is reported a simple example. .. code-block:: xml :linenos: A0A0AAAAAAAA ... Using external providers and wrapper classes can simplify this activity by moving definition of parameter values into java code. .. code-block:: xml :linenos: .. code-block:: java :linenos: public class MyRuleProvider { public static VT_TextFilter_Wrapper getMyTextFilter() { NumberFilter filter = new NumberFilter(NumberFilter.GREATER, 20); return new VT_TextFilter_Wrapper(filter); } } Example --------------- Following example describe how an if-do rule expressed in natural language can be represented by using the model and XML format described in previous sections. Please notice that names of modules, value types, triggers, condition checkers and performers are from fantasy. Defining them is not a target of this section. * **Natural form** - *When receiving an SMS while driving, read it* * **Normalized form** - *If an SMS is received and my speed is greater than 20km/h, read sender name and message content* Below is reported the rule definition in XML format: .. code-block:: xml :linenos: Read SMS while driving A0A0AAAAAAAA incoming message message content from .. _srd: Atooma binary format --------------------------------- The Atooma binary format (SRD, *Serialized Rule Definition*) is an encoding used for representing a rule definition through a compact byte sequence. Even if rules in such format are not human readable, their parsing is much more efficient and memory required is minimized. Having a clear understanding of how binary format works is extremely important because the definition of new value types requires the implementation of proper methods for encoding / decoding data to / from their SRD representation. For such purpose, it follows a brief description of the binary representation for the primitive data types. * **Integer** - Integers are represented with 4 bytes in Big Endian mode (network order). * **Binary sequence** - Binary sequences are represented as follows: * An integer indicating the length of the sequence. In case value is negative, sequence is null. In case value is zero, sequence is empty. In case value is positive, sequence is populated. * In case sequence is populated, a number of bytes described by the length value. * **String** - Strings are represented as binary sequences, encoding characters according to UTF-8 charset. * **Boolean** - Booleans are represented with a single byte. ``0x0`` is used for representing ``FALSE``, while ``0x1`` is used for representing ``TRUE``. * **Number** - Numbers are decimal values. Their binary representation is aligned with IEEE P754 with double precision (8 bytes). * **Timestamp** - Timestamp values (date and time, with mills precision) are represented with UNIX Time format (number of mills elapsed in UTC from midnight of January 1, 1970). Such value is encoded using a 64 bit integer, represented with 8 bytes in Big Endian mode (network order). * **Date** - Dates are represented by saving the number of days (positive or negative) from January 1, 1970. Such value is encoded using a 32 bit integer, represented with 4 bytes in Big Endian mode (network order). * **Time** - Times are represented by saving the number of mills from the midnight of the previous day (0 time). Such value (always positive) is encoded using a 32 bit integer, represented with 4 bytes in Big Endian mode (network order). When defining new value types, serialization / deserialization logic must be defined for allowing Atooma to handle properties in SRD format. Please notice that binary format is also essential for defining properties in the XML definition of a rule.