GenericDBProxy - Code

From Wesip

From Wesip

There are two main classes that implement most of the service.

  • GenericDBProxy: Encapsulates all the SIP logic. It is a SipServlet.
  • ApplicationDBCall: Encapsulates all the database logic.


The application proxies incoming INVITE requests to a list of URIs retrieved from one of the several preconfigured Application Databases. Which database is queried, which statement is executed and which data is sent along, depends on the application prefix. The application looks for an application prefix in the request URI which uses to retrieve the statement data from the Master DB.

The statement data consists in a String with information tokens separated by a separator char. It has the following structure

  • database_name#callable-statement#SIP_paramA#SIP_paramB#SIP_paramN

where

  • [database_name]:Name of the target database. A JNDI datasource resource has to be configured in the application server that can be retrieved with the following lookup: (new InitialContext()).lookup("java:comp/env/database_name")
  • [callable_statement]:Stored procedure that will be executed in the target database.Must include a '?' character for every input parameter which is going to be bound plus one '?' for the outgoing parameter that will hold the list of proxy URIs separated by coma.
  • [SIP_paramN]: SIP data that will be bound to the input parameters of the statement. It can be the name of any of the headers present in the SIP requests. If the 'From' or 'To' headers are specified only the From and To URI are used, otherwise the whole header is bound.

Let's see a example

An incoming request arrives. The request URI is

  • sip:genericdbproxy.031@x.x.x.x

The GenericDBProxy servlet detects 031 as the application prefix and queries the master database

protected void doInvite(SipServletRequest invite) 
   throws ServletException, IOException {
 ....
 //Get the application prefix from the request URI
 String applicationPrefix = sipUri.getUser().substring(stripPrefix.length());
 ....
 //Retrieve statement data from the master databases
String statementData = ApplicationDBCall.getStatementData(applicationPrefix);

statementData will look like this

databaseFoo#begin provision.activate_service(?,?,?);end;#From,User-Agent

which is parsed as

  • database_name: databaseFoo
  • callable_statement: begin provision.activate_service(?,?,?);end;
  • SIP_param1:From
  • SIP_param2:User-Agent

The statement data is executed with

ApplicationDBCall applicationDBCall = 
         new ApplicationDBCall(statementData, invite);
//Executing the query
uris = applicationDBCall.execute(); 

At this point the ApplicationDBCall obtains a connection from the datasource at "java:comp/env/databaseFoo" (method DataSource getDatabase(String bbddName))

and creates the following statement :

 "begin provision.activate_service(?,?,?);end;"

Then binds the From URI and the User-Agent as the two first parameters and the third parameter as a bound parameter. The list of proxy URIs will be saved there after execution of the procedure.

// Set the parameters to the CallableStatement
for(i = 0; i < attributes.size(); i++){
   cstmt.setString(i+1, attributes.get(i));
}
// Register the out parameter.
cstmt.registerOutParameter(i+1,Types.VARCHAR);

// Executes the procedure
cstmt.execute();

When the stored procedure "provision.activate_service('From','User-Agent','Output') is executed in the database it will perform any database logic that applies and then save a list of URIs separated by coma in the Output variable. Using stored procedures instead of simple queries allows the application to be used with transactional purposes.

Going back to the SipServlet GenericDBProxy, now with the list of URIs the request can be proxied. Proxying operation is carried out by the proxyMessage(SipServletRequest invite, List uris) method.

The proxying logic involves obtaining a Proxy object from the request

// Obtain the Proxy object of the INVITE request.
Proxy proxy = invite.getProxy();

Configure the behaviour as per the initialization parameters

proxy.setParallel(parallel);
proxy.setSupervised(supervised);
proxy.setRecordRoute(recordroute);
if(!parallel){
  proxy.setSequentialSearchTimeout(timeout_seq);
 }

and then simply

// Do PROXY...
proxy.proxyTo(uris);

The application container will take care of all the responses automatically. In case that the deployment specifies record routing behaviour subsequent requests wil be managed by the container as well without the developer having to add extra code.

<< Signalling | Configuration >>