package org.mobicents.slee.sipevent.server.subscription.sip;
import gov.nist.javax.sip.header.ims.PChargingFunctionAddressesHeader;
import gov.nist.javax.sip.header.ims.PChargingVectorHeader;
import java.text.ParseException;
import javax.persistence.EntityManager;
import javax.sip.Dialog;
import javax.sip.ListeningPoint;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.ContactHeader;
import javax.sip.header.EventHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.UserAgentHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import javax.slee.ActivityContextInterface;
import org.apache.log4j.Logger;
import org.mobicents.slee.sipevent.server.internal.InternalSubscriptionHandler;
import org.mobicents.slee.sipevent.server.subscription.ImplementedSubscriptionControlSbbLocalObject;
import org.mobicents.slee.sipevent.server.subscription.SubscriptionControlSbb;
import org.mobicents.slee.sipevent.server.subscription.pojo.Subscription;
/**
* Handler for SIP SUBSCRIBE events.
*
* @author martins
*
*/
public class SipSubscriptionHandler {
private static Logger logger = Logger
.getLogger(SubscriptionControlSbb.class);
protected SubscriptionControlSbb sbb;
private NewSipSubscriptionHandler newSipSubscriptionHandler;
private RefreshSipSubscriptionHandler refreshSipSubscriptionHandler;
private RemoveSipSubscriptionHandler removeSipSubscriptionHandler;
private SipSubscriberNotificationHandler sipSubscriberNotificationHandler;
public SipSubscriptionHandler(SubscriptionControlSbb sbb) {
this.sbb = sbb;
newSipSubscriptionHandler = new NewSipSubscriptionHandler(this);
refreshSipSubscriptionHandler = new RefreshSipSubscriptionHandler(this);
removeSipSubscriptionHandler = new RemoveSipSubscriptionHandler(this);
sipSubscriberNotificationHandler = new SipSubscriberNotificationHandler(
this);
}
// --- GETTERS
public NewSipSubscriptionHandler getNewSipSubscriptionHandler() {
return newSipSubscriptionHandler;
}
public RefreshSipSubscriptionHandler getRefreshSipSubscriptionHandler() {
return refreshSipSubscriptionHandler;
}
public RemoveSipSubscriptionHandler getRemoveSipSubscriptionHandler() {
return removeSipSubscriptionHandler;
}
public SipSubscriberNotificationHandler getSipSubscriberNotificationHandler() {
return sipSubscriberNotificationHandler;
}
// --- LOGIC
/**
* SIP SUBSCRIBE event processing
*
* @param event
* @param aci
*/
public void processRequest(RequestEvent event, ActivityContextInterface aci) {
// get child sbb that handles all the concrete event package subscription logic
ImplementedSubscriptionControlSbbLocalObject childSbb = sbb
.getImplementedControlChildSbb();
if (childSbb == null) {
try {
// create response
Response response = sbb.getMessageFactory().createResponse(
Response.SERVER_INTERNAL_ERROR, event.getRequest());
event.getServerTransaction().sendResponse(response);
if (logger.isDebugEnabled()) {
logger.debug("Response sent:\n" + response.toString());
}
} catch (Exception f) {
logger.error("Can't send error response!", f);
}
return;
}
EntityManager entityManager = sbb.getEntityManager();
if (logger.isDebugEnabled()) {
logger.debug("Processing SUBSCRIBE request...");
}
// get event header
EventHeader eventHeader = (EventHeader) event.getRequest().getHeader(
EventHeader.NAME);
if (eventHeader != null) {
// check event package
String eventPackage = eventHeader.getEventType();
if (acceptsEventPackage(eventPackage, childSbb)) {
// process expires header
ExpiresHeader expiresHeader = event.getRequest().getExpires();
int expires;
// if expires does not exist then set it's value to default
// value
if (expiresHeader == null) {
expires = sbb.getConfiguration().getDefaultExpires();
} else {
expires = expiresHeader.getExpires();
}
// check expires value
if (expires > 0) {
// check if expires is not less than the allowed min expires
if (expires >= sbb.getConfiguration().getMinExpires()) {
// ensure expires is not bigger than max expires
if (expires > sbb.getConfiguration().getMaxExpires()) {
expires = sbb.getConfiguration().getMaxExpires();
}
// new subscription or subscription refresh ?
Dialog dialog = event.getDialog();
if (dialog == null) {
// no dialog means it's a new subscription for sure
newSipSubscriptionHandler.newSipSubscription(event,
aci, eventPackage,
eventHeader.getEventId(), expires,
entityManager, childSbb);
} else {
String eventId = eventHeader.getEventId();
// trying to create or refresh a subscription
Subscription subscription = Subscription
.getSubscription(entityManager, dialog
.getCallId().getCallId(), dialog
.getRemoteTag(), eventPackage,
eventId);
if (subscription != null) {
// subscription exists
if (subscription.getStatus().equals(
Subscription.Status.active)
|| subscription.getStatus().equals(
Subscription.Status.pending)) {
// subscription status permits refresh
refreshSipSubscriptionHandler
.refreshSipSubscription(event, aci,
expires, subscription,
entityManager, childSbb);
} else {
// subscription status does not permits
// refresh
sendResponse(
Response.CONDITIONAL_REQUEST_FAILED,
event.getRequest(), event
.getServerTransaction(),
childSbb);
}
} else {
// subscription does not exists
newSipSubscriptionHandler.newSipSubscription(
event, aci, eventPackage, eventHeader
.getEventId(), expires,
entityManager, childSbb);
}
}
} else {
// expires is > 0 but < min expires, respond (Interval
// Too Brief) with Min-Expires = MINEXPIRES
sendResponse(Response.INTERVAL_TOO_BRIEF, event
.getRequest(), event.getServerTransaction(),
childSbb);
}
}
else if (expires == 0) {
Dialog dialog = event.getDialog();
if (dialog != null) {
String eventId = eventHeader.getEventId();
// trying to remove a subscription
Subscription subscription = Subscription
.getSubscription(entityManager, dialog
.getCallId().getCallId(), dialog
.getRemoteTag(), eventPackage, eventId);
if (subscription != null) {
if (subscription.getStatus().equals(
Subscription.Status.active)
|| subscription.getStatus().equals(
Subscription.Status.pending)) {
// subscription exists and status permits remove
try {
Response response = sbb.getMessageFactory()
.createResponse(Response.OK,
event.getRequest());
response = addContactHeader(response);
response.addHeader(sbb.getHeaderFactory()
.createExpiresHeader(expires));
event.getServerTransaction().sendResponse(
response);
if (logger.isDebugEnabled()) {
logger.debug("Response sent:\n"
+ response.toString());
}
} catch (Exception e) {
logger.error("Can't send RESPONSE", e);
}
// remove subscription
if (subscription.getResourceList()) {
sbb.getEventListControlChildSbb().removeSubscription(subscription);
}
removeSipSubscriptionHandler
.removeSipSubscription(aci,
subscription, entityManager,
childSbb);
} else {
// subscription does exists but status does
// not permits removal
sendResponse(
Response.CONDITIONAL_REQUEST_FAILED,
event.getRequest(), event
.getServerTransaction(),
childSbb);
}
} else {
// subscription does not exists, one shot
// subscription request, not supported
sendResponse(Response.CONDITIONAL_REQUEST_FAILED,
event.getRequest(), event
.getServerTransaction(), childSbb);
}
} else {
// dialog does not exists, one shot subscription
// request, not supported
sendResponse(Response.CONDITIONAL_REQUEST_FAILED, event
.getRequest(), event.getServerTransaction(),
childSbb);
}
} else {
// expires can't be negative
sendResponse(Response.BAD_REQUEST, event.getRequest(),
event.getServerTransaction(), childSbb);
}
} else {
// wrong event package, send bad event type error
sendResponse(Response.BAD_EVENT, event.getRequest(), event
.getServerTransaction(), childSbb);
}
} else {
// subscribe does not have a event header
sendResponse(Response.BAD_REQUEST, event.getRequest(), event
.getServerTransaction(), childSbb);
}
entityManager.flush();
entityManager.close();
}
/*
* Sends a response with the specified status code, adding additional
* headers if needed
*/
public void sendResponse(int responseCode, Request request,
ServerTransaction serverTransaction,
ImplementedSubscriptionControlSbbLocalObject childSbb) {
try {
// create response
Response response = sbb.getMessageFactory().createResponse(
responseCode, request);
// add headers if needed
if (responseCode == Response.BAD_EVENT) {
String allowEventsHeader = "";
boolean first = true;
for (String acceptedEventPackage : childSbb.getEventPackages()) {
if (first) {
allowEventsHeader += acceptedEventPackage + ","
+ acceptedEventPackage + ".winfo";
first = false;
} else {
allowEventsHeader += "," + acceptedEventPackage + ","
+ acceptedEventPackage + ".winfo";
}
}
response.addHeader(sbb.getHeaderFactory()
.createAllowEventsHeader(allowEventsHeader));
} else if (responseCode == Response.INTERVAL_TOO_BRIEF) {
response.addHeader(sbb.getHeaderFactory()
.createMinExpiresHeader(
sbb.getConfiguration().getMinExpires()));
}
// 2xx response to SUBSCRIBE need a Contact
response = addContactHeader(response);
/*...aayush started adding here..(with ref issue#567)
*
* The 200 OK of the SUBSCRIBE needs to preserve the P-charging-vector
* header that was received in the request, adding a term-ioi parameter
* to it which points to the home domain.
*/
// 1. Get header from the request
PChargingVectorHeader pcv = (PChargingVectorHeader)
request.getHeader(PChargingVectorHeader.NAME);
// 2. Check for NULL, as the request may not come from IMS all the time.
if(pcv!=null)
{
pcv.setTerminatingIOI(sbb.getConfiguration().getPChargingVectorHeaderTerminatingIOI());
response.addHeader(pcv);
}
// We also need to get the P-charging-function-addresses header from the request
// and add it to the response:
PChargingFunctionAddressesHeader pcfa = (PChargingFunctionAddressesHeader)
request.getHeader(PChargingFunctionAddressesHeader.NAME);
if(pcfa!=null)
response.addHeader(pcfa);
//...aayush added code till here.
serverTransaction.sendResponse(response);
if (logger.isDebugEnabled()) {
logger.debug("Response sent:\n" + response.toString());
}
} catch (Exception e) {
logger.error("Can't send response!", e);
}
}
/*
* Adds subscription agent contact header to SIP response
*/
public Response addContactHeader(Response response) throws ParseException {
if (response.getHeader(ContactHeader.NAME) != null) {
response.removeHeader(ContactHeader.NAME);
}
ListeningPoint listeningPoint = sbb.getSipProvider().getListeningPoint(
"udp");
Address address = sbb.getAddressFactory().createAddress(
sbb.getConfiguration().getContactAddressDisplayName()
+ " <sip:" + listeningPoint.getIPAddress() + ">");
((SipURI) address.getURI()).setPort(listeningPoint.getPort());
response.addHeader(sbb.getHeaderFactory().createContactHeader(address));
return response;
}
/**
* verifies if the specified event packaged is accepted
*/
public boolean acceptsEventPackage(String eventPackage,
ImplementedSubscriptionControlSbbLocalObject childSbb) {
if (eventPackage != null) {
for (String acceptedEventPackage : childSbb.getEventPackages()) {
if (eventPackage.equals(acceptedEventPackage)
|| eventPackage.equals(acceptedEventPackage + ".winfo")) {
return true;
}
}
}
return false;
}
}