/**
* EasyBeans
* Copyright (C) 2012 Bull S.A.S.
* Contact: easybeans@ow2.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id$
* --------------------------------------------------------------------------
*/
package org.ow2.easybeans.component.quartz;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import javax.ejb.NoSuchObjectLocalException;
import javax.ejb.ScheduleExpression;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerHandle;
import javax.ejb.TimerService;
import org.ow2.easybeans.api.EZBContainer;
import org.ow2.easybeans.api.EZBServer;
import org.ow2.easybeans.api.Factory;
import org.ow2.easybeans.api.FactoryException;
import org.ow2.easybeans.component.api.EZBComponentException;
import org.ow2.easybeans.component.itf.TimerComponent;
import org.ow2.easybeans.component.util.Property;
import org.ow2.easybeans.container.JContainer3;
import org.ow2.easybeans.container.session.stateless.StatelessSessionFactory;
import org.ow2.easybeans.server.Embedded;
import org.ow2.util.archive.api.IArchive;
import org.ow2.util.archive.impl.MemoryArchive;
import org.ow2.util.ee.deploy.api.deployable.IDeployable;
import org.ow2.util.ee.deploy.api.helper.DeployableHelperException;
import org.ow2.util.ee.deploy.impl.helper.DeployableHelper;
import org.ow2.util.marshalling.Serialization;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Tests the Quartz Timer service.
* @author Florent Benoit
*/
public class TestQuartzTimerService {
private static final long MILLIS = 1000L;
private static final long TWO_MINUTES = 2 * 60 * 1000L;
private static final long THREE_MINUTES = 3 * 60 * 1000L;
TimerService timerService = null;
@BeforeClass
protected void init() throws FactoryException, DeployableHelperException, EZBComponentException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
QuartzComponent quartzComponent = new QuartzComponent();
List<Property> properties = new ArrayList<Property>();
Property p1 = new Property();
p1.setName("org.quartz.scheduler.instanceName");
p1.setValue("EasyBeans");
properties.add(p1);
Property p2 = new Property();
p2.setName("org.quartz.threadPool.class");
p2.setValue("org.quartz.simpl.SimpleThreadPool");
properties.add(p2);
Property p3 = new Property();
p3.setName("org.quartz.threadPool.threadCount");
p3.setValue("5");
properties.add(p3);
Property p4 = new Property();
p4.setName("org.quartz.threadPool.threadPriority");
p4.setValue("5");
properties.add(p4);
Property p5 = new Property();
p5.setName("org.quartz.jobStore.class");
p5.setValue("org.quartz.simpl.RAMJobStore");
properties.add(p5);
quartzComponent.setProperties(properties);
quartzComponent.init();
quartzComponent.start();
List<String> classes = new ArrayList<String>();
classes.add(DummyStateless.class.getName());
IArchive inMemoryArchive = new MemoryArchive(TestQuartzTimerService.class.getClassLoader(), classes);
IDeployable<?> deployable = DeployableHelper.getDeployable(inMemoryArchive);
EZBServer easybeans = new Embedded();
EZBContainer container = easybeans.createContainer(deployable);
container.setClassLoader(TestQuartzTimerService.class.getClassLoader());
StatelessSessionFactory statelessSessionFactory = new StatelessSessionFactory(DummyStateless.class.getName(), container);
Field factoriesField = JContainer3.class.getDeclaredField("factories");
factoriesField.setAccessible(true);
Map<String, Factory<?, ?>> factories = (Map<String, Factory<?, ?>>) factoriesField.get(container);
factories.put(statelessSessionFactory.getClassName(), statelessSessionFactory);
this.timerService = quartzComponent.getTimerService(statelessSessionFactory);
easybeans.getComponentManager().getComponentRegistry().register(TimerComponent.class.getName(), quartzComponent);
}
@Test
public void testSimpleTimer() {
String serializableData = "serializable";
long TEN_SECONDS = 10000L;
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createTimer(new Date(System.currentTimeMillis() + TEN_SECONDS), serializableData);
// Check Serializable stuff
Assert.assertEquals(serializableData, timer.getInfo());
// We should get the fire in less than 10s
Assert.assertTrue(timer.getTimeRemaining() < TEN_SECONDS);
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void testInvalidDateSingleTimer() {
TimerConfig timerConfig = new TimerConfig();
// negative value
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 1945);
this.timerService.createSingleActionTimer(calendar.getTime(), timerConfig);
Assert.fail("IllegalArgumentException should be thrown");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void testInvalidLongSingleTimer() {
TimerConfig timerConfig = new TimerConfig();
this.timerService.createSingleActionTimer(-1L, timerConfig);
Assert.fail("IllegalArgumentException should be thrown");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void testNullDateSingleTimer() {
this.timerService.createSingleActionTimer(null, new TimerConfig());
Assert.fail("IllegalArgumentException should be thrown");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void testInvalidDateIntervalTimer() {
TimerConfig timerConfig = new TimerConfig();
// negative value
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 1945);
this.timerService.createIntervalTimer(calendar.getTime(), 1L, timerConfig);
Assert.fail("IllegalArgumentException should be thrown");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void testInvalidLongIntervalTimer() {
TimerConfig timerConfig = new TimerConfig();
this.timerService.createIntervalTimer(-1L, 1L, timerConfig);
Assert.fail("IllegalArgumentException should be thrown");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void testInvalidNegativeIntervalLongIntervalTimer() {
TimerConfig timerConfig = new TimerConfig();
this.timerService.createIntervalTimer(new Date(), -1L, timerConfig);
Assert.fail("IllegalArgumentException should be thrown");
}
/**
* Test with an end time of the schedule expression.
*/
@Test(expectedExceptions=NoSuchObjectLocalException.class)
public void testAfterExpiration() {
Calendar now = new GregorianCalendar();
Calendar expressionDate = (Calendar) now.clone();
expressionDate.add(Calendar.YEAR, 30);
Calendar endDate = (Calendar) expressionDate.clone();
endDate.add(Calendar.YEAR, -1);
ScheduleExpression scheduleExpression = new ScheduleExpression().second(expressionDate.get(Calendar.SECOND)).minute(expressionDate.get(Calendar.MINUTE)).hour(expressionDate.get(Calendar.HOUR_OF_DAY)).month(expressionDate.get(Calendar.MONTH)).year(expressionDate.get(Calendar.YEAR)).end(endDate.getTime());
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createCalendarTimer(scheduleExpression);
Date fireTime = timer.getTrigger().getNextFireTime();
Assert.assertNull(fireTime);
// Should fail
timer.getNextTimeout();
Assert.fail("getNextTimeout method should have failed");
}
/**
* Test with an end time < start time.
* So all methods on the timer will give errors
*/
@Test(expectedExceptions=NoSuchObjectLocalException.class)
public void testEndBeforeStart() {
Calendar now = new GregorianCalendar();
Calendar startDate = (Calendar) now.clone();
startDate.add(Calendar.MINUTE, 300);
Calendar endDate = (Calendar) now.clone();
endDate.add(Calendar.MINUTE, 50);
now.add(Calendar.SECOND, 30);
ScheduleExpression scheduleExpression = new ScheduleExpression().second(now.get(Calendar.SECOND)).minute(now.get(Calendar.MINUTE)).hour(now.get(Calendar.HOUR_OF_DAY)).start(startDate.getTime()).end(endDate.getTime());
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createCalendarTimer(scheduleExpression);
Date fireTime = timer.getTrigger().getNextFireTime();
Assert.assertNull(fireTime);
// Should fail
timer.getNextTimeout();
Assert.fail("getNextTimeout method should have failed");
}
/**
* Check that the expected next timeout is valid
*/
@Test
public void testDayOfWeekNextTimeout() {
// Now
Calendar now = Calendar.getInstance();
now.set(Calendar.MILLISECOND, 0);
for (int i = 0; i < 7; i++) {
int seconds = now.get(Calendar.SECOND);
int minutes = now.get(Calendar.MINUTE);
int hour =now.get(Calendar.HOUR_OF_DAY);
int dayOfWeek = now.get(Calendar.DAY_OF_WEEK);
ScheduleExpression scheduleExpression = new ScheduleExpression().second(seconds).minute(minutes).hour(hour).dayOfMonth("*").month("*").year("*").dayOfWeek(dayOfWeek);
// add a new day
now.add(Calendar.DAY_OF_WEEK, 1);
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createCalendarTimer(scheduleExpression);
Date nextTimeout = timer.getNextTimeout();
Assert.assertNotNull(timer);
Assert.assertNotNull(nextTimeout);
// Check that next timeout is for the given time
Assert.assertEquals(nextTimeout, now.getTime());
}
}
@Test
public void testScheduleWithStartAfterFirstDate() {
// Now
Calendar now = Calendar.getInstance();
now.add(Calendar.SECOND, 20);
now.add(Calendar.YEAR, 4);
int seconds = now.get(Calendar.SECOND);
int minutes = now.get(Calendar.MINUTE);
int hour = now.get(Calendar.HOUR_OF_DAY);
int month = now.get(Calendar.MONTH) + 1;
int dayOfMonth = now.get(Calendar.DAY_OF_MONTH);
Calendar startDate = (Calendar) now.clone();
startDate.add(Calendar.SECOND, 1);
ScheduleExpression scheduleExpression = new ScheduleExpression().second(seconds).minute(minutes).hour(hour).dayOfMonth(dayOfMonth).month(month).year("2012-2030").start(startDate.getTime());
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createCalendarTimer(scheduleExpression);
Date fireTime = timer.getTrigger().getNextFireTime();
Date nextTimeout = timer.getNextTimeout();
Calendar nextTimeoutCalendar = Calendar.getInstance();
nextTimeoutCalendar.setTime(nextTimeout);
Assert.assertNotNull(fireTime);
Assert.assertEquals( nextTimeoutCalendar.get(Calendar.YEAR), now.get(Calendar.YEAR) + 1);
}
@Test
public void testScheduleExpression() {
Date now = new Date();
int currentMinutes = Calendar.getInstance().get(Calendar.MINUTE);
currentMinutes +=3;
if (currentMinutes > 59) {
currentMinutes -=60;
}
ScheduleExpression scheduleExpression = new ScheduleExpression().second("0").minute(currentMinutes + "/5").hour("*");
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createCalendarTimer(scheduleExpression);
Date fireTime = timer.getTrigger().getNextFireTime();
Assert.assertTrue(fireTime.getTime() - now.getTime() > TWO_MINUTES);
Assert.assertTrue(fireTime.getTime() - now.getTime() < THREE_MINUTES);
Assert.assertEquals(fireTime.getSeconds(), 0);
}
@Test
public void testTimerEquals() {
ScheduleExpression scheduleExpression = new ScheduleExpression().second("*").minute("*").hour("*").year(2050);
TimerConfig timerConfig = new TimerConfig();
timerConfig.setInfo("testTimerEquals");
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createCalendarTimer(scheduleExpression, timerConfig);
// We should be equals to ourself
Assert.assertEquals(timer, timer);
Collection<Timer> timers = this.timerService.getTimers();
Assert.assertNotNull(timers);
Assert.assertTrue(timers.size() > 0);
Timer foundTimer = null;
boolean found = false;
for (Timer currentTimer : timers) {
if ("testTimerEquals".equals(currentTimer.getInfo())) {
found = true;
foundTimer = currentTimer;
break;
}
}
Assert.assertTrue(found);
Assert.assertNotNull(foundTimer);
// We should be equals to the timer retrieved
Assert.assertEquals(timer, foundTimer);
}
@Test
public void testTimerHandle() throws IOException, ClassNotFoundException {
ScheduleExpression scheduleExpression = new ScheduleExpression().second("*").minute("*").hour("*").year(2050);
EasyBeansTimer timer = (EasyBeansTimer) this.timerService.createCalendarTimer(scheduleExpression);
TimerHandle timerHandle = timer.getHandle();
byte[] bytesHandle = Serialization.storeObject(timerHandle);
TimerHandle reconstructHandle = (TimerHandle) Serialization.loadObject(bytesHandle);
Timer reconstructTimer = reconstructHandle.getTimer();
// We should be equals to the timer retrieved
Assert.assertEquals(timer, reconstructTimer);
}
}