package org.saf.smppagent;
import java.io.IOException;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.saf.business.BaseMTInfo;
import org.saf.common.Globals;
import org.saf.pdu.AbstractPDUCache;
import org.saf.settings.SMPPSettings;
import org.saf.settings.SMSCChannelSettings;
import com.logica.smpp.Connection;
import com.logica.smpp.Data;
import com.logica.smpp.Session;
import com.logica.smpp.TCPIPConnection;
import com.logica.smpp.TimeoutException;
import com.logica.smpp.WrongSessionStateException;
import com.logica.smpp.pdu.BindRequest;
import com.logica.smpp.pdu.BindTransmitter;
import com.logica.smpp.pdu.EnquireLinkResp;
import com.logica.smpp.pdu.PDUException;
import com.logica.smpp.pdu.Response;
import com.logica.smpp.pdu.SubmitSM;
import com.logica.smpp.pdu.SubmitSMResp;
import com.logica.smpp.pdu.ValueNotSetException;
import com.logica.smpp.pdu.WrongLengthOfStringException;
class TransmitterAgent extends BaseSMPPAgent {
private static final Logger logger = Logger.getLogger(TransmitterAgent.class);
private static final int MAX_SUBMIT_SM_QUEUED = 1000;
private TransmitterQueue queue = null;
private Vector<MTListener> mtListeners = null;
private AbstractPDUCache pduCache = null;
private boolean synchronous = false;
private boolean synchronousSubmitSent = false;
private boolean synchronousSubmitResult = false;
TransmitterAgent(String channel, SMSCChannelSettings channelSettings,
SMPPSettings smppSettings, TransmitterQueue queue,
AbstractPDUCache pduCache, boolean synchronous) {
super(channel, channelSettings, smppSettings);
init(queue, pduCache, synchronous);
}
public boolean addMTToSend(BaseMTInfo info) {
boolean ret = false;
if(this.synchronous == false) {
if(this.queue != null) {
ret = queue.add(info);
} else {
logger.fatal("null mt queue");
}
} else { //synchronous way
logger.debug("synchronous way");
if(bind == true) {
logger.debug("bound session");
synchronousSubmitSent = false;
synchronousSubmitResult = false;
ret = queue.add(info);
if(ret == true) {
while(synchronousSubmitSent == false) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
ret = synchronousSubmitResult;
}
} else {
logger.error("unbound session");
}
}
return ret;
}
void addMTListener(MTListener moListener) {
this.mtListeners.add(moListener);
}
@Override
protected void workingProcess() {
if(this.synchronous == false) {
transmitAsynchronous();
logger.debug("End transmit phase...");
} else {
transmitSynchronous();
}
}
@Override
protected boolean bind() {
boolean ret = false;
//Save on cache no managed puds..
if(this.safeStop == true) {
saveToCache();
}
if(this.safeStop == false) {
try {
this.socket = SocketUtility.createSocket(this.settings, true);
if(this.socket != null) {
Connection conn = new TCPIPConnection(this.socket);
this.session = new Session(conn);
BindRequest request = getBindRequest();
Response response = this.session.bind(request);
if(response.getCommandStatus() == Data.ESME_ROK) {
ret = true;
}
else {
logger.fatal("couldn't bind trasmitter. Status=" +
response.getCommandStatus());
}
}
}catch(Exception ex){
logger.fatal("error on bindTrasmitter exception:"
+ ex.toString());
}
//Save on cache no managed pdus..
if(this.safeStop == true) {
saveToCache();
if(ret == true) {
unbind();
}
}
}
return ret;
}
@Override
protected void localSafeStop() {
logger.info("safe stop..");
if(synchronous == false) {
this.queue.safeStop();
saveToCache();
}
}
private void callMTListeners(BaseMTInfo info, SubmitSMResp response) {
MTEvent mtEvent = new MTEvent(info, response);
for(int i = 0; i < this.mtListeners.size(); i++) {
this.mtListeners.elementAt(i).mtDelivered(mtEvent);
}
}
private void transmitSynchronous() {
boolean working = true;
while(working == true) {
BaseMTInfo info = null;
try {
info = this.queue.get(
this.settings.getQuerylinkTimeout());
if(info != null) {
if(safeStop == false) {
working = sendSubmitSM(info);
synchronousSubmitResult = working;
synchronousSubmitSent = true;
} else {
safeUnbind();
working = false;
synchronousSubmitResult = false;
synchronousSubmitSent = false;
}
} else {
if(safeStop == false) {
logger.debug("send enq lnk");
EnquireLinkResp response = null;
try {
response = this.session.enquireLink();
logger.trace("sent enq lnk");
if(response.getCommandStatus() != Data.ESME_ROK) {
safeUnbind();
working = false;
}
} catch (Exception e) {
logger.error("error on enquire link " +
e.getMessage());
safeUnbind();
working = false;
}
} else {
safeUnbind();
working = false;
}
}
} catch (InterruptedException e) {
logger.error("interrupted reading from submitSM queue " +
e.getMessage());
}
}
}
private void transmitAsynchronous(){
boolean working = true;
long retriesTimestamp =
this.smppSettings.getSubmitRetriesTimeout() * 1000;
while(working == true) {
BaseMTInfo info = null;
try {
info = this.queue.get(
this.settings.getQuerylinkTimeout());
if(info != null) {
if(safeStop == false) {
if(info.getRetries() == 0) {
working = sendSubmitSM(info);
if(working == false) {
unbind();
}
} else { //retries
long timestamp = System.currentTimeMillis() -
info.getTimestampLastRetries();
if(timestamp >= retriesTimestamp ) {
working = sendSubmitSM(info);
if(working == false) {
unbind();
}
} else {
boolean added = addMTToSend(info);
if(added == false) {
if(this.pduCache != null) {
logger.info("going out save message on cache");
this.pduCache.addSubmitSMToTransmit(info,
this.settings.getChannelPDU());
}
unbind();
working = false;
}
}
}
} else {
if(this.pduCache != null) {
logger.info("going out save message on cache");
this.pduCache.addSubmitSMToTransmit(
info, this.settings.getChannelPDU());
}
safeUnbind();
working = false;
}
} else {
if(safeStop == false) {
logger.debug("send enq lnk");
EnquireLinkResp response = null;
try {
response = this.session.enquireLink();
logger.trace("sent enq lnk");
if(response.getCommandStatus() != Data.ESME_ROK) {
logger.error("error on enquire link no OK, unbind");
unbind();
working = false;
}
} catch (Exception e) {
logger.error("error on enquire link " +
e.getMessage());
unbind();
working = false;
}
} else {
safeUnbind();
working = false;
}
}
} catch (InterruptedException e) {
logger.error("interrupted reading from submitSM queue " +
e.getMessage());
}
}
}
private void safeUnbind() {
saveToCache();
unbind();
}
private void init(TransmitterQueue queue, AbstractPDUCache pduCache,
boolean synchronous) {
if(synchronous == false) {
if(queue == null) {
this.queue =
new TransmitterQueue(MAX_SUBMIT_SM_QUEUED, this.channel);
} else {
this.queue = queue;
}
} else { //syncronous case
this.queue = new TransmitterQueue(1, this.channel);
}
this.synchronous = synchronous;
this.mtListeners = new Vector<MTListener>();
this.pduCache = pduCache;
}
private BindRequest getBindRequest()
throws WrongLengthOfStringException {
BindRequest request = new BindTransmitter();
request.setSystemId(this.settings.getSystemId());
request.setPassword(this.settings.getPassword());
request.setSystemType(this.settings.getSystemType());
request.setAddressRange( this.settings.getAddrTon(),
this.settings.getAddrNpi(), this.settings.getAddressRange());
return request;
}
private boolean sendSubmitSM(BaseMTInfo info) {
boolean ret = false;
if(this.bind == true && this.session != null) {
SubmitSMResp response = null;
SubmitSM request = info.getRequest();
try {
logger.info("MT to send for src: " +
request.getSourceAddr().getAddress() +
" dstn: " + request.getDestAddr().getAddress() +
" seqNum: " + request.getSequenceNumber());
long start = System.currentTimeMillis();
response = this.session.submit(request);
if(response != null) {
long stop = System.currentTimeMillis();
info.setTransactionTime(stop - start);
logger.info("MT response " + response.debugString() +
" for src: " + request.getSourceAddr().getAddress() +
" dstn: " + request.getDestAddr().getAddress() +
" seqNum: " + request.getSequenceNumber());
callMTListeners(info, response);
ret = true;
} else {
if(synchronous == false) {
logger.fatal("No response going out....");
addMTToSend(info);
} else {
logger.fatal("No response...");
}
}
} catch (ValueNotSetException e) {
logger.fatal("no way to manage this exception " + e.getMessage());
} catch (TimeoutException e) {
logger.error(e.getMessage());
if(synchronous == false) {
logger.error(" re-adding in queue " +
request.debugString());
addMTToSend(info);
}
} catch (PDUException e) {
logger.fatal("no way to manage this exception " + e.getMessage());
} catch (WrongSessionStateException e) {
logger.fatal("no way to manage this exception " + e.getMessage());
} catch (IOException e) {
logger.error(e.getMessage());
if(synchronous == false) {
logger.error(" re-adding in queue " +
request.debugString());
addMTToSend(info);
}
} catch (NullPointerException e) {
logger.error(e.getMessage());
if(synchronous == false) {
logger.error(" re-adding in queue " +
request.debugString());
addMTToSend(info);
}
}
} else {
logger.error("unbind session");
}
return ret;
}
private void saveToCache() {
if(this.pduCache != null) {
BaseMTInfo info = null;
logger.info("saving to cache");
long timeout =
Globals.getInstance().getTimeoutSafestopQueuePolling();
do {
try {
info = this.queue.get(timeout);
if(info != null) {
this.pduCache.addSubmitSMToTransmit(
info, this.settings.getChannelPDU());
}
} catch (InterruptedException e) {
info = null;
}
} while (info != null);
}
}
}