package org.mobicents.mgcp.stack;
import jain.protocol.ip.mgcp.JainMgcpCommandEvent;
import jain.protocol.ip.mgcp.JainMgcpEvent;
import jain.protocol.ip.mgcp.JainMgcpListener;
import jain.protocol.ip.mgcp.JainMgcpProvider;
import jain.protocol.ip.mgcp.JainMgcpResponseEvent;
import jain.protocol.ip.mgcp.JainMgcpStack;
import jain.protocol.ip.mgcp.message.AuditConnectionResponse;
import jain.protocol.ip.mgcp.message.AuditEndpointResponse;
import jain.protocol.ip.mgcp.message.Constants;
import jain.protocol.ip.mgcp.message.CreateConnection;
import jain.protocol.ip.mgcp.message.CreateConnectionResponse;
import jain.protocol.ip.mgcp.message.DeleteConnectionResponse;
import jain.protocol.ip.mgcp.message.ModifyConnectionResponse;
import jain.protocol.ip.mgcp.message.NotificationRequestResponse;
import jain.protocol.ip.mgcp.message.Notify;
import jain.protocol.ip.mgcp.message.NotifyResponse;
import jain.protocol.ip.mgcp.message.RestartInProgressResponse;
import jain.protocol.ip.mgcp.message.parms.CallIdentifier;
import jain.protocol.ip.mgcp.message.parms.ConnectionIdentifier;
import jain.protocol.ip.mgcp.message.parms.NotifiedEntity;
import jain.protocol.ip.mgcp.message.parms.RequestIdentifier;
import jain.protocol.ip.mgcp.message.parms.ReturnCode;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TooManyListenersException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.log4j.Logger;
public class JainMgcpStackProviderImpl implements JainMgcpProvider {
private static Logger logger = Logger.getLogger(JainMgcpStackProviderImpl.class);
private final JainMgcpStackImpl runningStack;
// a tx handle id must be between 1 and 999999999
private static int MIN_TRANSACTION_HANDLE_ID = 1;
private static int MAX_TRANSACTION_HANDLE_ID = Integer.MAX_VALUE < 999999999 ? Integer.MAX_VALUE : 999999999;
private static AtomicInteger transactionHandleCounter = new AtomicInteger(MIN_TRANSACTION_HANDLE_ID);
private static AtomicLong callIdentifierCounter = new AtomicLong(1);
private static AtomicLong requestIdentifierCounter = new AtomicLong(1);
// For now provider is only holder of listeners
protected Set<JainMgcpListener> jainListeners = new HashSet<JainMgcpListener>();
// This set contains upgraded listeners - one that allow to notify when tx
// ends
protected Set<JainMgcpExtendedListener> jainMobicentsListeners = new HashSet<JainMgcpExtendedListener>();
protected NotifiedEntity notifiedEntity = null;
public JainMgcpStackProviderImpl(JainMgcpStackImpl runningStack) {
super();
//eventQueue = new QueuedExecutor();
//pool = Executors.newCachedThreadPool(new ThreadFactoryImpl());
this.runningStack = runningStack;
}
public void setNotifiedEntity(NotifiedEntity notifiedEntity){
this.notifiedEntity = notifiedEntity;
}
public NotifiedEntity getNotifiedEntity(){
return this.notifiedEntity;
}
public void addJainMgcpListener(JainMgcpListener listener) throws TooManyListenersException {
if (listener instanceof JainMgcpExtendedListener) {
synchronized (this.jainMobicentsListeners) {
this.jainMobicentsListeners.add((JainMgcpExtendedListener) listener);
}
} else {
synchronized (this.jainListeners) {
this.jainListeners.add(listener);
}
}
}
public JainMgcpStack getJainMgcpStack() {
return this.runningStack;
}
public void removeJainMgcpListener(JainMgcpListener listener) {
if (listener instanceof JainMgcpExtendedListener) {
synchronized (this.jainMobicentsListeners) {
this.jainMobicentsListeners.remove((JainMgcpExtendedListener) listener);
}
} else {
synchronized (this.jainListeners) {
this.jainListeners.remove(listener);
}
}
}
public synchronized void sendMgcpEvents(JainMgcpEvent[] events) throws IllegalArgumentException {
for (JainMgcpEvent event : events) {
//For any onther than CRCX wildcard does not count?
boolean isWildcarded=false;
if (event instanceof JainMgcpCommandEvent) {
// SENDING REQUEST
JainMgcpCommandEvent commandEvent = (JainMgcpCommandEvent) event;
//This is for TCK
if(commandEvent.getTransactionHandle() < 1){
commandEvent.setTransactionHandle(this.getUniqueTransactionHandler());
}
TransactionHandler handle = null;
switch (commandEvent.getObjectIdentifier()) {
case Constants.CMD_AUDIT_CONNECTION:
if (logger.isDebugEnabled()) {
logger.debug("Sending EndpointConfiguration object to " + commandEvent.getEndpointIdentifier());
}
handle = new AuditConnectionHandler(this.runningStack);
break;
case Constants.CMD_AUDIT_ENDPOINT:
if (logger.isDebugEnabled()) {
logger.debug("Sending EndpointConfiguration object to " + commandEvent.getEndpointIdentifier());
}
handle = new AuditEndpointHandler(this.runningStack);
break;
case Constants.CMD_CREATE_CONNECTION:
if (logger.isDebugEnabled()) {
logger.debug("Sending CreateConnection object to " + commandEvent.getEndpointIdentifier());
}
handle = new CreateConnectionHandler(this.runningStack);
CreateConnection crcx=(CreateConnection) event;
isWildcarded=EndpointHandler.isAnyOfWildcard(crcx.getEndpointIdentifier().toString());
break;
case Constants.CMD_DELETE_CONNECTION:
if (logger.isDebugEnabled()) {
logger.debug("Sending DeleteConnection object to " + commandEvent.getEndpointIdentifier());
}
handle = new DeleteConnectionHandler(this.runningStack);
break;
case Constants.CMD_ENDPOINT_CONFIGURATION:
if (logger.isDebugEnabled()) {
logger.debug("Sending EndpointConfiguration object to " + commandEvent.getEndpointIdentifier());
}
handle = new EndpointConfigurationHandler(this.runningStack);
break;
case Constants.CMD_MODIFY_CONNECTION:
if (logger.isDebugEnabled()) {
logger.debug("Sending ModifyConnection object to " + commandEvent.getEndpointIdentifier());
}
handle = new ModifyConnectionHandler(this.runningStack);
break;
case Constants.CMD_NOTIFICATION_REQUEST:
if (logger.isDebugEnabled()) {
logger.debug("Sending NotificationRequest object to " + commandEvent.getEndpointIdentifier());
}
handle = new NotificationRequestHandler(this.runningStack);
break;
case Constants.CMD_NOTIFY:
if (logger.isDebugEnabled()) {
logger.debug("Sending Notify object to NotifiedEntity"
+ ((Notify) commandEvent).getNotifiedEntity());
}
handle = new NotifyHandler(this.runningStack);
break;
case Constants.CMD_RESP_UNKNOWN:
if (logger.isDebugEnabled()) {
logger.debug("Sending ResponseUnknown object to " + commandEvent.getEndpointIdentifier());
}
handle = new RespUnknownHandler(this.runningStack);
break;
case Constants.CMD_RESTART_IN_PROGRESS:
if (logger.isDebugEnabled()) {
logger.debug("Sending RestartInProgress object to " + commandEvent.getEndpointIdentifier());
}
handle = new RestartInProgressHandler(this.runningStack);
break;
default:
throw new IllegalArgumentException("Could not send type of the message yet");
}
handle.setCommand(true);
handle.setCommandEvent(commandEvent);
EndpointHandler eh=this.runningStack.getEndpointHandler(handle.getEndpointId(),isWildcarded);
eh.addTransactionHandler(handle);
eh.scheduleTransactionHandler(handle);
//try {
// eventQueue.execute(handle);
//} catch (InterruptedException e) {
// logger.error("Error when sending the Comand "+commandEvent, e);
//}
// handle.send(commandEvent);
} else {
// SENDING RESPONSE
int tid = event.getTransactionHandle();
TransactionHandler handler = (TransactionHandler) runningStack.getLocalTransactions().get(Integer
//XXX:TransactionHandler handler = (TransactionHandler) runningStack.getLocalTransaction(Integer
.valueOf(tid));
if (handler != null) {
handler.setCommand(false);
handler.setResponseEvent((JainMgcpResponseEvent) event);
//try {
// eventQueue.execute(handler);
//} catch (InterruptedException e) {
// logger.error("Error when sending the Response "+event, e);
//}
EndpointHandler eh=handler.getEndpointHandler();
eh.scheduleTransactionHandler(handler);
} else {
logger.error("The TransactionHandler not found for TransactionHandle " + tid
+ " May be the Tx timed out. Event = " + (JainMgcpResponseEvent) event);
}
// send event
// handler.send((JainMgcpResponseEvent) event);
}
}
}
public int getUniqueTransactionHandler() {
// retreives current counter value and sets next one
int current;
int next;
do {
current = transactionHandleCounter.get();
next = (current == MAX_TRANSACTION_HANDLE_ID ? MIN_TRANSACTION_HANDLE_ID : current + 1);
} while (!transactionHandleCounter.compareAndSet(current, next));
return current;
}
public void processMgcpResponseEvent(JainMgcpResponseEvent response, JainMgcpEvent command) {
// ra.processMgcpResponseEvent(response, command);
synchronized (this.jainListeners) {
for (JainMgcpListener listener : this.jainListeners) {
listener.processMgcpResponseEvent(response);
}
}
synchronized (this.jainMobicentsListeners) {
for (JainMgcpListener listener : this.jainMobicentsListeners) {
listener.processMgcpResponseEvent(response);
}
}
}
public void processMgcpCommandEvent(JainMgcpCommandEvent command) {
// ra.processMgcpCommandEvent(command);
synchronized (this.jainListeners) {
for (JainMgcpListener listener : this.jainListeners) {
listener.processMgcpCommandEvent(command);
}
}
synchronized (this.jainMobicentsListeners) {
for (JainMgcpListener listener : this.jainMobicentsListeners) {
listener.processMgcpCommandEvent(command);
}
}
}
public void processTxTimeout(JainMgcpCommandEvent command) {
// notify RA
// ra.processTxTimeout(command);
synchronized (this.jainMobicentsListeners) {
for (JainMgcpExtendedListener listener : this.jainMobicentsListeners) {
listener.transactionTxTimedOut(command);
}
}
}
public void processRxTimeout(JainMgcpCommandEvent command) {
// notify RA
// ra.processRxTimeout(command);
synchronized (this.jainMobicentsListeners) {
for (JainMgcpExtendedListener listener : this.jainMobicentsListeners) {
listener.transactionRxTimedOut(command);
}
}
// reply to server
JainMgcpResponseEvent response = null;
// FIXME - how to change o return code of transaction timeout?!?
switch (command.getObjectIdentifier()) {
case Constants.CMD_AUDIT_CONNECTION:
response = new AuditConnectionResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_AUDIT_ENDPOINT:
response = new AuditEndpointResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_CREATE_CONNECTION:
response = new CreateConnectionResponse(this, ReturnCode.Transient_Error, new ConnectionIdentifier(Long
.toHexString(new Random(System.currentTimeMillis()).nextLong())));
break;
case Constants.CMD_DELETE_CONNECTION:
response = new DeleteConnectionResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_ENDPOINT_CONFIGURATION:
response = new DeleteConnectionResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_MODIFY_CONNECTION:
response = new ModifyConnectionResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_NOTIFICATION_REQUEST:
response = new NotificationRequestResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_NOTIFY:
response = new NotifyResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_RESP_UNKNOWN:
// FIXME - what response?!?
response = new NotifyResponse(this, ReturnCode.Transient_Error);
break;
case Constants.CMD_RESTART_IN_PROGRESS:
response = new RestartInProgressResponse(this, ReturnCode.Transient_Error);
break;
default:
throw new IllegalArgumentException("Could not send type of the message yet");
}
response.setTransactionHandle(command.getTransactionHandle());
JainMgcpEvent[] events = { response };
sendMgcpEvents(events);
}
public CallIdentifier getUniqueCallIdentifier() {
long current = -1;
boolean b = true;
while (b) {
current = callIdentifierCounter.get();
if (current == Long.MAX_VALUE) {
b = !callIdentifierCounter.compareAndSet(current, 1);
} else {
b = !callIdentifierCounter.compareAndSet(current, current + 1);
}
}
return new CallIdentifier(Long.toHexString(current));
}
public RequestIdentifier getUniqueRequestIdentifier() {
long current = -1;
boolean b = true;
while (b) {
current = requestIdentifierCounter.get();
if (current == Long.MAX_VALUE) {
b = !requestIdentifierCounter.compareAndSet(current, 1);
} else {
b = !requestIdentifierCounter.compareAndSet(current, current + 1);
}
}
return new RequestIdentifier(Long.toHexString(current));
}
}