Entw.: Datasnap und Sencha Touch

Sencha Touch der Fa. Sencha und Datasnap der Fa. Embarcadero arbeiten hervorragend in einer WebApp-Applikation zusammen. Dabei übernimmt Sencha Touch die Client-Seite mit HTML5/CSS3 und Datasnap die Server-Seite als RESTServer. Anhand eines einfachen Beispiels wird gezeigt, wie einfach das Zusammenspiel funktioniert.

In unserem Beispiel benötigt die Client-Seite die Daten aller Gleise einer Werksbahn. Die Gleisliste wird anschliessend lokal über HTML5-Localstorage gespeichert.


Serverseitig mit Datasnap:

Die Server-Methode, die die Daten aus der Datenbank liest und im JSON-Format an den Client liefert, zeigt folgender Code:

type
{$MethodInfo ON}
  TDMHermesPermDataLists = class(TDSServerModule)
  private
    { Private declarations }
    FGleisList: TList<TJSONObject>;
  public
    function ListeGleise(const USID: String): TJSONObject;
 end;
{$MethodInfo OFF}

Die Methodenimplementierung wird hier nicht gezeigt. Sie besteht im Wesentlichen aus SQL-Anweisungen an die Datenbank.

Datasnap erzeugt den zugehörigen Javascript-Methodenaufruf und schreibt ihn in die Datei serverfunctions.js. Dieser Methodenaufruf ist von der Client-Seite anzuwenden, um die Daten der Gleisliste vom RESTServer zu beziehen. Folgendes Listing zeigt den erzeugten Code.

function TDMPermDataLists(connectionInfo)
{
  this.executor = new ServerFunctionExecutor("TDMPermDataLists",connectionInfo);
 
  /*
   * @param USID [in] - Type on server: string
   * @return result - Type on server: TJSONObject
   */
  this.ListeGleise = function(USID) {
    var returnObject = this.executor.executeMethod('ListeGleise', "GET", [USID], arguments[1], true, arguments[2], arguments[3]);
    if (arguments[1] == null) {
      if (returnObject != null && returnObject.result != null && isArray(returnObject.result)) {
        var resultArray = returnObject.result;
        var resultObject = new Object();
        resultObject.USID = USID;
        resultObject.result = resultArray[0];
        if (returnObject.cacheId != null && returnObject.cmdIndex != null) {
          resultObject._cacheId = returnObject.cacheId;
          resultObject._cmdIndex = returnObject.cmdIndex;
        }
        return resultObject;
      }
      return returnObject;
    }
  };
 
  this.ListeGleise_URL = function(USID) {
    return this.executor.getMethodURL("ListeGleise", "GET", [USID], arguments[1])[0];
  };
}

Client-seitig mit Sencha Touch:

Anfänglich ist das Kommunikationsobjekt und das Datasnap-Methodenobjekt einmalig zu initialisieren.

// Anfangsintialisierungen
permDataListsMethods = null;
connectionInfo = null;
 
// Setzen der Kommunikationsinformationen
function setConnection(host, port, urlPath) {
  connectionInfo = {"host":host,"port":port,"authentication":null,"pathPrefix":urlPath};
}
 
 
// Initialiserung der Kommunikation und des Methodenobjekts von Datasnap
setConnection(window.location.hostname,window.location.port,null);
 
PermDataListsMethods = new TDMPermDataLists(connectionInfo);

Sencha Touch besitzt einen komfortablen Mechanismus für den Umgang mit persistenten Daten. Man definiert ein Model und einen Store. Damit wird festgelegt, wie die Daten zu beziehen (Ajax-Aufruf) und lokal zu verwenden sind. Eine besondere Bedeutung kommt dem Model zu. Die Struktur des Models muss mit der JSON-Datenstruktur der zu liefernden Daten übereinstimmen.

Ext.regModel("GleisModel", {
  fields : [
    { name : "HBZ",   type : "string" },
    { name : "UBZ",   type : "string" },
    { name : "NR",    type : "string" },
    { name : "VALUE", type : "string" },
    { name : "XMID",  type : "number" },
    { name : "YMID",  type : "number" }
  ],
  proxy: {
    type: 'localstorage',
    id: 'app-gleisliste'
  }
});
 
gleisstore = new Ext.data.Store({
  model : "GleisModel",
  autoLoad: false,
  data  : []
});
 
function LoadGleisliste() {
 // >>>>>>>>>>> Aufruf der Datasnap-Methode >>>>>>>>>>
 var tmpObj = permDataListsMethods.ListeGleise(usid);
 // <<<<<<<<<<< Aufruf der Datasnap-Methode <<<<<<<<<<
 if (tmpObj && tmpObj.result && tmpObj.result.ErrId == 0) {
   while (gleisstore.getCount() > 0)
     gleisstore.removeAt(gleisstore.getCount()-1);
   gleisstore.loadData(tmpObj.result.items);
   gleisstore.save();
   gleisstore.sync();
 }
 else {
   doHandleResultError(tmpObj);
 }
}

Der Methodenaufruf permDataListsMethods.ListeGleise(usid) liefert die benötigten Daten. Die Gleisliste befindet sich in tmpObj.result.items.
Diese Gleisliste wird mit gleisstore.loadData(tmpObj.result.items); im Store gespeichert. Mit den Aufrufen gleisstore.save(); und gleisstore.sync(); werden die Daten in HTML5-Localstorage gespeichert.