<commit_before>package org.jsmpp.session;

import java.io.IOException;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import org.jsmpp.InvalidResponseException;
import org.jsmpp.PDUSender;
import org.jsmpp.PDUStringException;
import org.jsmpp.SMPPConstant;
import org.jsmpp.bean.Command;
import org.jsmpp.bean.DataCoding;
import org.jsmpp.bean.DataSm;
import org.jsmpp.bean.DataSmResp;
import org.jsmpp.bean.ESMClass;
import org.jsmpp.bean.NumberingPlanIndicator;
import org.jsmpp.bean.OptionalParameter;
import org.jsmpp.bean.RegisteredDelivery;
import org.jsmpp.bean.TypeOfNumber;
import org.jsmpp.extra.NegativeResponseException;
import org.jsmpp.extra.PendingResponse;
import org.jsmpp.extra.ProcessRequestException;
import org.jsmpp.extra.ResponseTimeoutException;
import org.jsmpp.extra.SessionState;
import org.jsmpp.session.connection.Connection;
import org.jsmpp.util.IntUtil;
import org.jsmpp.util.Sequence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author uudashr
 *
 */
public abstract class AbstractSession implements Session {
    private static final Logger logger = LoggerFactory.getLogger(AbstractSession.class);
    private static final Random random = new Random();
    
    private final Map<Integer, PendingResponse<Command>> pendingResponse = new ConcurrentHashMap<Integer, PendingResponse<Command>>();
    private final Sequence sequence = new Sequence(1);
    private final PDUSender pduSender;
    private int pduProcessorDegree = 3;
    
    private String sessionId = generateSessionId();
    private int enquireLinkTimer = 5000;
    private long transactionTimer = 2000;
    
    public AbstractSession(PDUSender pduSender) {
        this.pduSender = pduSender;
    }
    
    protected abstract AbstractSessionContext sessionContext();
    protected abstract Connection connection();
    protected abstract GenericMessageReceiverListener messageReceiverListener();
    
    protected PDUSender pduSender() {
        return pduSender;
    }
    
    protected Sequence sequence() {
        return sequence;
    }
    
    protected PendingResponse<Command> removePendingResponse(int sequenceNumber) {
        return pendingResponse.remove(sequenceNumber);
    }
    
    public String getSessionId() {
        return sessionId;
    }
    
    public void setEnquireLinkTimer(int enquireLinkTimer) {
        if (sessionContext().getSessionState().isBound()) {
            try {
                connection().setSoTimeout(enquireLinkTimer);
            } catch (IOException e) {
                logger.error("Failed setting so_timeout for session timer", e);
            }
        }
        this.enquireLinkTimer = enquireLinkTimer;
    }
    
    public int getEnquireLinkTimer() {
        return enquireLinkTimer;
    }
    
    public void setTransactionTimer(long transactionTimer) {
        this.transactionTimer = transactionTimer;
    }
    
    public long getTransactionTimer() {
        return transactionTimer;
    }
    
    public SessionState getSessionState() {
        return sessionContext().getSessionState();
    }
    
    public void addSessionStateListener(SessionStateListener l) {
        sessionContext().addSessionStateListener(l);
    }
    
    public void removeSessionStateListener(SessionStateListener l) {
        sessionContext().removeSessionStateListener(l);
    }
    
    public long getLastActivityTimestamp() {
        return sessionContext().getLastActivityTimestamp();
    }
    
    /**
     * Set total thread can read PDU and process it parallely. It's defaulted to
     * 3.
     * 
     * @param pduProcessorDegree is the total thread can handle read and process
     *        PDU parallely.
     * @throws IllegalStateException if the PDU Reader has been started.
     */
    public void setPduProcessorDegree(int pduProcessorDegree) throws IllegalStateException {
        if (!getSessionState().equals(SessionState.CLOSED)) {
            throw new IllegalStateException(
                    "Cannot set pdu processor degree since the pdu dispatcher thread already created.");
        }
        this.pduProcessorDegree = pduProcessorDegree;
    }
    
    /**
     * Get the total of thread that can handle read and process PDU parallely.
     * 
     * @return the total of thread that can handle read and process PDU
     *         parallely.
     */
    public int getPduProcessorDegree() {
        return pduProcessorDegree;
    }
    
    /**
     * Send the data_sm command.
     * 
     * @param serviceType is the service_type parameter.
     * @param sourceAddrTon is the source_addr_ton parameter.
     * @param sourceAddrNpi is the source_addr_npi parameter.
     * @param sourceAddr is the source_addr parameter.
     * @param destAddrTon is the dest_addr_ton parameter.
     * @param destAddrNpi is the dest_addr_npi parameter.
     * @param destinationAddr is the destination_addr parameter.
     * @param esmClass is the esm_class parameter.
     * @param registeredDelivery is the registered_delivery parameter.
     * @param dataCoding is the data_coding parameter.
     * @param optionalParameters is the optional parameters.
     * @return the result of data_sm (data_sm_resp).
     * @throws PDUStringException if there is an invalid PDU String found.
     * @throws ResponseTimeoutException if the response take time too long.
     * @throws InvalidResponseException if the response is invalid.
     * @throws NegativeResponseException if the response return non-ok command_status.
     * @throws IOException if there is an IO error found.
     */
    public DataSmResult dataShortMessage(String serviceType,
            TypeOfNumber sourceAddrTon, NumberingPlanIndicator sourceAddrNpi,
            String sourceAddr, TypeOfNumber destAddrTon,
            NumberingPlanIndicator destAddrNpi, String destinationAddr,
            ESMClass esmClass, RegisteredDelivery registeredDelivery,
            DataCoding dataCoding, OptionalParameter... optionalParameters)
            throws PDUStringException, ResponseTimeoutException,
            InvalidResponseException, NegativeResponseException, IOException {
        
        
        DataSmCommandTask task = new DataSmCommandTask(pduSender,
                serviceType, sourceAddrTon, sourceAddrNpi, sourceAddr,
                destAddrTon, destAddrNpi, destinationAddr, esmClass,
                registeredDelivery, dataCoding, optionalParameters);
        
        DataSmResp resp = (DataSmResp)executeSendCommand(task, getTransactionTimer());
        
        return new DataSmResult(resp.getMessageId(), resp.getOptionalParameters());
    }
    
    public void close() {
        sessionContext().close();
        try {
            connection().close();
        } catch (IOException e) {
        }
    }
    
    /**
     * Validate the response, the command_status should be 0 otherwise will
     * throw {@link NegativeResponseException}.
     * 
     * @param response is the response.
     * @throws NegativeResponseException if the command_status value is not zero.
     */<commit_msg>Check session state before close connection<commit_after>package org.jsmpp.session;

import java.io.IOException;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import org.jsmpp.InvalidResponseException;
import org.jsmpp.PDUSender;
import org.jsmpp.PDUStringException;
import org.jsmpp.SMPPConstant;
import org.jsmpp.bean.Command;
import org.jsmpp.bean.DataCoding;
import org.jsmpp.bean.DataSm;
import org.jsmpp.bean.DataSmResp;
import org.jsmpp.bean.ESMClass;
import org.jsmpp.bean.NumberingPlanIndicator;
import org.jsmpp.bean.OptionalParameter;
import org.jsmpp.bean.RegisteredDelivery;
import org.jsmpp.bean.TypeOfNumber;
import org.jsmpp.extra.NegativeResponseException;
import org.jsmpp.extra.PendingResponse;
import org.jsmpp.extra.ProcessRequestException;
import org.jsmpp.extra.ResponseTimeoutException;
import org.jsmpp.extra.SessionState;
import org.jsmpp.session.connection.Connection;
import org.jsmpp.util.IntUtil;
import org.jsmpp.util.Sequence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author uudashr
 *
 */
public abstract class AbstractSession implements Session {
    private static final Logger logger = LoggerFactory.getLogger(AbstractSession.class);
    private static final Random random = new Random();
    
    private final Map<Integer, PendingResponse<Command>> pendingResponse = new ConcurrentHashMap<Integer, PendingResponse<Command>>();
    private final Sequence sequence = new Sequence(1);
    private final PDUSender pduSender;
    private int pduProcessorDegree = 3;
    
    private String sessionId = generateSessionId();
    private int enquireLinkTimer = 5000;
    private long transactionTimer = 2000;
    
    public AbstractSession(PDUSender pduSender) {
        this.pduSender = pduSender;
    }
    
    protected abstract AbstractSessionContext sessionContext();
    protected abstract Connection connection();
    protected abstract GenericMessageReceiverListener messageReceiverListener();
    
    protected PDUSender pduSender() {
        return pduSender;
    }
    
    protected Sequence sequence() {
        return sequence;
    }
    
    protected PendingResponse<Command> removePendingResponse(int sequenceNumber) {
        return pendingResponse.remove(sequenceNumber);
    }
    
    public String getSessionId() {
        return sessionId;
    }
    
    public void setEnquireLinkTimer(int enquireLinkTimer) {
        if (sessionContext().getSessionState().isBound()) {
            try {
                connection().setSoTimeout(enquireLinkTimer);
            } catch (IOException e) {
                logger.error("Failed setting so_timeout for session timer", e);
            }
        }
        this.enquireLinkTimer = enquireLinkTimer;
    }
    
    public int getEnquireLinkTimer() {
        return enquireLinkTimer;
    }
    
    public void setTransactionTimer(long transactionTimer) {
        this.transactionTimer = transactionTimer;
    }
    
    public long getTransactionTimer() {
        return transactionTimer;
    }
    
    public SessionState getSessionState() {
        return sessionContext().getSessionState();
    }
    
    public void addSessionStateListener(SessionStateListener l) {
        sessionContext().addSessionStateListener(l);
    }
    
    public void removeSessionStateListener(SessionStateListener l) {
        sessionContext().removeSessionStateListener(l);
    }
    
    public long getLastActivityTimestamp() {
        return sessionContext().getLastActivityTimestamp();
    }
    
    /**
     * Set total thread can read PDU and process it parallely. It's defaulted to
     * 3.
     * 
     * @param pduProcessorDegree is the total thread can handle read and process
     *        PDU parallely.
     * @throws IllegalStateException if the PDU Reader has been started.
     */
    public void setPduProcessorDegree(int pduProcessorDegree) throws IllegalStateException {
        if (!getSessionState().equals(SessionState.CLOSED)) {
            throw new IllegalStateException(
                    "Cannot set pdu processor degree since the pdu dispatcher thread already created.");
        }
        this.pduProcessorDegree = pduProcessorDegree;
    }
    
    /**
     * Get the total of thread that can handle read and process PDU parallely.
     * 
     * @return the total of thread that can handle read and process PDU
     *         parallely.
     */
    public int getPduProcessorDegree() {
        return pduProcessorDegree;
    }
    
    /**
     * Send the data_sm command.
     * 
     * @param serviceType is the service_type parameter.
     * @param sourceAddrTon is the source_addr_ton parameter.
     * @param sourceAddrNpi is the source_addr_npi parameter.
     * @param sourceAddr is the source_addr parameter.
     * @param destAddrTon is the dest_addr_ton parameter.
     * @param destAddrNpi is the dest_addr_npi parameter.
     * @param destinationAddr is the destination_addr parameter.
     * @param esmClass is the esm_class parameter.
     * @param registeredDelivery is the registered_delivery parameter.
     * @param dataCoding is the data_coding parameter.
     * @param optionalParameters is the optional parameters.
     * @return the result of data_sm (data_sm_resp).
     * @throws PDUStringException if there is an invalid PDU String found.
     * @throws ResponseTimeoutException if the response take time too long.
     * @throws InvalidResponseException if the response is invalid.
     * @throws NegativeResponseException if the response return non-ok command_status.
     * @throws IOException if there is an IO error found.
     */
    public DataSmResult dataShortMessage(String serviceType,
            TypeOfNumber sourceAddrTon, NumberingPlanIndicator sourceAddrNpi,
            String sourceAddr, TypeOfNumber destAddrTon,
            NumberingPlanIndicator destAddrNpi, String destinationAddr,
            ESMClass esmClass, RegisteredDelivery registeredDelivery,
            DataCoding dataCoding, OptionalParameter... optionalParameters)
            throws PDUStringException, ResponseTimeoutException,
            InvalidResponseException, NegativeResponseException, IOException {
        
        
        DataSmCommandTask task = new DataSmCommandTask(pduSender,
                serviceType, sourceAddrTon, sourceAddrNpi, sourceAddr,
                destAddrTon, destAddrNpi, destinationAddr, esmClass,
                registeredDelivery, dataCoding, optionalParameters);
        
        DataSmResp resp = (DataSmResp)executeSendCommand(task, getTransactionTimer());
        
        return new DataSmResult(resp.getMessageId(), resp.getOptionalParameters());
    }
    
    public void close() {
        SessionContext ctx = sessionContext();
        if (!ctx.getSessionState().equals(SessionState.CLOSED)) {
            ctx.close();
            try {
                connection().close();
            } catch (IOException e) {
            }
        }
    }
    
    /**
     * Validate the response, the command_status should be 0 otherwise will
     * throw {@link NegativeResponseException}.
     * 
     * @param response is the response.
     * @throws NegativeResponseException if the command_status value is not zero.
     */
{'fraction_non_alphanumeric': 0.07150806900389538, 'fraction_numerical': 0.0019476905954368391, 'mean_word_length': 3.0215384615384617, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6715245', 'n_tokens_mistral': 3823, 'n_tokens_neox': 3734, 'n_words': 1022}