Author Message
liu159
Joined: Jan 19, 2015
Messages: 96
Offline
I have a class myClass.java which will invoke call.initiate().

I want a timeout mechanism such that after 1 minute if the user does not pick up the call, we invoke the timeout function and drop the call.

How should I do this ? Is there any example to do so ?

Thank you !


JoelEzell
Joined: Nov 15, 2013
Messages: 780
Offline
Hello, the correct way to do this is to use an EJB timer. See the following article for an example.

http://www.tutorialspoint.com/ejb/ejb_timer_service.htm
liu159
Joined: Jan 19, 2015
Messages: 96
Offline
I have read the example but been quite confused. In the example, it mentioned "JBoss", "jndi.properties" and "InitialContext Obj" which I don't know how to put or initialize in my snap-in.

I have created the two classes: "TimerSessionBean.java" and "TimerSessionBeanRemote.java".

Screenshot 1 is the class where I need to start a timer.

How can I create a TimerService and start the timer ?
  • [Thumb - Screenshot 1.jpg]
[Disk] Download
JoelEzell
Joined: Nov 15, 2013
Messages: 780
Offline
My apologies for the confusion. I should have taken more time to research the matter before replying. You're correct that I mistakenly pointed you to a description of how to do an EJB timer in JBoss. I've consulted with the Engagement Development Platform team on the best way to do such a thing within EDP, and we're working up an example for you. Expect to see something by Monday at the latest.
liu159
Joined: Jan 19, 2015
Messages: 96
Offline
Thank you very much !
JoelEzell
Joined: Nov 15, 2013
Messages: 780
Offline
OK, hopefully the following from my colleagues on the EDP development team will be helpful to you. Please let us know how it goes!

First, there is an example that is closely tied to the CallListener class.
============= The MyTimer class ====================
@Startup
@Singleton
public class MyTimer {

@Resource
private TimerService timerService;

public void createTimer(long millis, final String callId)
{
TimerConfig timerConfig = new TimerConfig();

timerConfig.setInfo(callId);

timerService.createSingleActionTimer(millis, timerConfig);
}

@Timeout
public void onTimer(Timer timer)
{
String callId = (String)timer.getInfo();

CallFactory.getCall(callId).allow();
}
}
================================================

============= In the @TheCallListener class ====================
@Override
public final void callIntercepted(final Call call) {
final String callId = call.getUCID();

try {
final InitialContext ctx = new InitialContext();

final String lookupName = "java:module/MyTimer";
MyTimer myTimer = (MyTimer) ctx.lookup(lookupName);
myTimer.createTimer(5000L, callId);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

call.suspend();
}
===================================================

It’s important to note that in the @TheCallListener class, the JNDI lookup done through the InitialContext object can probably be done once and reused. However, the lookup will probably best be done in a lazy initialization manner just prior to first use. Otherwise, one may encounter timing problems, since we don’t know if the container will guarantee that a Singleton bean annotated with @Startup will be constructed before a SipServlet begins its initialization (which means, since the ServiceLifeCycle we make available through our API is based on the SipServlet lifecycle, the init() method available there may not a reliable place to do the lookup of the MyTimer bean).

Also, note that the JNDI lookup string of "java:module/MyTimer" works if the MyTimer class is in the WAR sub-project. If it were to be put in a jar outside of the WAR module (but of course, still in the EAR), then the string would need to be "java:app/<module>/MyTimer", where <module> is the name of the jar file without the “.jar” extension (for example, "java:app/robtest-ejb-0.0.1-SNAPSHOT/MyTimer2", where the jar file containing the MyTimer2 class is named is “robtest-ejb-0.0.1-SNAPSHOT.jar”).


Here is a more general example that is not closely tied to the CallListener class:
============= The MyTimer class ====================
@Startup
@Singleton
public class MyTimer {
Logger logger = Logger.getLogger(MyTimer.class);

@Resource
private TimerService timerService;

public void createTimer(long millis, final MyInfo myInfo)
{
TimerConfig timerConfig = new TimerConfig();

timerConfig.setInfo(myInfo);

timerService.createSingleActionTimer(millis, timerConfig);
}

@Timeout
public void onTimer(Timer timer)
{
MyInfo myInfo = (MyInfo)timer.getInfo();

logger.info(myInfo.getSomeData());
}
}
================================================

============= A Class that Holds Data Needed When the Timer Fires ==================
public static class MyInfo implements Serializable
{
private static final long serialVersionUID = 1L;

final String someData;

MyInfo(final String someData)
{
this.someData = someData;
}

public String getSomeData()
{
return someData;
}
}
========================================================================

============= Code that creates the timer ====================
final MyInfo myInfo = new MyInfo("The data I need when timer is triggered");

try {
final InitialContext ctx = new InitialContext();

final String lookupName = "java:module/MyTimer";

MyTimer myTimer = (MyTimer) ctx.lookup(lookupName);
myTimer.createTimer(5000L, myInfo);
} catch (NamingException e) {
e.printStackTrace();
}
===================================================

The same explanation as above applies for the JNDI lookup string.
liu159
Joined: Jan 19, 2015
Messages: 96
Offline
Thank you ! It's very helpful and it works with my code !

I'm also wondering if I want to cancel the timer after the user picks up the call, do I need to store the timer as an attribute of a call instance such that I can cancel it in the callListener ?
liu159
Joined: Jan 19, 2015
Messages: 96
Offline
There is a problem. For some reason the "onTimer" (timeout method) is executed every 5 minutes even after I redeployed the service. I think it's because the Timer hasn't been canceled correctly.

*******************Update**********************

I have start a timer and set a 1 minute timeout.

But before it timeout, I pick up the call so it goes to callOriginated(), where I want to cancel the timer but get an exception:

MyTimer: Exception after cancelling timer : javax.ejb.NoSu chObjectLocalException: TimerImpl(103, BeanId(EdpFmwRestSvcTest-1.0.0.0.0#edpfmw resttest-war-1.0.0.0.0.war#MyTimer, null)); nested exception is: com.ibm.websphe re.scheduler.TaskInvalid: SCHD0061E: The task information for task ID 103 and ow ner token EdpFmwRestSvcTest-1.0.0.0.0 was not found in the database.


Here is my code:

**************************************

ClickToCall.java (where start the timer):

final String callUCID = call.getUCID();

logger.fine("makeCall: bind callUCID: " + callUCID + " to timer.");

try
{
final InitialContext ctx = new InitialContext();
final String lookupName = "java:module/MyTimer";
MyTimer myTimer = (MyTimer) ctx.lookup(lookupName);
myTimer.createTimer(60000L, callUCID);
logger.fine("makeCall: start timer ...");
call.setAttribute(CallData.TIMER, myTimer);

}
catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

call.initiate();

**************************************

MyCallListener.java

@Override
public void callOriginated(final Call call)
{
logger.fine("Entered callOriginated.");

if(call.getAttribute(CallData.TIMER)!=null){

// cancel the timer
logger.fine("callOriginated: Cancel the timer.");
MyTimer myTimer = (MyTimer) call.getAttribute(CallData.TIMER);
// myTimer.cancelTimer(call.getUCID());
myTimer.cancelAllTimers();
call.setAttribute(CallData.TIMER, null);

}

...
}

*************************************

MyTimer.java:


@Startup
@Singleton
public class MyTimer {
private static Logger logger = Logger.getLogger(MyTimer.class);


@Resource
private TimerService timerService;

public void createTimer(long millis, final String callId)
{
TimerConfig timerConfig = new TimerConfig();

timerConfig.setInfo(callId);

timerService.createSingleActionTimer(millis, timerConfig);
}

@Timeout
public void onTimer(Timer timer)
{
logger.fine("MyTimer: timeout ...");

String callId = (String)timer.getInfo();

logger.fine("MyTimer: drop the call : " + callId);

CallFactory.getCall(callId).drop();

checkTimerStatus();

// timer.cancel();
}

public void cancelTimer(String timerName)
{
try
{
Collection<Timer> timers = timerService.getTimers();
Iterator<Timer> it = timers.iterator();
while (it.hasNext())
{
Timer myTimer = (Timer) it.next();
if ((myTimer.getInfo().equals(timerName))) {
myTimer.cancel();

logger.fine("MyTimer: Successfully Cancelled " + timerName);
}
}
}
catch (Exception e) {

logger.fine("MyTimer: Exception after cancelling timer : "+
e.toString());

}
return;
}

public void cancelAllTimers()
{
try
{
Collection<Timer> timers = timerService.getTimers();
Iterator<Timer> it = timers.iterator();
while (it.hasNext())
{
Timer myTimer = (Timer) it.next();

myTimer.cancel();

logger.fine("MyTimer: Successfully Cancelled " + myTimer.getInfo());

}
}
catch (Exception e) {

logger.fine("MyTimer: Exception after cancelling timer : "+
e.toString());

}
return;
}

public void checkTimerStatus() {
Timer timer = null;
int count = 0;
Collection<Timer> timers = timerService.getTimers();
Iterator<Timer> iterator = timers.iterator();
while (iterator.hasNext()) {
timer = iterator.next();
logger.fine("Timer: " + timer.getInfo() + " will expire after " + timer.getTimeRemaining() + " milliseconds.");
count += 1;
}
logger.fine("Timer: total timer count: " + count);
}

}




JoelEzell
Joined: Nov 15, 2013
Messages: 780
Offline
I'll look into this with the team.
liu159
Joined: Jan 19, 2015
Messages: 96
Offline
I finally figured out that this is what I should use in CallOriginated to cancel the Timer:

@Override
public void callOriginated(final Call call)
{
logger.fine("Entered callOriginated.");

// cancel timer
try
{
final InitialContext ctx = new InitialContext();
final String lookupName = "java:module/MyTimer";
MyTimer myTimer = (MyTimer) ctx.lookup(lookupName);

logger.fine("callOriginated: cancel timer ...");

myTimer.cancelTimer(call.getUCID());
// myTimer.checkTimerStatus();

}
catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

....
}


I have also cleaned up all the timers which have not been canceled properly yesterday.

Thank you !
JoelEzell
Joined: Nov 15, 2013
Messages: 780
Offline
That's great news, thanks for sharing it with us.
Go to:   
Mobile view