package net.frontlinesms.camel.smslib;
import java.util.LinkedList;
import java.util.Map;
import org.smslib.CIncomingMessage;
import org.smslib.COutgoingMessage;
import org.smslib.CService;
import org.smslib.NotConnectedException;
import org.smslib.service.MessageClass;
public class SmslibService {
static { System.out.println("SmsLibService class loaded."); }
private CService cService;
private SmslibProducer producer;
private SmslibConsumer consumer;
private boolean consumerRunning;
private boolean producerRunning;
private MessageClass receiveMessageClass = MessageClass.ALL;
private final CServiceFactory cServiceFactory;
private final String uri;
private final String remaining;
private final Map<String, Object> parameters;
private ReceiveThread receiveThread;
//> CONSTRUCTORS
public SmslibService(CServiceFactory cServiceFactory, String uri, String remaining, Map<String, Object> parameters) {
this.cServiceFactory = cServiceFactory;
this.uri = uri;
this.remaining = remaining;
this.parameters = parameters;
Object receiveMessageClass = parameters.get("receiveMessageClass");
if(receiveMessageClass != null) {
if(receiveMessageClass instanceof MessageClass)
this.receiveMessageClass = (MessageClass) receiveMessageClass;
else warn("Could not set receiveMessageClass to value " + receiveMessageClass +
" of class " + receiveMessageClass.getClass());
}
}
private synchronized void initCService() {
this.cService = cServiceFactory.create(uri, remaining, parameters);
}
//> ACCESSORS
public boolean isConsumerRunning() {
return consumerRunning;
}
public boolean isProducerRunning() {
return producerRunning;
}
public void setReceiveMessageClass(MessageClass receiveMessageClass) {
this.receiveMessageClass = receiveMessageClass;
}
public synchronized SmslibProducer getProducer() {
return producer;
}
public synchronized void setProducer(SmslibProducer producer) throws SmslibServiceException {
if(this.producer != null) {
throw new SmslibServiceException("Producer already set.");
}
this.producer = producer;
}
public synchronized SmslibConsumer getConsumer() {
return consumer;
}
public synchronized void setConsumer(SmslibConsumer consumer) throws SmslibServiceException {
if(this.consumer != null) {
throw new SmslibServiceException("Consumer already set.");
}
this.consumer = consumer;
}
public CService getCService() {
return cService;
}
public ReceiveThread getReceiveThread() {
return receiveThread;
}
//> SERVICE METHODS
public synchronized void startForConsumer() throws Exception {
assert(consumer != null);
consumerRunning = true;
receiveThread = new ReceiveThread();
receiveThread.start();
startService();
}
public synchronized void startForProducer() throws Exception {
assert(producer != null);
producerRunning = true;
try {
startService();
} catch(Exception ex) {
producerRunning = false;
producer = null;
throw ex;
}
}
public synchronized void stopForProducer(SmslibProducer p) throws Exception {
if(producer == p) {
producerRunning = false;
stopIfUnused();
producer = null;
}
}
public synchronized void stopForConsumer(SmslibConsumer c) throws Exception {
if(consumer == c) {
consumerRunning = false;
stopIfUnused();
consumer = null;
receiveThread.join();
receiveThread = null;
}
}
private synchronized void stopIfUnused() throws Exception {
if(!producerRunning && !consumerRunning) {
if(cService!=null && cService.isConnected()) {
cService.disconnect();
}
cService = null;
}
}
//> SEND/RECEIVE METHODS
private synchronized void startService() throws Exception {
if(cService == null) {
initCService();
}
if(!cService.isConnected()) {
cService.connect();
}
}
public void send(OutgoingSmslibCamelMessage message) throws Exception {
COutgoingMessage cMess = message.getCMessage();
this.cService.sendMessage(cMess);
if(cMess.getRefNo() < 0) {
throw new MessageRejectedException(cMess);
}
}
public void doReceive() throws Exception {
try {
LinkedList<CIncomingMessage> messageList = new LinkedList<CIncomingMessage>();
this.cService.readMessages(messageList, receiveMessageClass);
for(CIncomingMessage m : messageList) {
this.consumer.accept(new IncomingSmslibCamelMessage(m));
// TODO deletion should be done in markRead() method in suitable class - sometimes deletion is
// not desired and this behaviour should not be forced
System.out.println("Deleting message...");
this.cService.deleteMessage(m);
System.out.println("Message deleted.");
}
} catch(NotConnectedException e) {
System.out.println("SmslibService.doReceive() : NotConnectedException caught");
this.consumer.handleDisconnection(e);
}
}
public class ReceiveThread extends Thread {
private boolean finished;
public void run() {
while(consumerRunning) {
try {
doReceive();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
finished = true;
}
public boolean isFinished() {
return finished;
}
}
//> LOGGING METHODS
private void warn(String message) {
log("WARN", message);
}
private void log(String level, String message) {
System.out.println(level + ": " + message);
}
}