Applications: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.