package org.jboss.varia.scheduler;
import java.lang.reflect.Constructor;
import java.text.SimpleDateFormat;
import java.security.InvalidParameterException;
import java.util.Date;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.timer.TimerNotification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import org.jboss.logging.Logger;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.mx.loading.ClassLoaderUtils;
public class Scheduler
extends ServiceMBeanSupport
implements SchedulerMBean
{
public static String JNDI_NAME = "scheduler:domain";
public static String JMX_NAME = "scheduler";
public static String DEFAULT_TIMER_NAME = "jboss:service=Timer";
private static final int NOTIFICATION = 0;
private static final int DATE = 1;
private static final int REPETITIONS = 2;
private static final int SCHEDULER_NAME = 3;
private static final int NULL = 4;
private long mActualSchedulePeriod;
private long mRemainingRepetitions = 0;
private int mActualSchedule = -1;
private String mTimerName = DEFAULT_TIMER_NAME;
private ObjectName mTimer;
private Schedulable mSchedulable;
private boolean mScheduleIsStarted = false;
private boolean mWaitForNextCallToStop = false;
private boolean mStartOnStart = false;
private boolean mIsRestartPending = true;
private boolean mUseMBean = false;
private Class mSchedulableClass;
private String mSchedulableArguments;
private String[] mSchedulableArgumentList = new String[0];
private String mSchedulableArgumentTypes;
private Class[] mSchedulableArgumentTypeList = new Class[0];
private ObjectName mSchedulableMBean;
private String mSchedulableMBeanMethod;
private String mSchedulableMBeanMethodName;
private int[] mSchedulableMBeanArguments = new int[0];
private String[] mSchedulableMBeanArgumentTypes = new String[0];
private SimpleDateFormat mDateFormatter;
private Date mStartDate;
private String mStartDateString;
private boolean mStartDateIsNow;
private long mSchedulePeriod;
private long mInitialRepetitions;
private NotificationListener listener;
public Scheduler()
{
}
public Scheduler(String pSchedulableClass,
String pInitArguments,
String pInitTypes,
String pInitialStartDate,
long pSchedulePeriod,
long pNumberOfRepetitions
)
{
setStartAtStartup(true);
setSchedulableClass(pSchedulableClass);
setSchedulableArguments(pInitArguments);
setSchedulableArgumentTypes(pInitTypes);
setInitialStartDate(pInitialStartDate);
setSchedulePeriod(pSchedulePeriod);
setInitialRepetitions(pNumberOfRepetitions);
}
public Scheduler(
String pSchedulableClass,
String pInitArguments,
String pInitTypes,
String pDateFormat,
String pInitialStartDate,
long pSchedulePeriod,
long pNumberOfRepetitions
)
{
setStartAtStartup(true);
setSchedulableClass(pSchedulableClass);
setSchedulableArguments(pInitArguments);
setSchedulableArgumentTypes(pInitTypes);
setDateFormat(pDateFormat);
setInitialStartDate(pInitialStartDate);
setSchedulePeriod(pSchedulePeriod);
setInitialRepetitions(pNumberOfRepetitions);
}
public void startSchedule()
{
if (!isStarted())
{
try
{
if (mUseMBean)
{
if (mSchedulableMBean == null)
{
log.debug("Schedulable MBean Object Name is not set");
throw new InvalidParameterException(
"Schedulable MBean must be set"
);
}
if (mSchedulableMBeanMethodName == null)
{
mSchedulableMBeanMethodName = "perform";
mSchedulableMBeanArguments = new int[]{DATE, REPETITIONS};
mSchedulableMBeanArgumentTypes = new String[]{
Date.class.getName(),
Integer.TYPE.getName()
};
}
}
else
{
if (mSchedulableClass == null)
{
log.debug("Schedulable Class is not set");
throw new InvalidParameterException(
"Schedulable Class must be set"
);
}
if (mSchedulableArgumentList.length != mSchedulableArgumentTypeList.length)
{
log.debug("Schedulable Class Arguments and Types do not match in length");
throw new InvalidParameterException(
"Schedulable Class Arguments and Types do not match in length"
);
}
}
if (mSchedulePeriod <= 0)
{
log.debug("Schedule Period is less than 0 (ms)");
throw new InvalidParameterException(
"Schedule Period must be set and greater than 0 (ms)"
);
}
if (!mUseMBean)
{
Object[] lArgumentList = new Object[mSchedulableArgumentTypeList.length];
try
{
for (int i = 0; i < mSchedulableArgumentTypeList.length; i++)
{
Class lClass = mSchedulableArgumentTypeList[i];
if (lClass == Boolean.TYPE)
{
lArgumentList[i] = new Boolean(mSchedulableArgumentList[i]);
}
else if (lClass == Integer.TYPE)
{
lArgumentList[i] = new Integer(mSchedulableArgumentList[i]);
}
else if (lClass == Long.TYPE)
{
lArgumentList[i] = new Long(mSchedulableArgumentList[i]);
}
else if (lClass == Short.TYPE)
{
lArgumentList[i] = new Short(mSchedulableArgumentList[i]);
}
else if (lClass == Float.TYPE)
{
lArgumentList[i] = new Float(mSchedulableArgumentList[i]);
}
else if (lClass == Double.TYPE)
{
lArgumentList[i] = new Double(mSchedulableArgumentList[i]);
}
else if (lClass == Byte.TYPE)
{
lArgumentList[i] = new Byte(mSchedulableArgumentList[i]);
}
else if (lClass == Character.TYPE)
{
lArgumentList[i] = new Character(mSchedulableArgumentList[i].charAt(0));
}
else
{
Constructor lConstructor = lClass.getConstructor(new Class[]{String.class});
lArgumentList[i] = lConstructor.newInstance(new Object[]{mSchedulableArgumentList[i]});
}
}
}
catch (Exception e)
{
log.error("Could not load or create constructor argument", e);
throw new InvalidParameterException("Could not load or create a constructor argument");
}
try
{
Constructor lSchedulableConstructor = mSchedulableClass.getConstructor(mSchedulableArgumentTypeList);
mSchedulable = (Schedulable) lSchedulableConstructor.newInstance(lArgumentList);
}
catch (Exception e)
{
log.error("Could not find the constructor or create Schedulable instance", e);
throw new InvalidParameterException("Could not find the constructor or create the Schedulable Instance");
}
}
mRemainingRepetitions = mInitialRepetitions;
mActualSchedulePeriod = mSchedulePeriod;
Date lStartDate = null;
if (mStartDateIsNow)
{
mStartDate = new Date(new Date().getTime() + 1000);
lStartDate = mStartDate;
}
else
{
if (mStartDate.getTime() < new Date().getTime())
{
long lNow = new Date().getTime() + 100;
long lSkipRepeats = ((lNow - mStartDate.getTime()) / mActualSchedulePeriod) + 1;
log.debug("Old start date: " + mStartDate + ", now: " + new Date(lNow) + ", Skip repeats: " + lSkipRepeats);
if (mRemainingRepetitions > 0)
{
if (lSkipRepeats >= mRemainingRepetitions)
{
log.info("No repetitions left because start date is in the past and could " +
"not be reached by Initial Repetitions * Schedule Period");
return;
}
else
{
mRemainingRepetitions -= lSkipRepeats;
}
}
lStartDate = new Date(mStartDate.getTime() + (lSkipRepeats * mActualSchedulePeriod));
}
else
{
lStartDate = mStartDate;
}
}
log.debug("Schedule initial call to: " + lStartDate + ", remaining repetitions: " + mRemainingRepetitions);
mActualSchedule = ((Integer) getServer().invoke(
mTimer,
"addNotification",
new Object[]{
"Schedule",
"Scheduler Notification",
null, lStartDate,
new Long(mActualSchedulePeriod),
mRemainingRepetitions < 0 ?
new Long(0) :
new Long(mRemainingRepetitions)
},
new String[]{
String.class.getName(),
String.class.getName(),
Object.class.getName(),
Date.class.getName(),
Long.TYPE.getName(),
Long.TYPE.getName()
}
)).intValue();
if (mUseMBean)
{
listener = new MBeanListener(mSchedulableMBean);
}
else
{
listener = new Listener(mSchedulable);
}
getServer().addNotificationListener(
mTimer,
listener,
new Scheduler.NotificationFilter(new Integer(mActualSchedule)),
null
);
mScheduleIsStarted = true;
mIsRestartPending = false;
}
catch (Exception e)
{
log.error("operation failed", e);
}
}
}
public void stopSchedule(boolean pDoItNow)
{
try
{
if (mActualSchedule < 0)
{
mScheduleIsStarted = false;
mWaitForNextCallToStop = false;
return;
}
if (pDoItNow)
{
mWaitForNextCallToStop = false;
if (listener != null)
{
getServer().removeNotificationListener(
mTimer,
listener
);
listener = null;
}
log.debug("stopSchedule(), schedule id: " + mActualSchedule);
getServer().invoke(
mTimer,
"removeNotification",
new Object[]{
new Integer(mActualSchedule)
},
new String[]{
Integer.class.getName()
}
);
log.debug("stopSchedule(), removed schedule id: " + mActualSchedule);
mActualSchedule = -1;
mScheduleIsStarted = false;
}
else
{
mWaitForNextCallToStop = true;
}
}
catch (Exception e)
{
log.error("operation failed", e);
}
}
public void restartSchedule()
{
stopSchedule(true);
startSchedule();
}
public String getSchedulableClass()
{
if (mSchedulableClass == null)
{
return null;
}
return mSchedulableClass.getName();
}
public void setSchedulableClass(String pSchedulableClass)
throws InvalidParameterException
{
if (pSchedulableClass == null || pSchedulableClass.equals(""))
{
throw new InvalidParameterException("Schedulable Class cannot be empty or undefined");
}
try
{
ClassLoader loader = TCLActions.getContextClassLoader();
mSchedulableClass = loader.loadClass(pSchedulableClass);
if (!isSchedulable(mSchedulableClass))
{
String msg = "Given class " + pSchedulableClass + " is not instance of Schedulable";
StringBuffer info = new StringBuffer(msg);
info.append("\nThe SchedulableClass info:");
ClassLoaderUtils.displayClassInfo(mSchedulableClass, info);
info.append("\nSchedulable.class info:");
ClassLoaderUtils.displayClassInfo(Schedulable.class, info);
log.debug(info.toString());
throw new InvalidParameterException(msg);
}
}
catch (ClassNotFoundException e)
{
log.info("Failed to find: "+pSchedulableClass, e);
throw new InvalidParameterException(
"Given class " + pSchedulableClass + " is not not found"
);
}
mIsRestartPending = true;
mUseMBean = false;
}
public String getSchedulableArguments()
{
return mSchedulableArguments;
}
public void setSchedulableArguments(String pArgumentList)
{
if (pArgumentList == null || pArgumentList.equals(""))
{
mSchedulableArgumentList = new String[0];
}
else
{
StringTokenizer lTokenizer = new StringTokenizer(pArgumentList, ",");
Vector lList = new Vector();
while (lTokenizer.hasMoreTokens())
{
String lToken = lTokenizer.nextToken().trim();
if (lToken.equals(""))
{
lList.add("null");
}
else
{
lList.add(lToken);
}
}
mSchedulableArgumentList = (String[]) lList.toArray(new String[0]);
}
mSchedulableArguments = pArgumentList;
mIsRestartPending = true;
}
public String getSchedulableArgumentTypes()
{
return mSchedulableArgumentTypes;
}
public void setSchedulableArgumentTypes(String pTypeList)
throws InvalidParameterException
{
if (pTypeList == null || pTypeList.equals(""))
{
mSchedulableArgumentTypeList = new Class[0];
}
else
{
StringTokenizer lTokenizer = new StringTokenizer(pTypeList, ",");
Vector lList = new Vector();
while (lTokenizer.hasMoreTokens())
{
String lToken = lTokenizer.nextToken().trim();
Class lClass = null;
if (lToken.equals("short"))
{
lClass = Short.TYPE;
}
else if (lToken.equals("int"))
{
lClass = Integer.TYPE;
}
else if (lToken.equals("long"))
{
lClass = Long.TYPE;
}
else if (lToken.equals("byte"))
{
lClass = Byte.TYPE;
}
else if (lToken.equals("char"))
{
lClass = Character.TYPE;
}
else if (lToken.equals("float"))
{
lClass = Float.TYPE;
}
else if (lToken.equals("double"))
{
lClass = Double.TYPE;
}
else if (lToken.equals("boolean"))
{
lClass = Boolean.TYPE;
}
if (lClass == null)
{
try
{
ClassLoader loader = TCLActions.getContextClassLoader();
lClass = loader.loadClass(lToken);
}
catch (ClassNotFoundException cnfe)
{
throw new InvalidParameterException(
"The argument type: " + lToken + " is not a valid class or could not be found"
);
}
}
lList.add(lClass);
}
mSchedulableArgumentTypeList = (Class[]) lList.toArray(new Class[0]);
}
mSchedulableArgumentTypes = pTypeList;
mIsRestartPending = true;
}
public String getSchedulableMBean()
{
return mSchedulableMBean == null ?
null :
mSchedulableMBean.toString();
}
public void setSchedulableMBean(String pSchedulableMBean)
throws InvalidParameterException
{
if (pSchedulableMBean == null)
{
throw new InvalidParameterException("Schedulable MBean must be specified");
}
try
{
mSchedulableMBean = new ObjectName(pSchedulableMBean);
mUseMBean = true;
}
catch (MalformedObjectNameException mone)
{
log.error("Schedulable MBean Object Name is malformed", mone);
throw new InvalidParameterException("Schedulable MBean is not correctly formatted");
}
}
public String getSchedulableMBeanMethod()
{
return mSchedulableMBeanMethod;
}
public void setSchedulableMBeanMethod(String pSchedulableMBeanMethod)
throws InvalidParameterException
{
if (pSchedulableMBeanMethod == null)
{
mSchedulableMBeanMethod = null;
return;
}
int lIndex = pSchedulableMBeanMethod.indexOf('(');
String lMethodName = "";
if (lIndex < 0)
{
lMethodName = pSchedulableMBeanMethod.trim();
mSchedulableMBeanArguments = new int[0];
mSchedulableMBeanArgumentTypes = new String[0];
}
else if (lIndex > 0)
{
lMethodName = pSchedulableMBeanMethod.substring(0, lIndex).trim();
}
if (lMethodName.equals(""))
{
lMethodName = "perform";
}
if (lIndex >= 0)
{
int lIndex2 = pSchedulableMBeanMethod.indexOf(')');
if (lIndex2 < lIndex)
{
throw new InvalidParameterException("Schedulable MBean Method: closing bracket must be after opening bracket");
}
if (lIndex2 < pSchedulableMBeanMethod.length() - 1)
{
String lRest = pSchedulableMBeanMethod.substring(lIndex2 + 1).trim();
if (lRest.length() > 0)
{
throw new InvalidParameterException("Schedulable MBean Method: nothing should be after closing bracket");
}
}
String lArguments = pSchedulableMBeanMethod.substring(lIndex + 1, lIndex2).trim();
if (lArguments.equals(""))
{
mSchedulableMBeanArguments = new int[0];
mSchedulableMBeanArgumentTypes = new String[0];
}
else
{
StringTokenizer lTokenizer = new StringTokenizer(lArguments, ",");
mSchedulableMBeanArguments = new int[lTokenizer.countTokens()];
mSchedulableMBeanArgumentTypes = new String[lTokenizer.countTokens()];
for (int i = 0; lTokenizer.hasMoreTokens(); i++)
{
String lToken = lTokenizer.nextToken().trim();
if (lToken.equals("NOTIFICATION"))
{
mSchedulableMBeanArguments[i] = NOTIFICATION;
mSchedulableMBeanArgumentTypes[i] = Notification.class.getName();
}
else if (lToken.equals("DATE"))
{
mSchedulableMBeanArguments[i] = DATE;
mSchedulableMBeanArgumentTypes[i] = Date.class.getName();
}
else if (lToken.equals("REPETITIONS"))
{
mSchedulableMBeanArguments[i] = REPETITIONS;
mSchedulableMBeanArgumentTypes[i] = Long.TYPE.getName();
}
else if (lToken.equals("SCHEDULER_NAME"))
{
mSchedulableMBeanArguments[i] = SCHEDULER_NAME;
mSchedulableMBeanArgumentTypes[i] = ObjectName.class.getName();
}
else
{
mSchedulableMBeanArguments[i] = NULL;
mSchedulableMBeanArgumentTypes[i] = lToken;
}
}
}
}
mSchedulableMBeanMethodName = lMethodName;
mSchedulableMBeanMethod = pSchedulableMBeanMethod;
}
public boolean isUsingMBean()
{
return mUseMBean;
}
public long getSchedulePeriod()
{
return mSchedulePeriod;
}
public void setSchedulePeriod(long pPeriod)
{
if (pPeriod <= 0)
{
throw new InvalidParameterException("Schedulable Period may be not less or equals than 0");
}
mSchedulePeriod = pPeriod;
mIsRestartPending = true;
}
public String getDateFormat()
{
if (mDateFormatter == null)
mDateFormatter = new SimpleDateFormat();
return mDateFormatter.toPattern();
}
public void setDateFormat(String dateFormat)
{
if (dateFormat == null || dateFormat.trim().length() == 0)
mDateFormatter = new SimpleDateFormat();
else
mDateFormatter = new SimpleDateFormat(dateFormat);
}
public String getInitialStartDate()
{
return mStartDateString;
}
public void setInitialStartDate(String pStartDate)
{
mStartDateString = pStartDate == null ? "" : pStartDate.trim();
if (mStartDateString.equals(""))
{
mStartDate = new Date(0);
}
else if (mStartDateString.equals("NOW"))
{
mStartDate = new Date(new Date().getTime() + 1000);
mStartDateIsNow = true;
}
else
{
try
{
long lDate = new Long(pStartDate).longValue();
mStartDate = new Date(lDate);
mStartDateIsNow = false;
}
catch (Exception e)
{
try
{
if (mDateFormatter == null)
{
mDateFormatter = new SimpleDateFormat();
}
mStartDate = mDateFormatter.parse(mStartDateString);
mStartDateIsNow = false;
}
catch (Exception e2)
{
log.error("Could not parse given date string: " + mStartDateString, e2);
throw new InvalidParameterException("Schedulable Date is not of correct format");
}
}
}
log.debug("Initial Start Date is set to: " + mStartDate);
}
public long getInitialRepetitions()
{
return mInitialRepetitions;
}
public void setInitialRepetitions(long pNumberOfCalls)
{
if (pNumberOfCalls <= 0)
{
pNumberOfCalls = -1;
}
mInitialRepetitions = pNumberOfCalls;
mIsRestartPending = true;
}
public long getRemainingRepetitions()
{
return mRemainingRepetitions;
}
public boolean isStarted()
{
return mScheduleIsStarted;
}
public boolean isRestartPending()
{
return mIsRestartPending;
}
public boolean isStartAtStartup()
{
return mStartOnStart;
}
public void setStartAtStartup(boolean pStartAtStartup)
{
mStartOnStart = pStartAtStartup;
}
public boolean isActive()
{
return isStarted() && mRemainingRepetitions != 0;
}
public String getTimerName()
{
return mTimerName;
}
public void setTimerName(String pTimerName)
{
mTimerName = pTimerName;
}
protected void startService()
throws Exception
{
try
{
mTimer = new ObjectName(mTimerName);
}
catch (MalformedObjectNameException mone)
{
mTimer = new ObjectName(DEFAULT_TIMER_NAME);
}
if (!getServer().isRegistered(mTimer))
{
getServer().createMBean("javax.management.timer.Timer", mTimer);
}
if (!((Boolean) getServer().getAttribute(mTimer, "Active")).booleanValue())
{
getServer().invoke(
mTimer,
"start",
new Object[]{},
new String[]{}
);
}
if (mStartOnStart)
{
log.debug("Start Scheduler on start up time");
startSchedule();
}
}
protected void stopService()
{
stopSchedule(true);
}
private static boolean isSchedulable(Class c)
{
boolean lFound = false;
do
{
Class[] lInterfaces = c.getInterfaces();
for (int i = 0; i < lInterfaces.length; i++)
{
if (lInterfaces[i] == Schedulable.class)
{
lFound = true;
break;
}
}
c = c.getSuperclass();
}
while (c != null && !lFound);
return lFound;
}
public class Listener
implements NotificationListener
{
private final Logger log = Logger.getLogger(Listener.class);
private Schedulable mDelegate;
public Listener(Schedulable pDelegate)
{
mDelegate = pDelegate;
}
public void handleNotification(Notification notification,Object handback)
{
log.debug("Listener.handleNotification(), notification: " + notification);
ClassLoader currentTCL = TCLActions.getContextClassLoader();
try
{
ClassLoader loader = TCLActions.getClassLoader(mDelegate.getClass());
TCLActions.setContextClassLoader(loader);
log.debug("Scheduler is started: " + isStarted());
Date lTimeStamp = new Date(notification.getTimeStamp());
if (isStarted())
{
if (getRemainingRepetitions() > 0 || getRemainingRepetitions() < 0)
{
if (mRemainingRepetitions > 0)
{
mRemainingRepetitions--;
}
mDelegate.perform(
lTimeStamp,
getRemainingRepetitions()
);
log.debug("Remaining Repititions: " + getRemainingRepetitions() +
", wait for next call to stop: " + mWaitForNextCallToStop);
if (getRemainingRepetitions() == 0 || mWaitForNextCallToStop)
{
stopSchedule(true);
}
}
}
else
{
getServer().invoke(
mTimer,
"removeNotification",
new Object[]{
new Integer(mActualSchedule)
},
new String[]{
Integer.class.getName()
}
);
mActualSchedule = -1;
}
}
catch (Exception e)
{
log.error("Handling a Scheduler call failed", e);
}
finally
{
TCLActions.setContextClassLoader(currentTCL);
}
}
}
public class MBeanListener
implements NotificationListener
{
private final Logger log = Logger.getLogger(Listener.class);
private ObjectName mDelegate;
public MBeanListener(ObjectName pDelegate)
{
mDelegate = pDelegate;
}
public void handleNotification(
Notification notification,
Object handback
)
{
log.debug("MBeanListener.handleNotification(), notification: " + notification);
try
{
log.debug("Scheduler is started: " + isStarted());
Date lTimeStamp = new Date(notification.getTimeStamp());
if (isStarted())
{
if (getRemainingRepetitions() > 0 || getRemainingRepetitions() < 0)
{
if (mRemainingRepetitions > 0)
{
mRemainingRepetitions--;
}
Object[] lArguments = new Object[mSchedulableMBeanArguments.length];
for (int i = 0; i < lArguments.length; i++)
{
switch (mSchedulableMBeanArguments[i])
{
case NOTIFICATION:
lArguments[i] = notification;
break;
case DATE:
lArguments[i] = lTimeStamp;
break;
case REPETITIONS:
lArguments[i] = new Long(mRemainingRepetitions);
break;
case SCHEDULER_NAME:
lArguments[i] = getServiceName();
break;
default:
lArguments[i] = null;
}
}
log.debug("MBean Arguments are: " + java.util.Arrays.asList(lArguments));
log.debug("MBean Arguments Types are: " + java.util.Arrays.asList(mSchedulableMBeanArgumentTypes));
try
{
getServer().invoke(
mDelegate,
mSchedulableMBeanMethodName,
lArguments,
mSchedulableMBeanArgumentTypes
);
}
catch (javax.management.JMRuntimeException jmre)
{
log.error("Invoke of the Schedulable MBean failed", jmre);
}
catch (javax.management.JMException jme)
{
log.error("Invoke of the Schedulable MBean failed", jme);
}
log.debug("Remaining Repititions: " + getRemainingRepetitions() +
", wait for next call to stop: " + mWaitForNextCallToStop);
if (getRemainingRepetitions() == 0 || mWaitForNextCallToStop)
{
stopSchedule(true);
}
}
}
else
{
getServer().invoke(
mTimer,
"removeNotification",
new Object[]{
new Integer(mActualSchedule)
},
new String[]{
Integer.class.getName()
}
);
mActualSchedule = -1;
}
}
catch (Exception e)
{
log.error("Handling a Scheduler call failed", e);
}
}
}
private static class NotificationFilter implements javax.management.NotificationFilter
{
private static final Logger log = Logger.getLogger(NotificationFilter.class);
private Integer mId;
public NotificationFilter(Integer id)
{
mId = id;
}
public boolean isNotificationEnabled(Notification notification)
{
if (notification instanceof TimerNotification)
{
TimerNotification lTimerNotification = (TimerNotification) notification;
if (log.isTraceEnabled())
log.trace("Scheduler.NotificationFilter.isNotificationEnabled(), Id: " + mId +
", notification: " + notification +
", notification Id: " + lTimerNotification.getNotificationID() +
", timestamp: " + lTimerNotification.getTimeStamp() +
", message: " + lTimerNotification.getMessage()
);
return lTimerNotification.getNotificationID().equals(mId);
}
return false;
}
}
public static class SchedulableExample
implements Schedulable
{
private static final Logger log = Logger.getLogger(Scheduler.SchedulableExample.class);
private String mName;
private int mValue;
public SchedulableExample(
String pName,
int pValue
)
{
mName = pName;
mValue = pValue;
}
public void perform(
Date pTimeOfCall,
long pRemainingRepetitions
)
{
log.info("Schedulable Examples is called at: " + pTimeOfCall +
", remaining repetitions: " + pRemainingRepetitions +
", test, name: " + mName + ", value: " + mValue);
}
}
}