
org.mobicents.slee.resource.sip11.SipResourceAdaptor Maven / Gradle / Ivy
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2014, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
*
* This file incorporates work covered by the following copyright contributed under the GNU LGPL : Copyright 2007-2011 Red Hat.
*/
package org.mobicents.slee.resource.sip11;
import gov.nist.javax.sip.ResponseEventExt;
import gov.nist.javax.sip.SipListenerExt;
import gov.nist.javax.sip.Utils;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import gov.nist.javax.sip.stack.SIPClientTransaction;
import gov.nist.javax.sip.stack.SIPServerTransaction;
import gov.nist.javax.sip.stack.SIPTransaction;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import javax.sip.DialogState;
import javax.sip.DialogTerminatedEvent;
import javax.sip.IOExceptionEvent;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipFactory;
import javax.sip.SipProvider;
import javax.sip.TimeoutEvent;
import javax.sip.Transaction;
import javax.sip.TransactionState;
import javax.sip.TransactionTerminatedEvent;
import javax.sip.address.AddressFactory;
import javax.sip.address.URI;
import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.Header;
import javax.sip.header.HeaderFactory;
import javax.sip.header.MaxForwardsHeader;
import javax.sip.header.RouteHeader;
import javax.sip.header.ToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import javax.slee.Address;
import javax.slee.SLEEException;
import javax.slee.facilities.EventLookupFacility;
import javax.slee.facilities.Tracer;
import javax.slee.resource.ActivityAlreadyExistsException;
import javax.slee.resource.ActivityFlags;
import javax.slee.resource.ActivityHandle;
import javax.slee.resource.ActivityIsEndingException;
import javax.slee.resource.ConfigProperties;
import javax.slee.resource.ConfigProperties.Property;
import javax.slee.resource.EventFlags;
import javax.slee.resource.FailureReason;
import javax.slee.resource.FireEventException;
import javax.slee.resource.FireableEventType;
import javax.slee.resource.IllegalEventException;
import javax.slee.resource.InvalidConfigurationException;
import javax.slee.resource.Marshaler;
import javax.slee.resource.ReceivableService;
import javax.slee.resource.ResourceAdaptorContext;
import javax.slee.resource.UnrecognizedActivityHandleException;
import net.java.slee.resource.sip.CancelRequestEvent;
import net.java.slee.resource.sip.DialogForkedEvent;
import net.java.slee.resource.sip.DialogTimeoutEvent;
import org.mobicents.ha.javax.sip.ClusteredSipStack;
import org.mobicents.ha.javax.sip.LoadBalancerElector;
import org.mobicents.ha.javax.sip.cache.SipResourceAdaptorMobicentsSipCache;
import org.mobicents.slee.container.resource.SleeEndpoint;
import org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor;
import org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptorContext;
import org.mobicents.slee.resource.sip11.wrappers.ACKDummyTransaction;
import org.mobicents.slee.resource.sip11.wrappers.ClientDialogWrapper;
import org.mobicents.slee.resource.sip11.wrappers.ClientTransactionWrapper;
import org.mobicents.slee.resource.sip11.wrappers.DialogWrapper;
import org.mobicents.slee.resource.sip11.wrappers.DialogWrapperAppData;
import org.mobicents.slee.resource.sip11.wrappers.RequestEventWrapper;
import org.mobicents.slee.resource.sip11.wrappers.ResponseEventWrapper;
import org.mobicents.slee.resource.sip11.wrappers.ServerTransactionWrapper;
import org.mobicents.slee.resource.sip11.wrappers.ServerTransactionWrapperAppData;
import org.mobicents.slee.resource.sip11.wrappers.TimeoutEventWrapper;
import org.mobicents.slee.resource.sip11.wrappers.TransactionWrapper;
import org.mobicents.slee.resource.sip11.wrappers.TransactionWrapperAppData;
import org.mobicents.slee.resource.sip11.wrappers.Wrapper;
public class SipResourceAdaptor implements SipListenerExt,FaultTolerantResourceAdaptor {
// Config Properties Names -------------------------------------------
private static final String SIP_BIND_ADDRESS = "javax.sip.IP_ADDRESS";
private static final String SIP_PORT_BIND = "javax.sip.PORT";
private static final String TRANSPORTS_BIND = "javax.sip.TRANSPORT";
private static final String STACK_NAME_BIND = "javax.sip.STACK_NAME";
private static final String LOAD_BALANCER_HEART_BEAT_SERVICE_CLASS = "org.mobicents.ha.javax.sip.LoadBalancerHeartBeatingServiceClassName";
private static final String BALANCERS = "org.mobicents.ha.javax.sip.BALANCERS";
private static final String LOOSE_DIALOG_VALIDATION = "org.mobicents.javax.sip.LOOSE_DIALOG_VALIDATION";
// Config Properties Values -------------------------------------------
private int port;
private Set transports = new HashSet();
private String transportsProperty;
private String stackAddress;
private String sipBalancerHeartBeatServiceClassName;
private String balancers;
private String loadBalancerElector;
/**
* default is true;
*/
private boolean looseDialogSeqValidation = true;
/**
* allowed transports
*/
private Set allowedTransports = new HashSet();
/**
* the real sip stack provider
*/
private SipProvider provider;
/**
* the ra sip provider, which wraps the real one
*/
private SleeSipProviderImpl providerWrapper;
/**
* manages the ra activities
*/
private SipActivityManagement activityManagement;
/**
* caches the eventIDs, avoiding lookup in container
*/
private final EventIDCache eventIdCache = new EventIDCache();
/**
* tells the RA if an event with a specified ID should be filtered or not
*/
private final EventIDFilter eventIDFilter = new EventIDFilter();
/**
*
*/
private ResourceAdaptorContext raContext;
private SleeEndpoint sleeEndpoint;
private EventLookupFacility eventLookupFacility;
/**
*
*/
private Tracer tracer;
/**
*
*/
private ClusteredSipStack sipStack = null;
/**
*
*/
private SipFactory sipFactory = null;
/**
*
*/
private Marshaler marshaler = new SipMarshaler();
/**
* for all events we are interested in knowing when the event failed to be processed
*/
public static final int DEFAULT_EVENT_FLAGS = EventFlags.REQUEST_PROCESSING_FAILED_CALLBACK;
public static final int UNREFERENCED_EVENT_FLAGS = EventFlags.setRequestEventReferenceReleasedCallback(DEFAULT_EVENT_FLAGS);
public static final int NON_MARSHABLE_ACTIVITY_FLAGS = ActivityFlags.REQUEST_ENDED_CALLBACK;//.NO_FLAGS;
public static final int MARSHABLE_ACTIVITY_FLAGS = ActivityFlags.setSleeMayMarshal(NON_MARSHABLE_ACTIVITY_FLAGS);
public SipResourceAdaptor() {
// Those values are default
this.port = 5060;
// this.transport = "udp";
allowedTransports.add("udp");
allowedTransports.add("tcp");
allowedTransports.add("ws");
allowedTransports.add("wss");
transports.add("udp");
// this.stackAddress = "127.0.0.1";
// this.stackPrefix = "gov.nist";
}
// XXX -- SipListenerMethods - here we process incoming data
/*
* (non-Javadoc)
* @see javax.sip.SipListener#processIOException(javax.sip.IOExceptionEvent)
*/
public void processIOException(IOExceptionEvent arg0) {
tracer.severe("processIOException event = "+arg0.toString());
}
/*
* (non-Javadoc)
* @see javax.sip.SipListener#processRequest(javax.sip.RequestEvent)
*/
public void processRequest(RequestEvent req) {
if (tracer.isInfoEnabled()) {
tracer.info("Received Request:\n"+req.getRequest());
}
// get dialog wrapper
final Dialog d = req.getDialog();
final DialogWrapper dw = getDialogWrapper(d);
if (dw != null && req.getServerTransaction() == null) {
if (tracer.isInfoEnabled()) {
tracer.info("No server tx found, for in dialog request, assuming it as retransmission and dropping...");
}
return;
}
if (req.getRequest().getMethod().equals(Request.CANCEL)) {
processCancelRequest(req,dw);
} else {
processNotCancelRequest(req,dw);
}
}
/**
*
* @param req
*/
private void processCancelRequest(RequestEvent req, DialogWrapper dw) {
// get server tx wrapper
ServerTransactionWrapper cancelSTW = null;
SIPServerTransaction cancelST = (SIPServerTransaction) req.getServerTransaction();
if (cancelST == null) {
// server tx not found
try {
cancelST = (SIPServerTransaction)provider.getNewServerTransaction(req.getRequest());
cancelSTW = new ServerTransactionWrapper(cancelST,this);
} catch (Throwable e) {
tracer.severe("Failed to create server tx in provider",e);
return;
}
}
else {
// server tx found
final ServerTransactionWrapperAppData appData = (ServerTransactionWrapperAppData) cancelST.getApplicationData();
if (appData != null) {
cancelSTW = (ServerTransactionWrapper) appData.getTransactionWrapper(cancelST,this);
}
else {
cancelSTW = new ServerTransactionWrapper(cancelST, this);
}
}
// get canceled invite stw
final SIPServerTransaction inviteST = ((SIPServerTransaction)cancelSTW.getWrappedServerTransaction()).getCanceledInviteTransaction();
final ServerTransactionWrapper inviteSTW = (ServerTransactionWrapper) getTransactionWrapper(inviteST);
// get dialog
Wrapper activity = dw;
if (activity == null) {
if (inviteSTW != null) {
activity = inviteSTW;
}
else {
activity = cancelSTW;
cancelSTW.setActivity(true);
addActivity(activity);
}
}
else {
if (inviteSTW != null && inviteSTW.isActivity()) {
// if the invite has a tx activity then use it for the cancel, even if there is already a dialog created by an sbb
activity = inviteSTW;
}
}
if (tracer.isFineEnabled()) {
tracer.fine("Activity selected to fire CANCEL event: " + activity);
}
final CancelRequestEvent REW = new CancelRequestEvent(this.providerWrapper, cancelSTW,
inviteSTW, dw, req.getRequest());
final int eventsFlags = EventFlags.setRequestEventReferenceReleasedCallback(DEFAULT_EVENT_FLAGS);
final FireableEventType eventType = eventIdCache.getEventId(eventLookupFacility, REW.getRequest(), activity.isDialog());
if (eventIDFilter.filterEvent(eventType)) {
if (tracer.isFineEnabled()) {
tracer.fine("Event " + (eventType == null?"null":eventType.getEventType()) + " filtered");
}
// event filtered
processCancelNotHandled(cancelSTW,req.getRequest());
} else {
try {
fireEvent(activity.getActivityHandle(),eventType,REW,activity.getEventFiringAddress(),eventsFlags);
} catch (Throwable e) {
tracer.severe("Failed to fire event",e);
// event not fired due to error
processCancelNotHandled(cancelSTW,req.getRequest());
}
}
}
protected boolean endActivity(Wrapper activity) {
try {
activity.ending();
if (!inLocalMode() && activity.getActivityHandle().isReplicated()) {
sleeEndpoint.endReplicatedActivity(activity.getActivityHandle());
}
else {
sleeEndpoint.endActivity(activity.getActivityHandle());
}
return true;
} catch (Exception e) {
tracer.severe(e.getMessage(),e);
}
return false;
}
protected void fireEvent(SipActivityHandle handle,FireableEventType eventType,
Object event, Address address, int eventFlags)
throws UnrecognizedActivityHandleException, IllegalEventException,
ActivityIsEndingException, NullPointerException, SLEEException,
FireEventException {
if (!inLocalMode() && handle.isReplicated()) {
sleeEndpoint.fireEventOnReplicatedActivity(handle, eventType, event, address, null, eventFlags);
} else {
sleeEndpoint.fireEvent(handle, eventType,
event, address, null, eventFlags);
}
}
/**
* Retrieves the wrapper associated with a dialog, recreating if needed in a cluster env.
* @param d
* @return
*/
public DialogWrapper getDialogWrapper(Dialog d) {
if (d == null) {
return null;
}
DialogWrapper dw = null;
DialogWrapperAppData dwad = (DialogWrapperAppData) d.getApplicationData();
if (dwad != null) {
dw = dwad.getDialogWrapper(d, this);
}
if (dw == null && !inLocalMode()) {
// may be a replicated dialog that locally has no wrapper yet
DialogWithIdActivityHandle dialogWithIdActivityHandle = new DialogWithIdActivityHandle(d.getDialogId());
if (sleeEndpoint.replicatedActivityExists(dialogWithIdActivityHandle)) {
// if exists recreate wrapper
dw = new DialogWrapper(dialogWithIdActivityHandle,this);
dw.setWrappedDialog(d);
}
else {
// does not exists try without remote tag, may be the master client dialog, which handle has no remote tag
DialogWithoutIdActivityHandle dialogWithoutIdActivityHandle = new DialogWithoutIdActivityHandle(d.getCallId().getCallId(), d.getLocalTag());
if (!sleeEndpoint.replicatedActivityExists(dialogWithoutIdActivityHandle)) {
return null;
}
// exists
ClientDialogWrapper cdw = new ClientDialogWrapper(dialogWithoutIdActivityHandle, this);
cdw.setWrappedDialog(d);
dw = cdw;
}
}
return dw;
}
/**
* Retrieves the wrapper associated with a tx, recreating if needed in a cluster env.
* @param t
* @return
*/
public TransactionWrapper getTransactionWrapper(Transaction t) {
if (t == null) {
return null;
}
final TransactionWrapperAppData twad = (TransactionWrapperAppData) t.getApplicationData();
return twad != null ? twad.getTransactionWrapper(t, this) : null;
}
private void processCancelNotHandled(ServerTransactionWrapper cancelSTW, Request request) {
try {
Response response = providerWrapper.getMessageFactory().createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST, request);
// createResponse(..) method does not generate a To header tag
ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);
if (toHeader.getTag() == null) {
toHeader.setTag(Utils.getInstance().generateTag());
}
cancelSTW.getWrappedServerTransaction().sendResponse(response);
} catch (Throwable e) {
tracer.severe("Failed to reply to cancel not handled", e);
try {
cancelSTW.terminate();
} catch (ObjectInUseException f) {
tracer.severe("failed to terminate server tx", f);
}
processTransactionTerminated(cancelSTW);
}
// we may need to delete it manually, since the stack does not do it for early server dialogs
final Dialog d = cancelSTW.getDialog();
if (d != null) {
d.delete();
}
}
/**
*
* @param req
* @param dw
*/
private void processNotCancelRequest(RequestEvent req, DialogWrapper dw) {
// get server tx wrapper
ServerTransactionWrapper stw = null;
if (req.getServerTransaction() == null) {
// server tx not found
if (!req.getRequest().getMethod().equals(Request.ACK)) {
try {
stw = new ServerTransactionWrapper((SIPServerTransaction)provider.getNewServerTransaction(req.getRequest()),this);
} catch (Throwable e) {
if(tracer.isFineEnabled()) {
tracer.fine("Failed to create server tx in provider",e);
}
return;
}
}
else {
// create fake ack server transaction
stw = new ServerTransactionWrapper(new ACKDummyTransaction(req.getRequest()),this);
if (tracer.isFineEnabled()) {
tracer.fine("New ACK server transaction "+stw);
}
}
}
else {
// server tx found
final SIPServerTransaction st = (SIPServerTransaction) req.getServerTransaction();
final ServerTransactionWrapperAppData appData = (ServerTransactionWrapperAppData) st.getApplicationData();
if (appData != null) {
stw = (ServerTransactionWrapper) appData.getTransactionWrapper(st, this);
}
else {
stw = new ServerTransactionWrapper(st, this);
}
}
Wrapper activity = dw;
if (activity == null) {
activity = stw;
stw.setActivity(true);
addActivity(activity);
}
int eventFlags = DEFAULT_EVENT_FLAGS;
if (stw.isAckTransaction()) {
// dummy ack txs are not terminated by stack, so we need to rely on the event release callback
eventFlags = UNREFERENCED_EVENT_FLAGS;
}
final FireableEventType eventType = eventIdCache.getEventId(eventLookupFacility, req.getRequest(), dw != null);
final RequestEventWrapper rew = new RequestEventWrapper(this.providerWrapper,stw,dw,req.getRequest());
if (eventIDFilter.filterEvent(eventType)) {
if (tracer.isFineEnabled()) {
tracer.fine("Event " + (eventType==null?"null":eventType.getEventType()) + " filtered");
}
// event was filtered, let's clean up state
try {
stw.terminate();
} catch (ObjectInUseException e) {
tracer.severe("failed to terminate server tx", e);
}
processTransactionTerminated(stw);
} else {
try {
fireEvent(activity.getActivityHandle(), eventType, rew, activity.getEventFiringAddress(), eventFlags);
} catch (Throwable e) {
// event not fired due to error, let's trace and cleanup state
tracer.severe("Failed to fire event",e);
try {
stw.terminate();
} catch (ObjectInUseException f) {
tracer.severe("failed to terminate server tx", f);
}
processTransactionTerminated(stw);
}
}
}
/*
* (non-Javadoc)
* @see javax.sip.SipListener#processResponse(javax.sip.ResponseEvent)
*/
public void processResponse(ResponseEvent responseEvent) {
final ResponseEventExt responseEventExt = (ResponseEventExt)responseEvent;
if (responseEventExt.isRetransmission() && responseEventExt.getDialog() != null) {
if (tracer.isInfoEnabled()) {
tracer.info("Dropping in dialog retransmission. Response:\n"+responseEventExt.getResponse());
}
return;
}
if(responseEventExt.isForkedResponse()) {
processResponseEventForked(responseEventExt);
}
else {
processResponseEventNotForked(responseEventExt);
}
}
private void processResponseEventNotForked(ResponseEventExt responseEventExt) {
final Response response = responseEventExt.getResponse();
if (tracer.isInfoEnabled()) {
tracer.info("Received Response:\n"+response);
}
ClientTransactionWrapper ctw = null;
final Dialog d = responseEventExt.getDialog();
DialogWrapper dw = getDialogWrapper(d);
if (dw != null && dw.isClientDialog()) {
final ClientDialogWrapper cdw = (ClientDialogWrapper) dw;
if (cdw.getState() == DialogState.EARLY) {
if (!inLocalMode()) {
// ensure the the relation handle -> remote tag is replicated, otherwise it's impossible to get the dialog from stack in another node
if (((ClusteredSipActivityManagement)activityManagement).replicateRemoteTag(dw.getActivityHandle(), d.getRemoteTag())) {
if (tracer.isInfoEnabled()) {
tracer.info("Replicating mapping of outgoing dialog handle "+dw.getActivityHandle()+" to remote tag "+d.getRemoteTag());
}
}
}
}
else if (cdw.getState() == DialogState.CONFIRMED) {
if (!cdw.stopForking(true)) {
if (!cdw.isForkingWinner()) {
if (tracer.isInfoEnabled()) {
tracer.info("Confirmed original dialog "+dw.getDialogId()+", but another related fork dialog already confirmed, sending ack and bye.");
}
processLateDialogFork2xxResponse(response,d);
return;
}
// else do nothing, the master dialog previously confirmed
}
else {
if (tracer.isInfoEnabled()) {
tracer.info("Original dialog "+dw.getDialogId()+" confirmed.");
}
if (!inLocalMode()) {
// ensure the the relation handle -> remote tag is replicated, otherwise it's impossible to get the dialog from stack in another node
if (((ClusteredSipActivityManagement)activityManagement).replicateRemoteTag(dw.getActivityHandle(), d.getRemoteTag())) {
if (tracer.isInfoEnabled()) {
tracer.info("Replicating mapping of outgoing dialog handle "+dw.getActivityHandle()+" to remote tag "+d.getRemoteTag());
}
}
}
}
}
}
SipActivityHandle handle = null;
Address address = null;
FireableEventType eventType = null;
Object event = null;
boolean requestEventUnreferenced = false;
final ClientTransaction ct = responseEventExt.getClientTransaction();
if (ct == null) {
// no client tx
if (!inLocalMode()) {
// ok, it may be a RTR sent to a cluster node after orig node went down
if (dw != null) {
// the dialog exists, thus confirmed, ignore the fact that there is no client tx
event = new ResponseEventWrapper(this.providerWrapper, null, dw, response);
eventType = eventIdCache.getEventId(eventLookupFacility, response);
handle = dw.getActivityHandle();
address = dw.getEventFiringAddress();
}
else {
// no dialog in stack, at most it was a unconfirmed dialog, lets end the related activity if exists
final String localTag = ((FromHeader) response.getHeader(FromHeader.NAME)).getTag();
if (localTag != null) {
// looks suspicious, we have a local tag, maybe it was a unconfirmed dialog, lets try to end the related activity
// first lets search for a fork with full dialog id
final SIPResponse sipResponse = (SIPResponse) response;
final String dialogId = sipResponse.getDialogId(false);
handle = new DialogWithIdActivityHandle(dialogId);
try {
if (sleeEndpoint.replicatedActivityExists(handle)) {
sleeEndpoint.endReplicatedActivity(handle);
}
else {
// ok now we search for an original dialog without id
final String callId = ((CallIdHeader) response.getHeader(CallIdHeader.NAME)).getCallId();
handle = new DialogWithoutIdActivityHandle(callId, localTag);
if (sleeEndpoint.replicatedActivityExists(handle)) {
sleeEndpoint.endReplicatedActivity(handle);
}
}
}
catch (UnrecognizedActivityHandleException e) {
if (tracer.isFineEnabled()) {
tracer.fine("failed to end client tx dialog "+handle+" that was not confirmed, probably from a dead node",e);
}
}
catch (Exception e) {
tracer.severe("failed to end client tx dialog "+handle+" that was not confirmed, probably from a dead node",e);
}
// and ack and bye if it's dialog confirmation
if (isDialogConfirmation(response)) {
processLateDialogFork2xxResponse(response,null);
}
}
else {
if (tracer.isInfoEnabled()) {
tracer.info("Received response not forked, without tx, without dialog, can't proceed, dropping...");
}
}
return;
}
}
else {
// no cluster
if (dw != null) {
// the dialog exists, thus confirmed, ignore the fact that there is no client tx
event = new ResponseEventWrapper(this.providerWrapper, null, dw, response);
eventType = eventIdCache.getEventId(eventLookupFacility, response);
handle = dw.getActivityHandle();
address = dw.getEventFiringAddress();
}
else {
if (tracer.isInfoEnabled()) {
tracer.info("Received response not forked, without tx, without dialog, can't proceed, dropping...");
}
return;
}
}
}
else {
// ct found
ctw = (ClientTransactionWrapper) getTransactionWrapper(ct);
if (ctw == null) {
if (tracer.isInfoEnabled()) {
tracer.info("Dropping response without app data in client tx, probably due to late dialog fork confirmation ack and bye.");
}
return;
}
if (tracer.isFineEnabled()) {
tracer.fine("Received "+response.getStatusCode()+" response on existent client transaction "+ctw.getActivityHandle());
}
// get address where to fire event
address = ctw.getEventFiringAddress();
// determine what is the handle
if (dw != null) {
handle = dw.getActivityHandle();
// (client tx that has a final response and is not an activity must be
// cleared on this callback, not on transaction terminated event)
if (!ctw.isActivity()) {
requestEventUnreferenced = response.getStatusCode() > 199;
}
}
else {
handle = ctw.getActivityHandle();
}
// create event and type
event = new ResponseEventWrapper(this.providerWrapper, ctw, dw, response);
eventType = eventIdCache.getEventId(eventLookupFacility, response);
}
int eventFlags = DEFAULT_EVENT_FLAGS;
if (requestEventUnreferenced) {
eventFlags = UNREFERENCED_EVENT_FLAGS;
}
if (eventIDFilter.filterEvent(eventType)) {
if (tracer.isInfoEnabled()) {
tracer.info("Event " + (eventType == null?"null":eventType.getEventType()) + " filtered");
}
// event filtered
if (requestEventUnreferenced) {
// event was filtered, consider it is unreferenced now
processResponseEventUnreferenced((ResponseEventWrapper)event);
}
} else {
try {
fireEvent(handle, eventType, event, address,eventFlags);
}
catch (UnrecognizedActivityHandleException e) {
tracer.warning("Failed to fire event "+eventType+", the activity "+handle+" does not exists in the SLEE");
} catch (Throwable e) {
tracer.severe("Failed to fire event",e);
// event not fired due to error
if (requestEventUnreferenced) {
// consider event is unreferenced now
processResponseEventUnreferenced((ResponseEventWrapper)event);
}
}
}
}
private void processResponseEventForked(ResponseEventExt responseEventExt) {
if (tracer.isInfoEnabled()) {
tracer.info("Received Forked Dialog Response:\n"+responseEventExt.getResponse());
}
SipActivityHandle handle = null;
FireableEventType eventType = null;
Object event = null;
final Dialog forkedDialog = responseEventExt.getDialog();
DialogWrapper forkedDialogWrapper = getDialogWrapper(forkedDialog);
final DialogState forkedDialogState = forkedDialog.getState();
final SIPClientTransaction originalClientTransaction = (SIPClientTransaction) responseEventExt.getOriginalTransaction();
final Dialog originalDialog = originalClientTransaction.getDefaultDialog();
final ClientDialogWrapper originalDialogWrapper = (ClientDialogWrapper) getDialogWrapper(originalDialog);
if (forkedDialogWrapper == null) {
// new fork
if (forkedDialogState == DialogState.CONFIRMED) {
// confirmed right away
if (originalDialogWrapper.stopForking(false)) {
// and this dialog was the first one participating in this forking that was confirmed
if (tracer.isInfoEnabled()) {
tracer.info("New confirmed dialog fork "+forkedDialog.getDialogId());
}
// add new dialog activity
final DialogWithIdActivityHandle forkedDialogHandle = new DialogWithIdActivityHandle(forkedDialog.getDialogId());
forkedDialogWrapper = new DialogWrapper(forkedDialogHandle, this);
forkedDialogWrapper.setWrappedDialog(forkedDialog);
addActivity(forkedDialogWrapper);
// fire dialog fork event in original dialog activity
handle = originalDialogWrapper.getActivityHandle();
event = new DialogForkedEvent(responseEventExt.getSource(), (ClientTransaction) getTransactionWrapper(originalClientTransaction), originalDialogWrapper, forkedDialogWrapper, responseEventExt.getResponse());
eventType = eventIdCache.getDialogForkEventId(eventLookupFacility);
}
else {
// forking is not allowed anymore
// ack and bye
if (tracer.isInfoEnabled()) {
tracer.info("New confirmed dialog fork "+forkedDialog.getDialogId()+", but forking is not possible anymore, sending ack and bye.");
}
processLateDialogFork2xxResponse(responseEventExt.getResponse(),forkedDialog);
return;
}
}
else if (forkedDialogState == DialogState.EARLY) {
if (originalDialogWrapper.isForkingPossible()) {
if (tracer.isInfoEnabled()) {
tracer.info("New unconfirmed dialog fork "+forkedDialog.getDialogId());
}
// add new dialog activity
final DialogWithIdActivityHandle forkedDialogHandle = new DialogWithIdActivityHandle(forkedDialog.getDialogId());
forkedDialogWrapper = new DialogWrapper(forkedDialogHandle, this);
forkedDialogWrapper.setWrappedDialog(forkedDialog);
addActivity(forkedDialogWrapper);
// fire dialog fork event in original dialog activity
handle = originalDialogWrapper.getActivityHandle();
event = new DialogForkedEvent(responseEventExt.getSource(), (ClientTransaction) getTransactionWrapper(originalClientTransaction), originalDialogWrapper, forkedDialogWrapper, responseEventExt.getResponse());
eventType = eventIdCache.getDialogForkEventId(eventLookupFacility);
}
else {
// forking not allowed anymore
// ignore
if (tracer.isInfoEnabled()) {
tracer.info("New unconfirmed dialog fork "+forkedDialog.getDialogId()+", but forking is not possible anymore, dropping.");
}
return;
}
}
else {
// new forks are not accepted in states other than early or confirmed
if (tracer.isInfoEnabled()) {
tracer.info("New dialog fork "+forkedDialog.getDialogId()+", but state "+forkedDialogState+" does not allows to create forked activity, dropping.");
}
return;
}
}
else {
// existent fork
if (forkedDialogState == DialogState.CONFIRMED) {
if (originalDialogWrapper.stopForking(false)) {
// and this dialog was the first one participating in this forking that was confirmed
if (tracer.isInfoEnabled()) {
tracer.info("Dialog fork "+forkedDialog.getDialogId()+" confirmed.");
}
// fire normal event on forked dialog activity
handle = forkedDialogWrapper.getActivityHandle();
event = new ResponseEventWrapper(responseEventExt.getSource(),(ClientTransaction) getTransactionWrapper(originalClientTransaction),forkedDialogWrapper, responseEventExt.getResponse());
eventType = eventIdCache.getEventId(eventLookupFacility, responseEventExt.getResponse());
}
else {
// lost the forking race
// ack and bye
if (tracer.isInfoEnabled()) {
tracer.info("Dialog fork "+forkedDialog.getDialogId()+" confirmed, but another related fork dialog already confirmed, sending ack and bye.");
}
processLateDialogFork2xxResponse(responseEventExt.getResponse(),forkedDialog);
return;
}
}
else {
// not yet confirmed, fire normal event on forked dialog activity
handle = forkedDialogWrapper.getActivityHandle();
event = new ResponseEventWrapper(responseEventExt.getSource(),(ClientTransaction) getTransactionWrapper(originalClientTransaction),forkedDialogWrapper, responseEventExt.getResponse());
eventType = eventIdCache.getEventId(eventLookupFacility, responseEventExt.getResponse());
}
}
// address is common for both dialogs
final Address address = forkedDialogWrapper.getEventFiringAddress();;
if (eventIDFilter.filterEvent(eventType)) {
if (tracer.isInfoEnabled()) {
tracer.info("Event " + (eventType == null?"null":eventType.getEventType()) + " filtered");
}
} else {
try {
fireEvent(handle, eventType, event, address, DEFAULT_EVENT_FLAGS);
}
catch (UnrecognizedActivityHandleException e) {
tracer.warning("Failed to fire event "+eventType+", the activity "+handle+" does not exists in the SLEE");
}
catch (Throwable e) {
tracer.severe("Failed to fire event",e);
}
}
}
/**
* @param response
* @return
*/
private boolean isDialogConfirmation(Response response) {
final CSeqHeader cSeqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
if (!cSeqHeader.getMethod().equals(Request.INVITE) && !cSeqHeader.getMethod().equals(Request.SUBSCRIBE)) {
// not a dialog creating method
return false;
}
if (cSeqHeader.getSeqNumber() != 1) {
return false;
}
if (response.getStatusCode() < 300 && response.getStatusCode() > 199) {
return true;
}
else {
return false;
}
}
/**
* @param response
*/
private void processLateDialogFork2xxResponse(Response response, Dialog dialog) {
final CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
try {
if (dialog != null) {
Request ack = dialog.createAck(cseq.getSeqNumber());
if (tracer.isInfoEnabled()) {
tracer.info("Sending request:\n"+ack);
}
dialog.sendAck(ack);
Request bye = dialog.createRequest(Request.BYE);
if (tracer.isInfoEnabled()) {
tracer.info("Sending request:\n"+bye);
}
// NOTE: Do not use provider wrapper here, would create activity
ClientTransaction clientTransaction = provider.getNewClientTransaction(bye);
dialog.sendRequest(clientTransaction);
}
else {
final SleeSipProviderImpl provider = getProviderWrapper();
List routeSet = org.mobicents.slee.resource.sip11.Utils.getRouteList(response,provider.getHeaderFactory());
//RFC3261 8.1.1.1
URI requestURI = org.mobicents.slee.resource.sip11.Utils.getRequestUri(response, provider.getAddressFactory());
String branch = ((ViaHeader)response.getHeaders(ViaHeader.NAME).next()).getBranch();
long cseqNumber = cseq.getSeqNumber();
if (requestURI == null) {
tracer.severe("Cannot ack on request that has empty contact!!!!");
return;
}
MaxForwardsHeader mf = provider.getHeaderFactory().createMaxForwardsHeader(70);
List lst = new ArrayList(1);
final ViaHeader localViaHeader = provider.getLocalVia();
localViaHeader.setBranch(branch);
lst.add(localViaHeader);
Request forgedRequest = provider.getMessageFactory().createRequest(requestURI,Request.ACK,(CallIdHeader)response.getHeader(CallIdHeader.NAME),provider.getHeaderFactory().createCSeqHeader(cseqNumber, Request.ACK),
(FromHeader)response.getHeader(FromHeader.NAME) ,(ToHeader)response.getHeader(ToHeader.NAME),lst,mf );
for (Header h : routeSet) {
forgedRequest.addLast(h);
}
if (tracer.isInfoEnabled()) {
tracer.info("Sending request:\n"+forgedRequest);
}
provider.sendRequest(forgedRequest);
lst = new ArrayList();
lst.add(provider.getLocalVia());
requestURI = org.mobicents.slee.resource.sip11.Utils.getRequestUri(response,provider.getAddressFactory());
forgedRequest = provider.getMessageFactory().createRequest(requestURI,Request.BYE,(CallIdHeader)response.getHeader(CallIdHeader.NAME),provider.getHeaderFactory().createCSeqHeader(cseqNumber+1, Request.BYE),
(FromHeader)response.getHeader(FromHeader.NAME) ,(ToHeader)response.getHeader(ToHeader.NAME),lst,mf );
for (Header h : routeSet) {
forgedRequest.addLast(h);
}
// ITS BUG....
((SIPRequest) forgedRequest).setMethod(Request.BYE);
if (tracer.isInfoEnabled()) {
tracer.info("Sending request:\n"+forgedRequest);
}
provider.sendRequest(forgedRequest);
}
// response.get
} catch (Exception e) {
tracer.severe(e.getMessage(),e);
}
}
/*
* (non-Javadoc)
* @see javax.sip.SipListener#processTimeout(javax.sip.TimeoutEvent)
*/
public void processTimeout(TimeoutEvent timeoutEvent) {
final SIPTransaction t;
if (timeoutEvent.isServerTransaction()) {
t = (SIPTransaction) timeoutEvent.getServerTransaction();
}
else {
t = (SIPTransaction) timeoutEvent.getClientTransaction();
}
if (tracer.isInfoEnabled()) {
tracer.info("Transaction "
+ t.getTransactionId()
+ " timer expired");
}
TransactionWrapper tw = getTransactionWrapper(t);
if (tw == null) {
if (tracer.isInfoEnabled()) {
tracer.info("Received timeout event for tx "+t.getTransactionId()+" with null app data, dropping...");
}
return;
}
final TimeoutEventWrapper tew;
if (timeoutEvent.isServerTransaction()) {
tew = new TimeoutEventWrapper(providerWrapper,(ServerTransaction)tw, timeoutEvent.getTimeout());
}
else {
tew = new TimeoutEventWrapper(providerWrapper,(ClientTransaction)tw, timeoutEvent.getTimeout());
}
final Dialog d = t.getDialog();
final DialogWrapper dw = getDialogWrapper(d);
final FireableEventType eventType = eventIdCache.getTransactionTimeoutEventId(
eventLookupFacility, dw != null);
if (!eventIDFilter.filterEvent(eventType)) {
Wrapper activity = tw.isActivity() ? tw : dw;
try {
fireEvent(activity.getActivityHandle(), eventType, tew, activity.getEventFiringAddress(),DEFAULT_EVENT_FLAGS);
}
catch (UnrecognizedActivityHandleException e) {
tracer.warning("Failed to fire event "+eventType+", the activity "+activity+" does not exists in the SLEE");
}
catch (Throwable e) {
tracer.severe("Failed to fire event",e);
}
}
else {
if (tracer.isFineEnabled()) {
tracer.fine("Event "+eventType+" filtered.");
}
}
if (d != null && dw != null && (d.getState() == null || d.getState() == DialogState.TERMINATED)) {
// Issue 98: sip stack won't invoke processDialogTerminate when dialog creating tx times out
processDialogTerminated(dw);
}
}
/*
* (non-Javadoc)
* @see javax.sip.SipListener#processTransactionTerminated(javax.sip.TransactionTerminatedEvent)
*/
public void processTransactionTerminated(
TransactionTerminatedEvent txTerminatedEvent) {
Transaction t = null;
if (txTerminatedEvent.isServerTransaction()) {
t = txTerminatedEvent.getServerTransaction();
}
else {
t = txTerminatedEvent.getClientTransaction();
}
final TransactionWrapper tw = getTransactionWrapper(t);
if (tw != null) {
if (tracer.isInfoEnabled()) {
tracer.info("SIP Transaction "+tw.getActivityHandle()+" terminated");
}
processTransactionTerminated(tw);
}
else {
if (tracer.isInfoEnabled()) {
tracer.info("SIP Transaction "+((SIPTransaction)t).getTransactionId()+" terminated");
}
}
}
private void processTransactionTerminated(TransactionWrapper tw) {
tw.terminated();
if (tw.isActivity()) {
endActivity(tw);
}
else {
if (!tw.isClientTransaction()) {
// client txs which are not activity are cleared on event unreferenced callbacks
tw.clear();
}
}
}
/*
* (non-Javadoc)
* @see javax.sip.SipListener#processDialogTerminated(javax.sip.DialogTerminatedEvent)
*/
public void processDialogTerminated(DialogTerminatedEvent dte) {
final Dialog d = dte.getDialog();
if (d!= null) {
DialogWrapper dw = getDialogWrapper(d);
if (dw != null) {
processDialogTerminated(dw);
} else {
if (tracer.isFineEnabled()) {
tracer.fine("DialogTerminatedEvent dropped due to null app data.");
}
}
}
}
/**
*
* @param dw
*/
public void processDialogTerminated(DialogWrapper dw) {
if (!dw.isEnding()) {
if (tracer.isInfoEnabled()) {
tracer.info("SIP Dialog " + dw.getActivityHandle() + " terminated");
}
if (!endActivity(dw)) {
tracer.warning("Dialog activity that ended not found.");
}
dw.ending();
}
}
/* (non-Javadoc)
* @see gov.nist.javax.sip.SipListenerExt#processDialogTimeout(gov.nist.javax.sip.DialogTimeoutEvent)
*/
public void processDialogTimeout(gov.nist.javax.sip.DialogTimeoutEvent timeoutEvent) {
final Dialog d = timeoutEvent.getDialog();
if (d != null) {
DialogWrapper dw = getDialogWrapper(d);
if (dw != null) {
final FireableEventType eventType = eventIdCache
.getDialogTimeoutEventId(eventLookupFacility);
final DialogTimeoutEvent event = new DialogTimeoutEvent(dw);
if (!eventIDFilter.filterEvent(eventType)) {
try {
fireEvent(dw.getActivityHandle(), eventType, event,
dw.getEventFiringAddress(), DEFAULT_EVENT_FLAGS);
} catch (UnrecognizedActivityHandleException e) {
tracer.warning("Failed to fire event " + eventType +
", the activity " + dw + " does not exists in the SLEE");
} catch (Throwable e) {
tracer.severe("Failed to fire event", e);
}
} else {
if (tracer.isFineEnabled()) {
tracer.fine("Event " + eventType + " filtered.");
}
}
} else {
if (tracer.isFineEnabled()) {
tracer.fine("DialogTimoutEvent dropped due to null app data.");
}
}
}
}
// *************** Event Life cycle
/**
*
* @param wrapperActivity
* @return
*/
public boolean addActivity(Wrapper wrapperActivity) {
if (tracer.isFineEnabled()) {
tracer.fine("Adding sip activity handle " + wrapperActivity.getActivityHandle());
}
final int activityFlags = wrapperActivity.isDialog() ? MARSHABLE_ACTIVITY_FLAGS : NON_MARSHABLE_ACTIVITY_FLAGS;
try {
sleeEndpoint.startActivity(wrapperActivity.getActivityHandle(),wrapperActivity,activityFlags);
}
catch (ActivityAlreadyExistsException e) {
if(tracer.isFineEnabled()) {
tracer.fine("Skipping activity start",e);
}
return true;
}
catch (Throwable e) {
tracer.severe("Failed to start activity",e);
return false;
}
activityManagement.put(wrapperActivity.getActivityHandle(), wrapperActivity);
return true;
}
/**
*
* @param wrapperActivity
* @return
*/
public boolean addSuspendedActivity(Wrapper wrapperActivity) {
if (tracer.isFineEnabled()) {
tracer.fine("Adding suspended sip activity handle " + wrapperActivity.getActivityHandle());
}
final int activityFlags = wrapperActivity.isDialog() ? MARSHABLE_ACTIVITY_FLAGS : NON_MARSHABLE_ACTIVITY_FLAGS;
try {
sleeEndpoint.startActivitySuspended(wrapperActivity.getActivityHandle(),wrapperActivity,activityFlags);
}
catch (ActivityAlreadyExistsException e) {
if(tracer.isFineEnabled()) {
tracer.fine("Skipping activity start",e);
}
return true;
}
catch (Throwable e) {
tracer.severe("Failed to start activity",e);
return false;
}
activityManagement.put(wrapperActivity.getActivityHandle(), wrapperActivity);
return true;
}
// LIFECYLE
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#raActive()
*/
public void raActive() {
try {
final Properties properties = new Properties();
// load properties for the stack
properties.load(getClass().getResourceAsStream("sipra.properties"));
// now load config properties
properties.setProperty(SIP_BIND_ADDRESS, this.stackAddress);
// setting the ra entity name as the stack name
properties.setProperty(STACK_NAME_BIND, raContext.getEntityName());
properties.setProperty(TRANSPORTS_BIND, transportsProperty);
properties.setProperty(SIP_PORT_BIND, Integer.toString(this.port));
if (sipBalancerHeartBeatServiceClassName != null) {
properties.setProperty(LOAD_BALANCER_HEART_BEAT_SERVICE_CLASS, sipBalancerHeartBeatServiceClassName);
}
if (balancers != null) {
properties.setProperty(BALANCERS, balancers);
}
if (loadBalancerElector != null) {
properties.setProperty(LoadBalancerElector.IMPLEMENTATION_CLASS_NAME_PROPERTY, loadBalancerElector);
}
// define impl of the cache of the HA stack
properties.setProperty(ClusteredSipStack.CACHE_CLASS_NAME_PROPERTY,SipResourceAdaptorMobicentsSipCache.class.getName());
this.sipFactory = SipFactory.getInstance();
this.sipFactory.setPathName("org.mobicents.ha");
this.sipStack = (ClusteredSipStack) this.sipFactory.createSipStack(properties);
this.sipStack.start();
if (inLocalMode()) {
activityManagement = new LocalSipActivityManagement();
}
else {
activityManagement = new ClusteredSipActivityManagement(sipStack,ftRaContext.getReplicateData(true),raContext.getSleeTransactionManager(),this);
}
if (tracer.isFineEnabled()) {
tracer
.fine("---> START "
+ Arrays.toString(transports.toArray()));
}
boolean created = false;
for (String trans : transports) {
ListeningPoint lp = this.sipStack.createListeningPoint(
this.stackAddress, this.port, trans);
if (!created) {
this.provider = this.sipStack.createSipProvider(lp);
this.provider.addSipListener(this);
created = true;
} else
this.provider.addListeningPoint(lp);
}
// LETS CREATE FP
// SipFactory sipFactory = SipFactory.getInstance();
AddressFactory addressFactory = sipFactory.createAddressFactory();
HeaderFactory headerFactory = sipFactory.createHeaderFactory();
MessageFactory messageFactory = sipFactory.createMessageFactory();
this.providerWrapper.raActive(addressFactory, headerFactory, messageFactory, sipStack, provider);
} catch (Throwable ex) {
String msg = "error in initializing resource adaptor";
tracer.severe(msg, ex);
throw new RuntimeException(msg,ex);
}
if (tracer.isFineEnabled()) {
tracer.fine("Sip Resource Adaptor entity active.");
}
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#raInactive()
*/
public void raInactive() {
this.provider.removeSipListener(this);
ListeningPoint[] listeningPoints = this.provider.getListeningPoints();
for (int i = 0; i < listeningPoints.length; i++) {
ListeningPoint lp = listeningPoints[i];
for (int k = 0; k < 10; k++) {
try {
this.sipStack.deleteListeningPoint(lp);
this.sipStack.deleteSipProvider(this.provider);
break;
} catch (ObjectInUseException ex) {
tracer
.severe(
"Object in use -- retrying to delete listening point",
ex);
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
}
}
this.providerWrapper.raInactive();
if (tracer.isFineEnabled()) {
tracer.fine("Sip Resource Adaptor entity inactive.");
}
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#raStopping()
*/
public void raStopping() {
if (tracer.isFineEnabled()) {
tracer.fine("Object for entity named "+raContext.getEntityName()+" is stopping. "+activityManagement);
}
}
// EVENT PROCESSING CALLBACKS
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#eventProcessingFailed(javax.slee.resource.ActivityHandle, javax.slee.resource.FireableEventType, java.lang.Object, javax.slee.Address, javax.slee.resource.ReceivableService, int, javax.slee.resource.FailureReason)
*/
public void eventProcessingFailed(ActivityHandle ah, FireableEventType arg1,
Object event, Address arg3, ReceivableService arg4, int arg5, FailureReason arg6) {
if (event.getClass() == CancelRequestEvent.class) {
// PROCESSING FAILED, WE HAVE TO SEND 481 response to CANCEL
try {
Response txDoesNotExistsResponse = this.providerWrapper.getMessageFactory().createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST,
((CancelRequestEvent) event).getRequest());
// createResponse(..) method does not generate a To header tag,
// if there is no tag, we must generate it
ToHeader toHeader = (ToHeader) txDoesNotExistsResponse.getHeader(ToHeader.NAME);
if (toHeader.getTag() == null) {
toHeader.setTag(Utils.getInstance().generateTag());
}
ServerTransactionWrapper stw = (ServerTransactionWrapper) getActivity(ah);
// provider.sendResponse(txDoesNotExistsResponse);
stw.sendResponse(txDoesNotExistsResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#eventProcessingSuccessful(javax.slee.resource.ActivityHandle, javax.slee.resource.FireableEventType, java.lang.Object, javax.slee.Address, javax.slee.resource.ReceivableService, int)
*/
public void eventProcessingSuccessful(ActivityHandle arg0,
FireableEventType arg1, Object arg2, Address arg3,
ReceivableService arg4, int arg5) {
// not used
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#eventUnreferenced(javax.slee.resource.ActivityHandle, javax.slee.resource.FireableEventType, java.lang.Object, javax.slee.Address, javax.slee.resource.ReceivableService, int)
*/
public void eventUnreferenced(ActivityHandle handle, FireableEventType eventType,
Object event, Address arg3, ReceivableService arg4, int arg5) {
if(tracer.isFineEnabled()) {
tracer.fine("Event Unreferenced. Handle = "+handle+", type = "+eventType.getEventType()+", event = "+event);
}
if(event instanceof ResponseEventWrapper) {
final ResponseEventWrapper rew = (ResponseEventWrapper) event;
processResponseEventUnreferenced(rew);
}
else if(event instanceof RequestEventWrapper) {
final RequestEventWrapper rew = (RequestEventWrapper) event;
final ServerTransactionWrapper stw = (ServerTransactionWrapper) rew.getServerTransaction();
if (stw.isAckTransaction()) {
processTransactionTerminated(stw);
}
else {
final Request r = rew.getRequest();
if (r.getMethod().equals(Request.CANCEL)) {
// lets be a good citizen and reply if no sbb has done
if (stw.getState() != TransactionState.TERMINATED) {
processCancelNotHandled(stw,r);
}
}
}
}
}
/**
* @param rew
*/
private void processResponseEventUnreferenced(ResponseEventWrapper rew) {
final ClientTransactionWrapper ctw = (ClientTransactionWrapper) rew
.getClientTransaction();
if (!ctw.isActivity()) {
// a client tx that is not activity must be removed from dialog here
final DialogWrapper dw = ctw.getDialogWrapper();
if (dw != null) {
dw.removeOngoingTransaction(ctw);
} else {
if (tracer.isWarningEnabled()) {
tracer.warning(ctw
+ " not able to remove itself from dialog, dialog reference does not exists");
}
}
ctw.clear();
} else {
// end the activity
endActivity(activityManagement.get(ctw.getActivityHandle()));
}
}
// RA CONFIG
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#raConfigurationUpdate(javax.slee.resource.ConfigProperties)
*/
public void raConfigurationUpdate(ConfigProperties properties) {
raConfigure(properties);
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#raConfigure(javax.slee.resource.ConfigProperties)
*/
public void raConfigure(ConfigProperties properties) {
if (tracer.isFineEnabled()) {
tracer.fine("Configuring RA.");
}
this.port = (Integer) properties.getProperty(SIP_PORT_BIND).getValue();
this.stackAddress = (String) properties.getProperty(SIP_BIND_ADDRESS).getValue();
if (this.stackAddress.equals("")) {
this.stackAddress = System.getProperty("jboss.bind.address");
}
this.balancers = (String) properties.getProperty(BALANCERS).getValue();
if (this.balancers.equals("")) {
this.balancers = null;
}
else {
this.sipBalancerHeartBeatServiceClassName = (String) properties.getProperty(LOAD_BALANCER_HEART_BEAT_SERVICE_CLASS).getValue();
if (this.sipBalancerHeartBeatServiceClassName.equals("")) {
throw new IllegalArgumentException("invalid "+LOAD_BALANCER_HEART_BEAT_SERVICE_CLASS+" property value");
}
}
this.loadBalancerElector = (String) properties.getProperty(LoadBalancerElector.IMPLEMENTATION_CLASS_NAME_PROPERTY).getValue();
if (this.loadBalancerElector.equals("")) {
this.loadBalancerElector = null;
}
this.transportsProperty = (String) properties.getProperty(TRANSPORTS_BIND).getValue();
for (String transport : this.transportsProperty.split(",")) {
this.transports.add(transport);
}
Property p = properties.getProperty(LOOSE_DIALOG_VALIDATION);
if(p!=null && p.getValue()!=null)
{
this.looseDialogSeqValidation = (Boolean) p.getValue();
}
tracer.info("RA entity named "+raContext.getEntityName()+" bound to port " + this.port);
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#raUnconfigure()
*/
public void raUnconfigure() {
this.port = -1;
this.stackAddress = null;
this.transports.clear();
this.balancers = null;
this.loadBalancerElector = null;
this.sipBalancerHeartBeatServiceClassName= null;
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#raVerifyConfiguration(javax.slee.resource.ConfigProperties)
*/
public void raVerifyConfiguration(ConfigProperties properties)
throws InvalidConfigurationException {
try {
// get port
Integer port = (Integer) properties.getProperty(SIP_PORT_BIND).getValue();
// get host
String stackAddress = (String) properties.getProperty(SIP_BIND_ADDRESS).getValue();
if (stackAddress.equals("")) {
stackAddress = System.getProperty("jboss.bind.address");
}
// try to open socket
InetSocketAddress sockAddress = new InetSocketAddress(stackAddress,
port);
new DatagramSocket(sockAddress).close();
// check transports
String transports = (String) properties.getProperty(TRANSPORTS_BIND).getValue();
String[] transportsArray = transports.split(",");
boolean validTransports = true;
if (transportsArray.length > 0) {
for (String transport : transportsArray) {
if (!allowedTransports.contains(transport.toLowerCase()))
validTransports = false;
break;
}
}
else {
validTransports = false;
}
if (!validTransports) {
throw new IllegalArgumentException(TRANSPORTS_BIND+" config property with invalid value: "+transports);
}
// get balancer heart beat class name
String sipBalancerHeartBeatServiceClassName = (String) properties.getProperty(LOAD_BALANCER_HEART_BEAT_SERVICE_CLASS).getValue();
if (!sipBalancerHeartBeatServiceClassName.equals("")) {
// check class is available
Class.forName(sipBalancerHeartBeatServiceClassName);
}
// get balancer elector class name
String sipBalancerElectorClassName = (String) properties.getProperty(LoadBalancerElector.IMPLEMENTATION_CLASS_NAME_PROPERTY).getValue();
if (!sipBalancerElectorClassName.equals("")) {
// check class is available
Class.forName(sipBalancerElectorClassName);
}
}
catch (Throwable e) {
throw new InvalidConfigurationException(e.getMessage(),e);
}
}
// EVENT FILTERING
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#serviceActive(javax.slee.resource.ReceivableService)
*/
public void serviceActive(ReceivableService receivableService) {
eventIDFilter.serviceActive(receivableService);
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#serviceInactive(javax.slee.resource.ReceivableService)
*/
public void serviceInactive(ReceivableService receivableService) {
eventIDFilter.serviceInactive(receivableService);
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#serviceStopping(javax.slee.resource.ReceivableService)
*/
public void serviceStopping(ReceivableService receivableService) {
eventIDFilter.serviceStopping(receivableService);
}
// RA CONTEXT
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#setResourceAdaptorContext(javax.slee.resource.ResourceAdaptorContext)
*/
public void setResourceAdaptorContext(ResourceAdaptorContext raContext) {
this.raContext = raContext;
this.tracer = raContext.getTracer(getClass().getSimpleName());
this.sleeEndpoint = (SleeEndpoint) raContext.getSleeEndpoint();
this.eventLookupFacility = raContext.getEventLookupFacility();
this.providerWrapper = new SleeSipProviderImpl(this);
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#unsetResourceAdaptorContext()
*/
public void unsetResourceAdaptorContext() {
this.raContext = null;
this.sleeEndpoint = null;
this.eventLookupFacility = null;
this.tracer = null;
this.tracer = null;
}
/**
*
* @return
*/
public EventLookupFacility getEventLookupFacility() {
return eventLookupFacility;
}
/**
*
* @return
*/
public SleeEndpoint getSleeEndpoint() {
return sleeEndpoint;
}
/**
*
* @param tracerName
* @return
*/
public Tracer getTracer(String tracerName) {
return raContext.getTracer(tracerName);
}
/**
* @return the activityManagement
*/
public SipActivityManagement getActivityManagement() {
return activityManagement;
}
// ACTIVITY MANAGEMENT
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#activityEnded(javax.slee.resource.ActivityHandle)
*/
public void activityEnded(ActivityHandle activityHandle) {
final Wrapper activity = activityManagement.remove((SipActivityHandle) activityHandle);
if (activity != null) {
activity.clear();
}
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#administrativeRemove(javax.slee.resource.ActivityHandle)
*/
public void administrativeRemove(ActivityHandle activityHandle) {
// TODO
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#activityUnreferenced(javax.slee.resource.ActivityHandle)
*/
public void activityUnreferenced(ActivityHandle arg0) {
// not used
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#getActivity(javax.slee.resource.ActivityHandle)
*/
public Object getActivity(ActivityHandle arg0) {
return activityManagement.get((SipActivityHandle)arg0);
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#getActivityHandle(java.lang.Object)
*/
public ActivityHandle getActivityHandle(Object activity) {
if (activity instanceof Wrapper) {
final Wrapper w = (Wrapper) activity;
if (w.getRa() == this) {
return w.getActivityHandle();
}
}
return null;
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#queryLiveness(javax.slee.resource.ActivityHandle)
*/
public void queryLiveness(ActivityHandle arg0) {
final SipActivityHandle handle = (SipActivityHandle) arg0;
final Wrapper activity = activityManagement.get(handle);
if (activity == null || activity.isEnding()) {
if (!inLocalMode() && handle.isReplicated()) {
sleeEndpoint.endReplicatedActivity(handle);
} else {
sleeEndpoint.endActivity(handle);
}
}
}
// OTHER GETTERS
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#getResourceAdaptorInterface(java.lang.String)
*/
public Object getResourceAdaptorInterface(String raTypeSbbInterfaceclassName) {
// this ra implements a single ra type
return providerWrapper;
}
/*
* (non-Javadoc)
* @see javax.slee.resource.ResourceAdaptor#getMarshaler()
*/
public Marshaler getMarshaler() {
return marshaler;
}
public SleeSipProviderImpl getProviderWrapper() {
return providerWrapper;
}
/**
* @return the eventIdCache
*/
public EventIDCache getEventIdCache() {
return eventIdCache;
}
/**
* @return the eventIDFilter
*/
public EventIDFilter getEventIDFilter() {
return eventIDFilter;
}
/**
*
* @return true if jsip dialog should not validate cseq.
*/
public boolean disableSequenceNumberValidation() {
return looseDialogSeqValidation;
}
// CLUSTERING
/**
* Indicates if the RA is running in local mode or in a clustered environment
* @return true if the RA is running in local mode, false if is running in a clustered environment
*/
public boolean inLocalMode() {
return sipStack.getSipCache().inLocalMode();
}
/*
* (non-Javadoc)
* @see org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor#dataRemoved(java.io.Serializable)
*/
public void dataRemoved(SipActivityHandle handle) {
// if we get this callback ensure the handle is removed from activity management, or a leak could occurr
// if the handle was used locally but removed remotely
activityManagement.remove(handle);
}
/*
* (non-Javadoc)
* @see org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor#failOver(java.io.Serializable)
*/
public void failOver(SipActivityHandle activityHandle) {
// not used
}
private FaultTolerantResourceAdaptorContext ftRaContext;
public void setFaultTolerantResourceAdaptorContext(
FaultTolerantResourceAdaptorContext context) {
this.ftRaContext = context;
}
public void unsetFaultTolerantResourceAdaptorContext() {
this.ftRaContext = null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy