SMS routing

From Complete Cyclos documentation wiki
Jump to: navigation, search

In a typical installation of Cyclos + SMS there will be one controller/driver for one Cyclos instance. It is however possible to connect more than one Driver and more than one Cycos instance to a single controller. Because of this the controller must be able to route incoming (Driver > Cyclos) and outgoing (Cyclos > Driver) messages to the correct Cyclos instance or Driver.

Routing Cyclos > Driver

Messages from Cylcos to the Driver are the outgoing messages. It is possible to send outgoing messages to different Drivers based on a custom field in the member profile. This field will have the mobile phone operator name. If no operator is defined in this field the default Driver will be used (see config example below). This way outgoing messages can be delivered directly to the provider of the message receiver what would result in cheaper costs for the organisations (as the organisation will be charged for outgoing messages). The custom field that defines the operator needs to be configured in the config.xml file of the in a cyclosInstance (see example below or Cyclos instances->memberSettings->providerCustomField). It also possible to define specific 'origin' phone numbers for the outgoing messages. This means that when users receive a message from the system the origin phone number can be different depending on the configuration. This would be common if you want to define more than one phone number for the same Cyclos instance.

Note: Allthough it is possible to configure various Drivers/Cyclos instances for one controller, for the large majority of projects only one controller/driver (AIO) and one Cyclos instance would be sufficiant (and the Routing configuration can be simply ommitted)

Example routing Cyclos > Driver

This is an example of one Cyclos instance a and one controller with internal driver (AIO) and two separate Drivers. As well the Cyclos instance, as AIO and two Drivers will run normally in the same application server. It is possible to to have them running in different application servers, and even in different locations.

In the example there are four users: Member A which has the provider Spring defined in the custom field 'provider', Member B with the provider Telefonica and Member C with the provider lowCost. Member D does not have anything defined in the field 'provider'. When no name is defined in the provider field the default Driver (argument default="true) is used. For information about the default Driver see: ( Cyclos instance->driverRouting->default).

This are the settings in the config.xml for the example:

<controller ...>
  <cyclosInstances>
    <cyclosInstance name="cyclos" language="en" country="US">
      .................
      <driverRouting>
        <route fromProvider="Spring" toDriver="springDriver" usedFromNumber="99999999"/> 
        <route fromProvider="Telefonica" toDriver="telefonicaDriver" usedFromNumber="99999999"/> 
        <route fromProvider="lowCost" toDriver="aioDriver" usedFromNumber="12345678"/> 
        <route fromProvider="*" toDriver="aioDriver" usedFromNumber="87654321" default="true"/> 
      </driverRouting>
      .................
      <memberSettings .... providerCustomField="provider" ...>
    </cyclosInstance>
  </cyclosInstances>
  ....................
</controller>

Routing results on above configuration:

  • Messages from Cyclos to Member A will use the springDriver.
  • Messages from Cyclos to Member B will use the telefonicaDriver.
  • Messages from Cyclos to Member C will use the aioDriver and origen nr 12345678.
  • Messages from Cyclos to any user other than the above will use the aioDriver and origen nr 87654321.


Message routing Driver > Cyclos

Message from the Driver to Cyclos are incoming messages (MO = Mobile Originated) and can be routed in two ways:

  1. Routing depending on the destination (organisation) phone number. The Driver will check the destination number which can be mapped to a specific Cyclos instance. (Note: the number that will be mapped is not the phone number of a user (payer/receiver) but the number of the organisation that will receive all messages)
  2. Routing depending on global commands or prefix

1 Routing depending on destination phone number

When there is an incoming message the controller will check the destination phone number (number that the SMS has been send to) and pass it to the Driver that is mapped to that number.
For the example we use the following configuration section of the Config.xml file:

  <driverInstances>
    <driverInstance name="aioDriver">
      <cyclosRouting>
        <route fromTargetNumber="99999999" toCyclos="cyclos"/>        
      </cyclosRouting>
      <connectionSettings connectionTimeout="120000" readTimeout="120000" disableCNCheck="true" trustAllCert="true"/>
    </driverInstance>
  </driverInstances>

In the above example, all messages that are handled by the controller via the Driver "aioDriver" and with destination number "99999999" will be passed to the Cyclos instance called "cyclos".

Important: It is necessary to configure an instance for each incoming number. In the above example. Any message that comes in via the "aioDriver" with a destination number other than "99999999" will be ignored.

2 Routing depending on global command or prefix

A part from the forwarding/mapping based on destination number it is also possible to define forwarding based on specific command (operation) names or prefixes.

Global commands

With global commands you can define specific commands names in the instance configurations so that each command can be handled by a different Cyclos instance. For example the command 'pay' could be forwarded to a specific Cyclos instance and the command 'payment' to another one. Mapping on destination and global commands can be used in a mixed configuration.

Note1: If two commands with the same name exists and are also mapped to the same driver the controller will just chose the first one. (see example below)
Note2: Commands that use the usingPrefix attribute (described further below) won't be evaluated by global commands.


Global command and Command not found error

Given a situation where an incoming message (via a Driver) has a fromTargetNumber for which more than one route exist (to different cyclosInstances) based on the config of the Global Commands.

In that case it could happen that the message cannot be mapped with none of the possible commands of the involved cyclosInstances. If it is not possible to determine a single cyclosInstances to hand over the processing, a an error of type Cyclos instance not found will be generated.

Global command examples

For the example we use the following configuration section of the Config.xml file:

 <driverInstances>
   <driverInstance name="aioDriver">
     <cyclosRouting>
       <route fromTargetNumber="11111111" toCyclos="cyclosOne"/>
       <route fromTargetNumber="11111111" toCyclos="cyclosTwo"/>
       <route fromTargetNumber="33333333" toCyclos="cyclosThree"/>
     </cyclosRouting>
     <connectionSettings connectionTimeout="120000" readTimeout="120000" disableCNCheck="true" trustAllCert="true"/>
   </driverInstance>
 </driverInstances>

Additional to the configuration above the Operation keys are defined in the instance properties file using regular expressions. (format: command.<commandName>.regularExpression).

  • cyclosOne
    • (\\s*)(acinfo|accountinfo)(\\s+.*)*$
    • (\\s*)(info|infotext)(\\s+.*)*$
  • cyclosTwo
    • (\\s*)(acinfo|accountinfo)(\\s+.*)*$
    • (\\s*)(pay|payment)(\\s+.*)*$
    • (\\s*)(rq|request)(\\s+.*)*$
  • cyclosThree
    • (\\s*)(pay|payment)(\\s+.*)*$
    • (\\s*)(info|infotext)(\\s+.*)*$
    • (\\s*)(help|helpinfo)(\\s+.*)*$

Note: As an example the above configuration has an invalid route for fromTargetNumber 11111111. For messages to this number with operation command (\\s*)(acinfo|accountinfo)(\\s+.*)*$ they could either to to cyclosOne or cyclosTwo. Both are matching.

For the example the following messages are received:

Global command
  • Destination number: 22222222
  • Text: acinfo 7410

Result: Message ignored by the controller. There is no route for "aioDriver" with fromTargetNumber "22222222".

Comandos global, by destination number
  • Destination number: 33333333
  • Text: infotext

Result: The message will be delivered to Cyclos instance "cyclosThree" as this is the only possible match.

Global command, by destination and name
  • Destion number: 11111111
  • Text: pay 7410 099123456

Result: The message will be delivered to Cyclos instance "cyclosTwo" because it is the only match. (the destination number matches two instances but only one has the pay command defined.

Routing based on text prefix

It is also possible to define a prefix for the commands. This can be either a name (characters) or numbers (digits). This can be done using the argument usingPrefix. Be aware that contrary to the global commands the prefix will match any occurrence but will always chose the most complete matching. For example a prefix of the characters 'pay' will match with both commands 'pay', 'payment' (and not with 'pagamiento'). But when a command 'payment' is passed it will only process the 'payment' command even if there exists a command defined as 'pay' within the same instance scope. This because the 'payment' command is an exacter match. If a command 'payment' is passed and the only possible command is 'pay' this command will be executed, because again, it the best match.

Note: for each fromTargetNumberthere must be only one unique prefix.

Text prefix examples

For the example we use the following configuration section of the Config.xml file:

 <driverInstances>
   <driverInstance name="aioDriver">
     <cyclosRouting>
       <route fromTargetNumber="11111111" toCyclos="cyclosOne" usingPrefix="eat"/>
       <route fromTargetNumber="11111111" toCyclos="cyclosTwo" usingPrefix="clean"/>
     </cyclosRouting>
     <connectionSettings connectionTimeout="120000" readTimeout="120000" disableCNCheck="true" trustAllCert="true"/>
   </driverInstance>
 </driverInstances>

Additional to the configuration above the Operation keys defined in the instance properties file using regular expressions. (format: command.<commandName>.regularExpression).

  • cyclosOne
    • (\\s*)(eatpizza)(\\s+.*)*$
  • cyclosTwo
    • (\\s*)(cleancar)(\\s+.*)*$
Prefix command 1
  • Destination number: 11111111
  • Text: eatpizza

Result: The message will be routed to the instance cyclosOne because it matches the prefix eat and a command for eatpizza exists for that instance.

Prefix command 2
  • Destination number: 11111111
  • Text: cleanpizza

Result: The system identifies a route to instance cyclosTwo based on the match of the prefix usingPrefix="clean". Because there is no match for the command cleanpizza in instance cyclosTwo, the system generates a command not found error.

Prefix command 3
  • Destination number: 11111111
  • Text: tvumbrella

Result: The system does not find a route because there is no prefix that matches with the message. The system will generate a message based on the key: controller.cyclosInstanceNotFound of the file controller.properties. The message depends on the configuration of the attribute: responseInvalidMessages defined in the Global settings.

Mix of global routing and text prefix

When a mixture of Text prefix and Global commands or used for the same Driverinstance with the same fromTargetNumber some points need to be considered:

  • The text prefix route has preference over the global commands. For example, when a message with the text "needmoney" is sent and a route with the usingPrefix="need exists it will have preference over any global command that would also match with "needmoney". This means that even if there is a global command match the message could be delivered to another Driver / Cyclos instance.
  • It is not possible to know what Cyclos instance will process a message if there is not one routing match for Text prefix or/and global command. In this case the user will receive an error message if this is defined in globalSetting->responseInvalidMessages="true".


Error example using two routings

Configuration:

<driverInstances>
  <driverInstance name="aioDriver">
    <cyclosRouting>
      <route fromTargetNumber="11111111" toCyclos="cyclosOne" usingPrefix="eat"/>
      <route fromTargetNumber="11111111" toCyclos="cyclosTwo" usingPrefix="need"/>
      <route fromTargetNumber="11111111" toCyclos="cyclosThree"/>
    </cyclosRouting>
    <connectionSettings connectionTimeout="120000" readTimeout="120000" disableCNCheck="true" trustAllCert="true"/>
  </driverInstance>
</driverInstances>


The Cyclos instances will have the following global commands defined (in the General operation keys->command.<commandName>.regularExpression):

  • cyclosOne
    • (\\s*)(eatmenu|eatm)(\\s+.*)*$
  • cyclosTwo
    • (\\s*)(needtaxi|needt)(\\s+.*)*$
    • (\\s*)(pay|payment)(\\s+.*)*$
  • cyclosThree
    • (\\s*)(pay|payment)(\\s+.*)*$
    • (\\s*)(info|infotext)(\\s+.*)*$
    • (\\s*)(needetails|need)(\\s+.*)*$


In the above example there are two routing errors.

  • The command defined in regular expression (\\s*)(pay|payment)(\\s+.*)*$ of the Cyclos instance "cyclosTwo", will never be executed because the route <route fromTargetNumber="0001" toCyclos="cyclosTwo" usingPrefix="need"/> (the only associated with cyclosTwo) will only pass message to cyclosTwo that have the prefix "need".
  • The command defined in regular expression (\\s*)(needetails|need)(\\s+.*)*$ of the instance cyclosThree will never be executed because any message that starts with the prefix "need" will be processed by instance cyclosTwo (because of the routing <route fromTargetNumber="0001" toCyclos="cyclosTwo" usingPrefix="need"/>)

Driver message routing errors

There are three types of routing errors. Explained below.

Command not found

This error occurs when the system achieves to obtain a single cyclos Instance responsible for the processing of the message, but the message does not match any of the commands that Cyclos instance has enabled. By default the error message will be send to the mobile origin.

Cyclos instance not found

This error occurs when using Global commands with multiple Cyclos instances, and the message does not match any of the commands defined in the Cyclos instances. In short, the system can not determine which is responsible Cyclos instances that needs to process the message. The default behavior of the application is to send a message back to the origin mobile. This is defined in the setting: responseInvalidMessage.

Custom error handler

It is possible to change to customize the (default) behavior in case errors are generated. This will require creating a class defined by the interface nl.strohalm.cyclos.controller.facade.MessageProcessErrorHandler that needs to be set in a bean with 'name = "messageProcessErrorHandler"' in the file WEB-INF/classess/controllerContext.xml.