/*
* eID Applet Project.
* Copyright (C) 2008-2014 FedICT.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version
* 3.0 as published by the Free Software Foundation.
*
* This software 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 software; if not, see
* http://www.gnu.org/licenses/.
*/
package test.be.fedict.eid.applet;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jgroups.Address;
import org.jgroups.ChannelClosedException;
import org.jgroups.ChannelException;
import org.jgroups.ChannelNotConnectedException;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.Receiver;
import org.jgroups.View;
import org.junit.Test;
public class JGroupsSpikeTest {
// /udp_fedict.xml
@Test
public void testJGroupsSingleAgent() throws Exception {
// setup
JChannel channel;
if (true) {
URL udpFedictConfig = JGroupsSpikeTest.class.getResource("/udp.xml");
assertNotNull(udpFedictConfig);
channel = new JChannel(udpFedictConfig);
} else {
channel = new JChannel();
}
MyReceiver myReceiver = new MyReceiver("Hello World");
channel.setReceiver(myReceiver);
channel.connect("hello-world");
// operate
channel.send(new Message(null, null, "Hello World"));
channel.close();
// verify
assertTrue(myReceiver.hasExpectedMessageReceived());
}
public static final class MyReceiver implements Receiver {
private static final Log LOG = LogFactory.getLog(MyReceiver.class);
private final String expectedMessage;
private boolean expectedMessageReceived;
public MyReceiver(String expectedMessage) {
this.expectedMessage = expectedMessage;
this.expectedMessageReceived = false;
}
@Override
public void receive(Message msg) {
Address srcAddress = msg.getSrc();
Object object = msg.getObject();
LOG.debug("receiving from " + srcAddress + " message " + object);
LOG.debug("message object type: " + object.getClass().getName());
if (this.expectedMessage.equals(object)) {
this.expectedMessageReceived = true;
}
}
public boolean hasExpectedMessageReceived() {
return this.expectedMessageReceived;
}
@Override
public byte[] getState() {
LOG.debug("getState");
return null;
}
@Override
public void setState(byte[] state) {
LOG.debug("setState");
}
@Override
public void block() {
LOG.debug("block");
}
@Override
public void suspect(Address address) {
LOG.debug("suspect: " + address);
}
@Override
public void viewAccepted(View view) {
LOG.debug("view accepted: " + view);
}
}
private static final int AGENT_COUNT = 1;
@Test
public void testJGroupsAgents() throws Exception {
RunnableReceiver[] agents = new RunnableReceiver[AGENT_COUNT];
AgentContext context = new AgentContext();
for (int idx = 0; idx < agents.length; idx++) {
RunnableReceiver agent = new RunnableReceiver("/udp.xml", "channel-name", context, idx);
agent.start();
agents[idx] = agent;
}
String msg = "hello world";
agents[0].sendMessage(msg);
context.waitForReceivedMessage(msg, AGENT_COUNT);
for (RunnableReceiver agent : agents) {
agent.stop();
}
}
public static class AgentContext {
private final Map<String, Set<Integer>> receivedMessages;
public AgentContext() {
this.receivedMessages = new HashMap<String, Set<Integer>>();
}
public void waitForReceivedMessage(String msg, int agentCount) throws InterruptedException {
synchronized (this) {
while (true) {
Set<Integer> agentIds = this.receivedMessages.get(msg);
if (null != agentIds) {
if (agentCount == agentIds.size()) {
return;
}
}
this.wait();
}
}
}
public synchronized void notifyReceivedMessage(int agentId, String message) {
Set<Integer> agentIds = this.receivedMessages.get(message);
if (null == agentIds) {
agentIds = new HashSet<Integer>();
}
this.receivedMessages.put(message, agentIds);
agentIds.add(agentId);
this.notify();
}
}
public static class RunnableReceiver implements Receiver, Runnable {
private static final Log LOG = LogFactory.getLog(RunnableReceiver.class);
private final String jgroupsConfigResourceName;
private final String channelName;
private final AgentContext context;
private final int agentId;
private boolean running;
private Thread thread;
private final List<String> outgoingMessages;
private boolean ready;
public RunnableReceiver(String jgroupsConfigResourceName, String channelName, AgentContext context,
int agentId) {
this.jgroupsConfigResourceName = jgroupsConfigResourceName;
this.channelName = channelName;
this.outgoingMessages = new LinkedList<String>();
this.context = context;
this.agentId = agentId;
}
public void sendMessage(String message) {
synchronized (this) {
LOG.debug("agent " + this.agentId + ": queing message for sending :" + message);
this.outgoingMessages.add(message);
this.notify();
}
}
@Override
public void receive(Message msg) {
Address srcAddress = msg.getSrc();
Object object = msg.getObject();
LOG.debug("receiving from " + srcAddress + " message " + object);
this.context.notifyReceivedMessage(this.agentId, object.toString());
}
@Override
public byte[] getState() {
LOG.debug("getState");
return null;
}
@Override
public void setState(byte[] state) {
LOG.debug("setState");
}
@Override
public void block() {
LOG.debug("block");
}
@Override
public void suspect(Address address) {
LOG.debug("suspect: " + address);
}
@Override
public void viewAccepted(View view) {
LOG.debug("view accepted: " + view);
}
public void stop() throws InterruptedException {
this.running = false;
synchronized (this) {
this.notify();
}
this.thread.join();
this.thread = null;
}
public void start() {
if (null != this.thread) {
throw new IllegalStateException("already started");
}
this.thread = new Thread(this);
this.thread.start();
}
@Override
public void run() {
LOG.debug("run");
this.running = true;
JChannel channel;
URL udpFedictConfig = RunnableReceiver.class.getResource(this.jgroupsConfigResourceName);
try {
channel = new JChannel(udpFedictConfig);
} catch (ChannelException e) {
throw new RuntimeException("JGroups channel exception: " + e.getMessage(), e);
}
channel.setReceiver(this);
try {
channel.connect(this.channelName);
} catch (ChannelException e) {
throw new RuntimeException("JGroups channel connect exception: " + e.getMessage(), e);
}
LOG.debug("connected to channel");
while (this.running) {
synchronized (this) {
try {
this.ready = true;
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException("wait error: " + e.getMessage(), e);
}
LOG.debug("agent " + this.agentId + ": waking up");
if (false == this.running) {
channel.close();
break;
}
while (false == this.outgoingMessages.isEmpty()) {
String message = this.outgoingMessages.remove(0);
LOG.debug("agent " + this.agentId + ": sending message: " + message);
try {
channel.send(new Message(null, null, message));
} catch (ChannelNotConnectedException e) {
throw new RuntimeException("channel not connected: " + e.getMessage(), e);
} catch (ChannelClosedException e) {
throw new RuntimeException("channel closed: " + e.getMessage(), e);
}
}
}
}
}
}
}