com.devoteam.srit.xmlloader.sip.StackSipCommon.java Source code

Java tutorial

Introduction

Here is the source code for com.devoteam.srit.xmlloader.sip.StackSipCommon.java

Source

/* 
 * Copyright 2012 Devoteam http://www.devoteam.com
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * 
 * This file is part of Multi-Protocol Test Suite (MTS).
 * 
 * Multi-Protocol Test Suite (MTS) is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, either version 3 of the
 * License.
 * 
 * Multi-Protocol Test Suite (MTS) 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Multi-Protocol Test Suite (MTS).
 * If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package com.devoteam.srit.xmlloader.sip;

import java.io.InputStream;

import org.dom4j.Element;

import com.devoteam.srit.xmlloader.core.utils.Utils;
import com.devoteam.srit.xmlloader.core.Runner;
import com.devoteam.srit.xmlloader.core.ScenarioRunner;
import com.devoteam.srit.xmlloader.core.Tester;
import com.devoteam.srit.xmlloader.core.log.GlobalLogger;
import com.devoteam.srit.xmlloader.core.log.TextEvent;
import com.devoteam.srit.xmlloader.core.protocol.Listenpoint;
import com.devoteam.srit.xmlloader.core.protocol.Msg;
import com.devoteam.srit.xmlloader.core.protocol.Stack;
import com.devoteam.srit.xmlloader.core.protocol.StackFactory;
import com.devoteam.srit.xmlloader.core.protocol.Trans;
import com.devoteam.srit.xmlloader.core.protocol.TransactionId;
import com.devoteam.srit.xmlloader.core.utils.Config;
import com.devoteam.srit.xmlloader.core.utils.expireshashmap.ExpireHashMap;
import com.devoteam.srit.xmlloader.core.coding.text.TextMessage;
import com.devoteam.srit.xmlloader.core.exception.ExecutionException;

/**
 *
 * @author gpasquiers
 */
public abstract class StackSipCommon extends Stack {

    private ExpireHashMap<TransactionId, Trans> outTransactionsResponse;
    private ExpireHashMap<TransactionId, Trans> inTransactionsResponse;

    /**
     * Config parameter
     * bug NSN equipment : add a CRLF at the end of the Content
     */
    public int addCRLFContent = 0;

    /** Creates a new instance */
    public StackSipCommon() throws Exception {
        super();

        this.outTransactionsResponse = new ExpireHashMap<TransactionId, Trans>("outTransactionsResponse",
                this.msgLifeTime);
        this.inTransactionsResponse = new ExpireHashMap<TransactionId, Trans>("inTransactionsResponse",
                this.msgLifeTime);

        DefaultRouter.resetInstance();

        if (getConfig().getBoolean("nsn.ADD_CRLF_CONTENT", false)) {
            this.addCRLFContent++;
        }
    }

    /** Creates a specific SIP Msg */
    @Override
    public Msg parseMsgFromXml(Boolean request, Element root, Runner runner) throws Exception {
        MsgSipCommon msgSip = (MsgSipCommon) super.parseMsgFromXml(request, root, runner);

        // DEPRECATED begin        
        String listenpointName = root.attributeValue("providerName");
        if (listenpointName != null) {
            Listenpoint listenpoint = getListenpoint(listenpointName);
            if (listenpoint == null && listenpointName != null) {
                throw new ExecutionException("The listenpoint <name=" + listenpointName + "> does not exist");
            }
            msgSip.setListenpoint(listenpoint);
        }
        if (request != null && request && !msgSip.isRequest()) {
            throw new ExecutionException(
                    "You specify to send a request using a <sendRequestXXX ...> tag, but the message you will send is not really a request.");
        }
        if (request != null && !request && msgSip.isRequest()) {
            throw new ExecutionException(
                    "You specify to send a response using a <sendResponseXXX ...> tag, but the message you will send is not really a response.");
        }
        // DEPRECATED end

        return msgSip;
    }

    /** Send the message from the given scenario */
    @Override
    public synchronized boolean sendMessageException(Msg msg, ScenarioRunner srcRunner, ScenarioRunner destRunner,
            ScenarioRunner answerHandler) throws Exception {
        // is the message a retransmission ?
        boolean isRetransmission = false;
        if (msg.getRetransmissionId() != null) {
            if (!msg.isRequest()) {
                isRetransmission = outRetransResponses.get(msg.getRetransmissionId()) != null;
            } else {
                isRetransmission = outRetransRequests.get(msg.getRetransmissionId()) != null;
            }
        }

        // is the message part of an inverted transaction ?
        MsgSipCommon msgSip = (MsgSipCommon) msg;
        boolean isInvertedTransaction = true;
        TransactionId responseTransactionId = msgSip.getResponseTransactionId();
        if (null == responseTransactionId) {
            isInvertedTransaction = false;
            GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL,
                    "StackSip: responseTransactionId is null, nothing to do.");
        }

        // do things, if we have to
        if (!isRetransmission && isInvertedTransaction) {
            // Create a new Transaction in order to do timer-based restransmitions.
            // This transaction will have a response as a "begin message" ex:180 INVITE, 183 INVITE, 200 INVITE.
            if (!msg.isRequest()) {
                if (msg.shallBeRetransmitted()) {
                    // add the transaction into the list
                    Trans transaction = new Trans(this, msg);
                    transaction.setScenarioRunner(srcRunner);
                    GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL,
                            "StackSip: create client transaction (for retrans) ", responseTransactionId,
                            " with begin message: \n", msg);
                    outTransactionsResponse.put(responseTransactionId, transaction);
                    // send the retransmission
                    if (retransmitManagement) {
                        transaction.startAutomaticRetransmit();
                    }
                }
            }
            // Add the Request to it's transaction. That way, when receiving a retransmission
            // of the begin message of that transaction we will retransmit this request as well.
            else {
                Trans transaction = this.inTransactionsResponse.get(msgSip.getResponseTransactionId());
                if (transaction != null) {
                    GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL,
                            "StackSip: add entry to server transaction (for retrans) ", responseTransactionId,
                            ": \n", msg);
                    transaction.addEndMessage(msg);
                } else {
                    GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL,
                            "StackSip: could not add message to any server transaction ", responseTransactionId,
                            " (for retrans) : \n", msg);
                }
            }
        }

        // then really then the message
        super.sendMessageException(msg, srcRunner, destRunner, answerHandler);
        return true;
    }

    /** Receive a message */
    @Override
    public boolean doReceiveMessage(Msg msg) throws Exception {
        // is the message a retransmission ?
        boolean isRetransmission = false;
        if (msg.getRetransmissionId() != null) {
            if (!msg.isRequest()) {
                isRetransmission = inRetransResponses.get(msg.getRetransmissionId()) != null;
            } else {
                isRetransmission = inRetransRequests.get(msg.getRetransmissionId()) != null;
            }
        }

        // is the message part of an inverted transaction ?
        MsgSipCommon msgSip = (MsgSipCommon) msg;
        boolean isInvertedTransaction = true;
        TransactionId responseTransactionId = msgSip.getResponseTransactionId();
        if (null == responseTransactionId) {
            isInvertedTransaction = false;
            GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL,
                    "StackSip: responseTransactionId is null, nothing to do.");
        }

        // do things, if we have to
        if (isInvertedTransaction) {
            if (!msg.isRequest()) {
                // Reception of a response retransmission :
                //  - if not a retransmission : create a new transaction.
                //  - if is a retransmission : get the transaction and retransmit the subsequent messages.
                if (msg.shallBeRetransmitted()) {
                    // add the transaction into the list
                    if (isRetransmission) {
                        Trans transaction = this.inTransactionsResponse.get(responseTransactionId);

                        if (retransmitManagement) {
                            if (transaction != null) {
                                transaction.retransmitAutomaticResponses();
                            } else {
                                GlobalLogger.instance().getApplicationLogger().warn(TextEvent.Topic.PROTOCOL,
                                        "StackSip: could not do automatic retransmissions for response transaction ",
                                        responseTransactionId, " of message:\n", msg);
                            }
                        }
                    } else {
                        GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL,
                                "StackSip: create server transaction (for retrans) ", responseTransactionId,
                                " with begin message: \n", msg);
                        Trans transaction = new Trans(this, msg);
                        this.inTransactionsResponse.put(responseTransactionId, transaction);
                    }
                }
            } else {
                // Reception of a non-retransmitted request (ACK, CANCEL, PRACK) :
                //  - Add the request to the transaction in order to stop the timer
                //    based retransmissions of the associated response.
                Trans transaction = this.outTransactionsResponse.get(responseTransactionId);
                if (transaction != null) {
                    GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL,
                            "StackSip: add entry to client transaction (for retrans) ", responseTransactionId,
                            " : \n", msg);
                    transaction.addEndMessage(msg);
                } else {
                    GlobalLogger.instance().getApplicationLogger().warn(TextEvent.Topic.PROTOCOL,
                            "StackSip: could not add message to any client transaction ", responseTransactionId,
                            " (for retrans) : \n", msg);
                }
            }
        }

        super.doReceiveMessage(msg);

        return true;
    }

    /** 
     * Returns the Config object to access the protocol config file 
     */
    @Override
    public Config getConfig() throws Exception {
        return Config.getConfigByName("sip.properties");
    }

    protected String reader(InputStream inputStream) throws Exception {
        StringBuilder message = new StringBuilder();

        String line = "new line";
        boolean begin = false;
        int lengthContent = 0;
        while (line.length() > 0) {
            line = Utils.readLineFromInputStream(inputStream).trim();
            if (!begin && line.contains(StackFactory.PROTOCOL_SIP)) {
                message = new StringBuilder();
                begin = true;
            }
            String length = TextMessage.getHeaderValue("\r\n" + line.toLowerCase(), "content-length");
            if (length == null) {
                length = TextMessage.getHeaderValue("\r\n" + line.toLowerCase(), "l");
            }
            if (length != null) {
                try {
                    lengthContent = Integer.valueOf(length);
                } catch (Exception e) {
                    lengthContent = 0;
                }
            }
            message.append(line).append("\r\n");
        }
        Tester.getGlobalLogger().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL, "lengthContent = ",
                lengthContent);
        if (lengthContent <= 0) {
            return message.toString();
        }

        byte[] tab = new byte[lengthContent];
        int done = Utils.readFromSocketStream(inputStream, tab);
        message.append(new String(tab, 0, done));
        return message.toString();
    }

    /*
     * Remove eldest entry if instructed, else grow capacity if appropriate
     * in all stack lists
     */
    @Override
    public void cleanStackLists() {
        super.cleanStackLists();
        this.outTransactionsResponse.cleanEldestEntries();
        this.inTransactionsResponse.cleanEldestEntries();
    }

}