We want to store the customer data in a database. As language to describe this transaction we use TDL (Transaction Definition Language) and as database we use Sqlite. So we have to tell the server to load the TDL module and the database module for Sqlite:
LoadModules { Module mod_protocol_wolframe Module mod_command_tdl Module mod_db_sqlite3 }
Now we also have to create a database and populate it with the following schema:
CREATE TABLE Customer ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, address TEXT );
Store this into schema.sql
. Then execute:
sqlite3 tutorial.db < schema.sql
Now we have to tell server to use this sqlite database file:
Database { SQLite { Identifier db File tutorial.db ForeignKeys yes } }
When we restart the server we see:
DEBUG: SQLite database unit 'db' created with 4 connections to file 'tutorial.db'
Now we want to use some XML filters to send/receive XML over the protocol,
so we have to add the following modules to tutorial.conf
:
LoadModules { Module mod_protocol_wolframe Module mod_command_tdl Module mod_db_sqlite3 Module mod_doctype_xml Module mod_filter_libxml2 }
The module mod_doctype_xml is there to detect documents of type XML. The module mod_filter_libxml2 is there to process XML documents. In order to see which modules are currently loaded in the wolframed we can use:
/usr/sbin/wolframed -p -c tutorial.conf
We see:
.. Module files to load: /usr/lib/wolframe/modules/mod_protocol_wolframe.so /usr/lib/wolframe/modules/mod_command_tdl.so /usr/lib/wolframe/modules/mod_db_sqlite3.so /usr/lib/wolframe/modules/mod_doctype_xml.so /usr/lib/wolframe/modules/mod_filter_libxml2.so ..
which looks ok.
For mapping the requests to programs in the business layer
we need the directmap module. First add to
tutorial.conf
:
LoadModules {
Module mod_protocol_wolframe
Module mod_command_tdl
Module mod_db_sqlite3
Module mod_doctype_xml
Module mod_filter_libxml2
Module mod_command_directmap
}
and a new section 'Processor' on the same level as 'LoadModules'
Processor { Database db CmdHandler { Directmap { Program tutorial.dmap Filter XML=libxml2 } } }
The "filter" directive denotes that the command handler should use the "libxml2" module for parsing XML requests.
Now we have to create a file tutorial.dmap
.
This file maps the requests to the corresponding transaction definitions:
COMMAND CustomerListRequest CALL SelectCustomerList RETURN SKIP {standalone="yes", root="list"};
We map the 'CustomerListRequest' request to a function 'SelectCustomerList' that is executed to perform the request. It will return the document without validation (SKIP). The attributes in curly brackets after the RETURN SKIP define the meta data of the document. Depending of the output filters used we have to define a set of document meta data. Because we do not declare the meta data as part of the document type description as we will do later, we have to declare them here in the command. The meta data attribute standalone='yes' tells the XML filter not to include any document type declaration. The declaration root='list' declares the root element for the XML output. In our example we need to define the root element because we use XML for output and XML needs a root element to be defined. The returned content will be a list of customers. The function will be implemented in a TDL program in the server. We first add the TDL program declaration to the 'Processor' configuration section:
Processor {
Database db
CmdHandler {
Directmap {
Program tutorial.dmap
Filter XML=libxml2
}
}
Program Customer.tdl
}
The Customer.tdl
file contains the database transaction 'SelectCustomerList'
we want to execute.
We only have to specify the enclosing tag 'customer' for each customer record
we are going to retrieve with 'INTO customer'.
TRANSACTION SelectCustomerList BEGIN INTO customer DO SELECT * from Customer; END
We also need a validator for the input when the client sends a 'CustomerListRequest'.
We load the simple form DDL compiler in the 'LoadModules' section of the tutorial.conf
and
register the simpleform program Customer.sfrm
to the list of programs in the same file:
LoadModules { Module mod_protocol_wolframe Module mod_command_tdl Module mod_db_sqlite3 Module mod_doctype_xml Module mod_filter_libxml2 Module mod_command_directmap Module mod_ddlcompiler_simpleform } Processor { Database db CmdHandler { Directmap { Program tutorial.dmap Filter XML=libxml2 } } Program Customer.tdl Program Customer.sfrm }
and we add a simple form file Customer.sfrm
.
We add a form called 'CustomerListRequest' which is empty for now
but for the root element 'customer':
FORM CustomerListRequest -root customer { }
We have to restart the Wolframe daemon now and restart it with:
pkill wolframed /usr/sbin/wolframed -f -c tutorial.conf
This we have to do every time we
change the configuration file tutorial.conf
or one of the files referenced there as tutorial.dmap
,
Customer.tdl
or Customer.sfrm
.
The server shows now a message about the transaction function it loaded:
DEBUG: Loaded transaction function 'SelectCustomerList'
Now we create a telnet request which contains pseudo authentication credentials
and a request for the list of customers, called
~/tutorial/client/CustomerListRequest.netcat
:
AUTH MECH NONE REQUEST <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE customer SYSTEM 'CustomerListRequest'> <customer/> . QUIT
This we can execute with:
netcat -v localhost 7661 < CustomerListRequest.netcat
and we get:
Wolframe OK MECHS NONE OK authorization ANSWER <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <list/> . OK REQUEST CustomerListRequest BYE
We got an empty list of customers. So we have successfully configured the server for our first command.
Let's add some customer data now:
cat > data.sql INSERT INTO Customer(name,address) values('Dr Who','Blue Police Box'); INSERT INTO Customer(name,address) values('John Smith','The Wheel in Space'); Ctrl-D sqlite3 tutorial.db < data.sql
When we reexecute the netcat command we see that the answer contains now the list of customers:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <list> <customer> <id>1</id> <name>Dr Who</name> <address>Blue Police Box</address> </customer> <customer> <id>2</id> <name>John Smith</name> <address>The Wheel in Space</address> </customer> </list>
So, the data is now correctly retrieved from the database.
Instead of using netcat you can also use the wolframec for testing the requests.
First create an XML file containing just the request and name
it CustomerListRequest.xml
:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE customer SYSTEM 'CustomerListRequest'> <customer/>
The request can be executed by calling:
wolframec -d CustomerListRequest.xml
We can also test the command without even starting the wolframed daemon process. We use the wolfilter program for that in the following way:
cat ~/tutorial/client/CustomerListRequest.xml | \ wolfilter -c ~/tutorial/server/tutorial.conf CustomerListRequest
We can move now to the wolfclient to make our first request visible.
Copyright © 2014 - Project Wolframe - All Rights Reserved