/*
* Copyright to the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.rioproject.impl.event;
import net.jini.config.EmptyConfiguration;
import net.jini.core.entry.Entry;
import net.jini.core.event.EventRegistration;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.event.UnknownEventException;
import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.lookup.ServiceID;
import net.jini.core.lookup.ServiceItem;
import net.jini.export.Exporter;
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.tcp.TcpServerEndpoint;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.rioproject.event.*;
import org.rioproject.impl.service.LandlordLessor;
import org.rioproject.impl.service.ServiceResource;
import org.rioproject.impl.watch.Watch;
import org.rioproject.impl.watch.WatchDataSourceRegistry;
import org.rioproject.resolver.ResolverConfiguration;
import org.rioproject.watch.Calculable;
import java.io.File;
import java.io.Serializable;
import java.rmi.MarshalledObject;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* Tests event consumer behavior
*/
public class BasicEventConsumerTest {
@BeforeClass
public static void setEnv() {
System.setProperty(ResolverConfiguration.RESOLVER_JAR,
System.getProperty("user.dir")+
File.separator+"target"+
File.separator+"test-classes"+
File.separator+"phony.jar");
}
@Test
public void testCreateBasicEventConsumerWithNullEventDescriptor() throws Exception {
/* Expect that we should be able to create a BEC with a null EventDescriptor */
new BasicEventConsumer((EventDescriptor) null);
}
@Test
public void testCreateBasicEventConsumerWithNullRemoteServiceEventListener() throws Exception {
/* Expect that we should be able to create a BEC with a null RemoteServiceEventListener */
new BasicEventConsumer((RemoteServiceEventListener) null);
}
@Test
public void testCreateBasicEventConsumerWithEventDescriptor() throws Exception {
new BasicEventConsumer(new EventDescriptor());
}
@Test
public void testCreateBasicEventConsumerWithRemoteServiceEventListener() throws Exception {
new BasicEventConsumer(new RemoteServiceEventListener() {
public void notify(RemoteServiceEvent event) {
}
});
}
@Test
public void testRegisteringAnEventProducerAndFiringAnEvent() throws Exception {
BasicEventConsumer consumer = new BasicEventConsumer(getEventDescriptor());
Listener listener = new Listener();
consumer.register(listener);
Producer p = new Producer();
p.createDEH();
ServiceItem serviceItem = createServiceItem(p);
EventRegistration eventRegistration = consumer.register(serviceItem);
Assert.assertNotNull(eventRegistration);
p.fire();
listener.countDown.await(5, TimeUnit.SECONDS);
Assert.assertTrue("Expected listener count to be > 0, found: " + listener.counter.get(),
listener.counter.get() > 0);
}
@Test
public void testRegisteringAnEventProducerAndFiringAnEventWithLeaseBeingDropped() throws Exception {
BasicEventConsumer consumer = new BasicEventConsumer(getEventDescriptor());
Listener listener = new Listener();
consumer.register(listener);
Producer p = new Producer();
p.setLeaseTime(3*1000);
p.createDEH();
ServiceItem serviceItem = createServiceItem(p);
EventRegistration eventRegistration = consumer.register(serviceItem);
Assert.assertNotNull(eventRegistration);
System.err.println("Waiting 5 seconds for lease to timeout...");
Thread.sleep(5*1000);
p.fire();
Assert.assertTrue("Should have not been notified, but got: "+listener.counter.get(), listener.counter.get()==0);
}
//@Test
public void testUsingWatch() throws Exception {
BasicEventConsumer consumer = new BasicEventConsumer(getEventDescriptor());
WatchDataSourceRegistry watchRegistry = new WatchDataSourceRegistry();
Watch watch = consumer.createWatch(watchRegistry);
Assert.assertNotNull(watch);
Assert.assertNotNull("Check Watch accessor", consumer.getWatch());
Assert.assertTrue("Only one watch should be created, calling createWatch twice should return the same watch",
watch.equals(consumer.createWatch(watchRegistry)));
Listener listener = new Listener();
consumer.register(listener);
Producer p = new Producer();
p.createDEH();
ServiceItem serviceItem = createServiceItem(p);
EventRegistration eventRegistration = consumer.register(serviceItem);
Assert.assertNotNull(eventRegistration);
p.fire();
p.fire();
System.err.println("Wait 1 second to catch up...");
Thread.sleep(1000);
Assert.assertTrue("Should have gotten 2, got "+watch.getCalculables().values().size(),
watch.getCalculables().values().size()==2);
Calculable[] calculables = watch.getWatchDataSource().getCalculable();
Assert.assertTrue("Should have gotten 2, got "+calculables.length, calculables.length==2);
for (Calculable calculable : calculables)
System.out.println("==> " + calculable.getValue());
}
@Test
public void testRegisteringAnEventProducerAndFiringEventsUsingRoundRobin() throws Exception {
Producer p = new Producer();
p.createRoundRobin();
ServiceItem serviceItem = createServiceItem(p);
BasicEventConsumer consumer1 = new BasicEventConsumer(getEventDescriptor());
Listener listener1 = new Listener(2);
consumer1.register(listener1);
BasicEventConsumer consumer2 = new BasicEventConsumer(getEventDescriptor());
Listener listener2 = new Listener(2);
consumer2.register(listener2);
BasicEventConsumer consumer3 = new BasicEventConsumer(getEventDescriptor());
Listener listener3 = new Listener(2);
consumer3.register(listener3);
Assert.assertNotNull(consumer1.register(serviceItem));
Assert.assertNotNull(consumer2.register(serviceItem));
Assert.assertNotNull(consumer3.register(serviceItem));
for(int i=0; i<6; i++)
p.fire();
Assert.assertTrue("Should have gotten 2, got "+listener1.counter.get(), listener1.countDown.await(5, TimeUnit.SECONDS));
Assert.assertTrue("Should have gotten 2, got "+listener2.counter.get(), listener2.countDown.await(5, TimeUnit.SECONDS));
Assert.assertTrue("Should have gotten 2, got "+listener3.counter.get(), listener3.countDown.await(5, TimeUnit.SECONDS));
}
private ServiceItem createServiceItem(Producer p) throws Exception {
UUID uuid = UUID.randomUUID();
ServiceID sid = new ServiceID(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
Entry[] attributes = new Entry[]{getEventDescriptor()};
return new ServiceItem(sid, p, attributes);
}
private static EventDescriptor getEventDescriptor() {
return new EventDescriptor(Object.class, (long)1);
}
public static class Producer implements EventProducer {
Object remote;
AtomicLong sequenceCounter = new AtomicLong();
LandlordLessor landlordLessor;
EventHandler eventHandler;
long leaseTime = 30*1000;
Producer() throws Exception {
Exporter exporter = new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
new BasicILFactory(),
false,
true);
remote = exporter.export(this);
landlordLessor = new LandlordLessor(EmptyConfiguration.INSTANCE);
}
void createDEH() throws Exception {
eventHandler = new DispatchEventHandler(getEventDescriptor());
}
void createRoundRobin() throws Exception {
eventHandler = new RoundRobinEventHandler(getEventDescriptor());
}
void setLeaseTime(long leaseTime) {
this.leaseTime = leaseTime;
}
@Override
public EventRegistration register(EventDescriptor descriptor,
RemoteEventListener listener,
MarshalledObject handback,
long duration) throws LeaseDeniedException, UnknownEventException {
eventHandler.register(remote, listener, handback, leaseTime);
return new EventRegistration(descriptor.eventID,
remote,
landlordLessor.newLease(new ServiceResource(new Object()), leaseTime),
sequenceCounter.incrementAndGet());
}
void fire() throws NoEventConsumerException {
TestEvent testEvent = new TestEvent(remote);
testEvent.setSequenceNumber(sequenceCounter.incrementAndGet());
eventHandler.fire(testEvent);
}
}
static class TestEvent extends RemoteServiceEvent implements Serializable {
public TestEvent(Object source) {
super(source);
}
}
class Listener implements RemoteServiceEventListener {
AtomicInteger counter = new AtomicInteger();
CountDownLatch countDown;
Listener() {
countDown = new CountDownLatch(1);
}
Listener(int startCountFrom) {
countDown = new CountDownLatch(startCountFrom);
}
public void notify(RemoteServiceEvent event) {
counter.incrementAndGet();
countDown.countDown();
}
}
}