/*
* Created on Jul 26, 2005
*
* Copyright 2005 CafeSip.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.cafesip.jiplet.sip;
import java.util.ArrayList;
import java.util.Iterator;
import javax.sip.RequestEvent;
import javax.sip.address.URI;
import javax.sip.header.ToHeader;
import javax.sip.message.Request;
import org.cafesip.jiplet.Jiplet;
import org.cafesip.jiplet.JipletException;
import org.cafesip.jiplet.JipletLogger;
import org.cafesip.jiplet.JipletRequest;
import org.cafesip.jiplet.JipletResponse;
import org.cafesip.jiplet.JipletTimeout;
import org.cafesip.jiplet.config.jip.InitParam;
import org.cafesip.jiplet.config.jip.JipletConfig;
/**
* This jiplet class handles the SIP proxy functionality. One of the important
* functions of many server-side SIP applications is to proxy SIP request and
* response messages recieved from other SIP user agents. For routine proxy
* operations, instead of writing your own jiplet for proxy service, you can use
* this jiplet instead. This jiplet receives SIP request messages and proxies
* them to one or more locations. Similarly, it proxies response messages back
* to the originator of the request.
* <p>
* To use this jiplet, you will need to define a jiplet that uses this class in
* your jip.xml file and configure it to suit your needs. This is a jiplet class
* and therefore in the jip.xml file, you can use the same configuration
* elements as any other jiplet including mapping and security constraints.
* <p>
* You can configure how the jiplet works by specifying init params to the
* jiplet in the jip.xml file. The following init parameters are supported:
* <ul>
* <li>stateful - yes (or true) if this a stateful proxy. If not specified, it
* acts as a stateless proxy.</li>
* <li>addRecordRoute - yes (or true) if a record route is to be added. If not
* specified, it does not add the record route to SIP request messages</li>
* <li>presenceServer - yes (or true) if you are implementing a presence
* server. If not specified, it assumes that this is not a presence server..
* </li>
* <li>locationRegister - name of the class that implements the
* org.cafesip.jiplet.sip.Location interface. This is the mechanism by which
* the jiplet looks up the proxy locations. You application must provide this
* class.</li>
* <li>locationRegisterParam - an optional parameter that you can pass to your
* location register class. This parameter is passed on to the class after the
* class is instantiated and the init() method is called.</li>
* <li>forwardLocation - This optional parameter contains the name of another
* jiplet. After a request/response/timeout is processes by this jiplet, if this
* parameter is specified, this jiplet object forwards the event to the jiplet
* you specified here. You can use this feature if you need additional
* processing to supplement the proxy functionality.</li>
* </ul>
*
* @author Amit Chatterjee
*
*/
public class ProxyJiplet extends Jiplet
{
private boolean stateful = false;
private boolean addRecordRoute = false;
private boolean presenceServer = false;
private String forward;
private Location location;
public void init(JipletConfig config) throws JipletException
{
try
{
String location = null;
String location_param = null;
Iterator iter = config.getInitParams().getInitParam().iterator();
while (iter.hasNext() == true)
{
InitParam parm = (InitParam) iter.next();
if (parm.getParamName().equals("stateful") == true)
{
String v = parm.getParamValue();
if ((v.equals("true") == true) || (v.equals("yes") == true))
{
stateful = true;
if (isDebugEnabled() == true)
{
debug("The ProxyJiplet is stateful.");
}
}
else if ((v.equals("false") == true)
|| (v.equals("no") == true))
{
stateful = false;
}
else
{
throw new JipletException(
"The value for the init-param \"stateful\" is invalid");
}
}
else if (parm.getParamName().equals("addRecordRoute") == true)
{
String v = parm.getParamValue();
if ((v.equals("true") == true) || (v.equals("yes") == true))
{
addRecordRoute = true;
if (isDebugEnabled() == true)
{
debug("The ProxyJiplet will add record route parameter.");
}
}
else if ((v.equals("false") == true)
|| (v.equals("no") == true))
{
addRecordRoute = false;
}
else
{
throw new JipletException(
"The value for the init-param \"addRecordRoute\" is invalid");
}
}
else if (parm.getParamName().equals("presenceServer") == true)
{
String v = parm.getParamValue();
if ((v.equals("true") == true) || (v.equals("yes") == true))
{
presenceServer = true;
if (isDebugEnabled() == true)
{
debug("The ProxyJiplet presenceServer setting = true.");
}
}
else if ((v.equals("false") == true)
|| (v.equals("no") == true))
{
presenceServer = false;
}
else
{
throw new JipletException(
"The value for the init-param \"presenceServer\" is invalid");
}
}
else if (parm.getParamName().equals("locationRegister") == true)
{
location = parm.getParamValue();
}
else if (parm.getParamName().equals("locationRegisterParam") == true)
{
location_param = parm.getParamValue();
}
else if (parm.getParamName().equals("forwardLocation") == true)
{
forward = parm.getParamValue();
}
else
{
warn ("Unknown init-param " + parm.getParamName());
}
}
if (location == null)
{
throw new JipletException(
"The location database has not been specified");
}
initLocationRegister(location, location_param);
}
catch (JipletException e)
{
throw e;
}
catch (Exception e)
{
throw new JipletException(e);
}
}
private void initLocationRegister(String className, String param)
throws ClassNotFoundException, InstantiationException,
IllegalAccessException, JipletException
{
Class c = getJipletContext().getClassLoader().loadClass(className);
location = (Location) c.newInstance();
location.setAddressFactory(getAddressFactory());
location.setMessageFactory(getMessageFactory());
location.setHeaderFactory(getHeaderFactory());
location.init(param);
}
public void processRequest(JipletRequest requestEvent)
{
try
{
// print the trace provided by the base-class.
super.processRequest(requestEvent);
RequestEvent req_event = requestEvent.getRequestEvent();
Request req_msg = req_event.getRequest();
ToHeader to = (ToHeader) req_msg.getHeader(ToHeader.NAME);
URI addr = to.getAddress().getURI();
// look up the database
ArrayList contacts = location.getLocation(addr);
if ((isDebugEnabled() == true) && (contacts != null))
{
Iterator i = contacts.iterator();
while (i.hasNext())
{
debug("Found contact URI = " + ((URI) i.next()).toString()
+ " for 'To' address = " + addr.toString()
+ " in request message " + req_msg.getMethod());
}
}
SipCommunicator proxy = requestEvent.getSipCommunicator();
proxy.proxyRequest(contacts, addRecordRoute, stateful,
presenceServer);
}
catch (Exception e)
{
error("A SIP request message could not be proxied because an exception occured.\n"
+ e.getClass().getName()
+ ": "
+ e.getMessage()
+ "\n"
+ JipletLogger.getStackTrace(e));
}
finally
{
if (forward != null)
{
forward(requestEvent, forward);
}
}
}
public void processResponse(JipletResponse responseEvent)
{
try
{
// print the trace provided by the base-class.
super.processResponse(responseEvent);
SipCommunicator proxy = responseEvent.getSipCommunicator();
proxy.proxyResponse(presenceServer);
}
catch (Exception e)
{
error("A SIP response message could not be proxied because an exception occured.\n"
+ e.getClass().getName()
+ ": "
+ e.getMessage()
+ "\n"
+ JipletLogger.getStackTrace(e));
}
finally
{
if (forward != null)
{
forward(responseEvent, forward);
}
}
}
public void processTimeout(JipletTimeout timeoutEvent)
{
try
{
// print the trace provided by the base-class.
super.processTimeout(timeoutEvent);
SipCommunicator proxy = timeoutEvent.getSipCommunicator();
proxy.handleProxyTimeout(stateful);
}
catch (Exception e)
{
error("A SIP timeout could not be handled because an exception occured.\n"
+ e.getClass().getName()
+ ": "
+ e.getMessage()
+ "\n"
+ JipletLogger.getStackTrace(e));
}
finally
{
if (forward != null)
{
forward(timeoutEvent, forward);
}
}
}
}