I have classes Source, Intermediate and Destination. Source class has method which with some probability receives new packets to send. Whenever packet is received it should be broadcasted (simulated by some setPacket method) to all neighbor intermediate nodes. Intermediate nodes should broadcast those packets to their neighbors until packets reach destination. The problem is whenever the chain of packet transmission is started source node stops running its method for getting new packets. So, basically the source class is frozen while chain of functions are working. Is there any way to run these two processes simultaneously? (It's like Source node will send request to Intermediate class and that one will do it's work independently) I tried for each of three classes to extend Thread class but still transmission chain is freezing Source class. The language used is Java, but if there any other language that could do the job, I can switch to them.
public class Main {
public static void main(String[] args) {
// init nodes
SourceNode sourceNode = new SourceNode();
IntermediateNode intermediateNode1 = new IntermediateNode();
IntermediateNode intermediateNode2 = new IntermediateNode();
IntermediateNode intermediateNode3 = new IntermediateNode();
DestinationNode destinationNode = new DestinationNode();
// create network topology, S - I - I - I - D
sourceNode.setNextNode(intermediateNode1);
intermediateNode1.setNextNode(intermediateNode2);
intermediateNode2.setNextNode(intermediateNode3);
intermediateNode3.setNextNode(destinationNode);
// setup listeners
sourceNode.setSetupMessageListener(intermediateNode1);
intermediateNode1.setSetupMessageListener(intermediateNode2);
intermediateNode2.setSetupMessageListener(intermediateNode3);
intermediateNode3.setSetupMessageListener(destinationNode);
sourceNode.run();
}
}
public interface SetupMessageListener {
void onNewSetupMessage();
}
public class Node {
protected SetupMessageListener setupMessageListener;
protected Node nextNode;
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
public void setSetupMessageListener(SetupMessageListener setupMessageListener) {
this.setupMessageListener = setupMessageListener;
}
}
import java.util.Random;
public class SourceNode extends Node implements Runnable {
#Override
public void run() {
while(true) {
// simulate generating new setup message with probability 1/10
Random random = new Random();
int rv = random.nextInt(10);
if (rv == 0) {
createNewSetupMessage();
}
}
}
public void createNewSetupMessage() {
System.out.println("New setup message was created in Source Node");
if (setupMessageListener != null) {
setupMessageListener.onNewSetupMessage();
}
}
}
public class IntermediateNode extends Node implements SetupMessageListener {
public static int count = 0;
private int id;
public IntermediateNode() {
id = count++;
}
#Override
public void onNewSetupMessage() {
System.out.println("Intermediate Node " + id + " got notified about setup message");
// pass setup message to next neighbor
setupMessageListener.onNewSetupMessage();
}
}
public class DestinationNode extends Node implements SetupMessageListener {
#Override
public void onNewSetupMessage() {
System.out.println("Destination Node got notified about new setup message");
}
}
And the example output is
New setup message was created in Source Node
Intermediate Node 0 got notified about setup message
Intermediate Node 1 got notified about setup message
Intermediate Node 2 got notified about setup message
Destination Node got notified about new setup message
New setup message was created in Source Node
Intermediate Node 0 got notified about setup message
However, I want it to be smth like
New setup message was created in Source Node
Intermediate Node 0 got notified about setup message
New setup message was created in Source Node
Intermediate Node 1 got notified about setup message
Intermediate Node 0 got notified about setup message
Intermediate Node 2 got notified about setup message
Destination Node got notified about new setup message
The thing is that the whole message passing is done in the main thread....you need to implement the functionality of createNewSetupMessage and onNewMessageSetup as instances of Runnable and initiate new threads to run them.
public class SetupMessageSender implements Runnable{
private SetupMessageListener setupMessageListener;
public SetupMessageSender(SetupMessageListener setupMessageListener){
this.setupMessageListener = setupMessageListener;
}
#Override
public void run() {
if (setupMessageListener != null) {
setupMessageListener.onNewSetupMessage();
}
}
public SetupMessageListener getSetupMessageListener() {
return this.setupMessageListener;
}
public void setSetupMessageListener(SetupMessageListener setupMessageListener) {
this.setupMessageListener = setupMessageListener;
}
}
then
public void createNewSetupMessage() {
System.out.println("New setup message was created in Source Node");
Thread smService = new Thread(new SetupMessageSender(this.setupMessageListener));
smService.start();
}
Be careful though at node listeners onNewMessageSetup, because it will need a bit of syncronization depending on the topology(e.g if an intermediate node is listener for more than one different nodes), so make it
#Override
public synchronized void onNewSetupMessage() {
System.out.println("Intermediate Node " + id + " got notified about setup message");
// pass setup message to next neighbor
Thread smService = new Thread(new SetupMessageSender(this.setupMessageListener));
smService.start();
}
Although the 2 methods provide the same functionality and you could implement them at your base class Node as a single method.
Related
I have a vertx application where I deploy multiple instances of verticle A (HttpVerticle.java) and multiple instances of verticle B (AerospikeVerticle.java). The aerospike verticles need to share a single AerospikeClient. The HttpVerticle listens to port 8888 and calls AerospikeVerticle using the event bus. My questions are:
Is using sharedData the right way to share singleton client instances? Is there any other recommended / cleaner approach? I plan to create and share more such singleton objects (cosmos db clients, meterRegistry etc.) in the application. I plan to use sharedData.localMap to share them in a similar fashion.
Is it possible to use vertx's eventloop as the backing eventloop for aerospike client? Such that the aerospike client initialisation does not need to create its own new eventloop? Currently looks like the onRecord part of the aerospike get call runs on aerospike's eventloop.
public class SharedAerospikeClient implements Shareable {
public final EventLoops aerospikeEventLoops;
public final AerospikeClient client;
public SharedAerospikeClient() {
EventPolicy eventPolicy = new EventPolicy();
aerospikeEventLoops = new NioEventLoops(eventPolicy, 2 * Runtime.getRuntime().availableProcessors());
ClientPolicy clientPolicy = new ClientPolicy();
clientPolicy.eventLoops = aerospikeEventLoops;
client = new AerospikeClient(clientPolicy, "localhost", 3000);
}
}
Main.java
public class Main {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
LocalMap localMap = vertx.sharedData().getLocalMap("SHARED_OBJECTS");
localMap.put("AEROSPIKE_CLIENT", new SharedAerospikeClient());
vertx.deployVerticle("com.demo.HttpVerticle", new DeploymentOptions().setInstances(2 * 4));
vertx.deployVerticle("com.demo.AerospikeVerticle", new DeploymentOptions().setInstances(2 * 4));
}
}
HttpVerticle.java
public class HttpVerticle extends AbstractVerticle {
#Override
public void start(Promise<Void> startPromise) throws Exception {
vertx.createHttpServer().requestHandler(req -> {
vertx.eventBus().request("read.aerospike", req.getParam("id"), ar -> {
req.response()
.putHeader("content-type", "text/plain")
.end(ar.result().body().toString());
System.out.println(Thread.currentThread().getName());
});
}).listen(8888, http -> {
if (http.succeeded()) {
startPromise.complete();
System.out.println("HTTP server started on port 8888");
} else {
startPromise.fail(http.cause());
}
});
}
}
AerospikeVerticle.java
public class AerospikeVerticle extends AbstractVerticle {
private SharedAerospikeClient sharedAerospikeClient;
#Override
public void start(Promise<Void> startPromise) throws Exception {
EventBus eventBus = vertx.eventBus();
sharedAerospikeClient = (SharedAerospikeClient) vertx.sharedData().getLocalMap("SHARED_OBJECTS").get("AEROSPIKE_CLIENT");
MessageConsumer<String> consumer = eventBus.consumer("read.aerospike");
consumer.handler(this::getRecord);
System.out.println("Started aerospike verticle");
startPromise.complete();
}
public void getRecord(Message<String> message) {
sharedAerospikeClient.client.get(
sharedAerospikeClient.aerospikeEventLoops.next(),
new RecordListener() {
#Override
public void onSuccess(Key key, Record record) {
if (record != null) {
String result = record.getString("value");
message.reply(result);
} else {
message.reply("not-found");
}
}
#Override
public void onFailure(AerospikeException exception) {
message.reply("error");
}
},
sharedAerospikeClient.client.queryPolicyDefault,
new Key("myNamespace", "mySet", message.body())
);
}
}
I don't know about the Aerospike Client.
Regarding sharing objects between verticles, indeed shared data maps are designed for this purpose.
However, it is easier to:
create the shared client in your main class or custom launcher
provide the client as a parameter of the verticle constructor
The Vertx interface has a deployVerticle(Supplier<Verticle>, DeploymentOptions) method which is convenient in this case:
MySharedClient client = initSharedClient();
vertx.deploy(() -> new SomeVerticle(client), deploymentOptions);
I am trying to implement a CoAP client based on Californium. I make this client observing to a resource:
public static class CoapCl{
double val = 0;
CoapClient client = new CoapClient("coap://localhost/Ultrasonic");
CoapObserveRelation relation = client.observe(new CoapHandler() {
#Override public void onLoad(CoapResponse response)
{
val = Double.parseDouble(response.getResponseText());
}
#Override
public void onError() {
System.out.println("Failed");
}
});
}
I want to access the value "val" from another class. How can I do it ? I tried to call a reference from the CoapCl class like this and print the value out:
CoapCl client = new CoapCl();
while(true)
{
System.out.println("Testing: " + client.val);
}
This will print all the value I get from the CoAP client, both changed and unchanged value. What should I do if I only want to get the changed value ?
Well, the issue itself isn't related to Californium and CoAP.
Except that CoapHandler is async but this is rather a strench.
Nevertheless, I'd recommend to end up with some kind of callback:
public class CoapCl {
private final Consumer<Double> valueChangedAction;
private final CoapClient client = new CoapClient("coap://localhost/Ultrasonic");
public CoapCl(Consumer<Double> valueChangedAction) {
this.valueChangedAction = valueChangedAction;
}
public void run() {
client.observe(new CoapHandler() {
#Override
public void onLoad(CoapResponse response) {
valueChangedAction.accept(
Double.parseDouble(
response.getResponseText()
)
);
}
#Override
public void onError() {
System.out.println("Failed");
}
});
}
}
new CoapCl(val -> System.out.println("Testing: " + val)).run();
Please keep in mind you have to block the main thread someway to keep the program from immediate exit.
Before, you had blocked it with your infinite loop.
Now you'll have to use System.in.read() or Thread.sleep or something else if you have no such stuff yet in your program.
i'm writing a program that connects with various TCP network devices. The GUI is made using JavaFX. The whole connection part is in its own package "Network". Roughly described, it looks like this: (I don't know much about UML, no blaming plaese :/ - i just needed a way to quickly describe how my program structure looks). http://i.stack.imgur.com/PSdsH.jpg
okay thats how it is:
The TCP classes are stored in a synchronized List in "NetworkManager". These classes hold information about the connection (how much data received yet, ip, mac etc.). The Rcv-Thread constantly tries to receive data.
well, this is what i want:
As soon as the Rcv-Thread receives a specific message, the controller should be invoked to do something (GUI refresh or whatever). Also the controller should stay decoupled from the "Network" module-> it is reused in another project. I want to achieve this behaviour through an custom event. In short: TCP-Rcv-Thread needs to be able to give information to the Controller. But i dont really know how to get it all to work. Lets see where i am:
I have an event class in the "Network" module.
import java.util.EventObject;
public class XEvent extends EventObject{
String message;
public XEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
I have a listener class in the "Network" module.
import java.util.EventListener;
public interface XListener extends EventListener{
void handlerMethod1(XEvent event);
void handlerMethod2(XEvent event);
}
I tried to prepare my Rcv-Thread for firing the event:
import javax.swing.event.EventListenerList;
import java.io.IOException;
public class ReceiveDataThread implements Runnable {
protected EventListenerList listenerList = new EventListenerList();
}
protected void addXListener(XListener xListener) {
listenerList.add(XListener.class, xListener);
}
protected void removeListener(XListener xListener) {
listenerList.remove(XListener.class, xListener);
}
protected void fireHandlerMethod1(String message) {
XEvent event = null;
Object[] list = listenerList.getListenerList();
for (int i = 0; i < list.length; i += 2) {
if (list[i] == XListener.class) {
if (event == null) event = new XEvent(this, message);
XListener l = (XListener) list[i + 1];
l.handlerMethod1(event);
}
}
}
protected void fireHandlerMethod2(String message) {
XEvent event = null;
Object[] list = listenerList.getListenerList();
for (int i = 0; i < list.length; i += 2) {
if (list[i] == XListener.class) {
if (event == null) event = new XEvent(this, message);
XListener l = (XListener) list[i + 1];
l.handlerMethod2(event);
}
}
}
#Override
public void run() {
String s;
while (!stopThread) {
s = receiveData();
System.out.println("test");
fireHandlerMethod1(s);
}
}
The Controller (this class should react on the custom events) implements the Listener:
public class Controller implements Initializable, XListener {
#Override
public void handlerMethod1(XEvent event) {
System.out.println("Event1: " + event.getMessage());
}
#Override
public void handlerMethod2(XEvent event) {
}
}
And from there on i'm not really shure how to get it work that my events (fired from my Rcv-Thread) are noticed by my controller class. I think i have to add a listener to every Rcv-Thread object via the controller class (just like when i use a ButtonListener, ...) . The problem is: from my TCP Class i can't access the Rcv-Thread-object's addXListener method - even when set to public (but i can access the Rcv-Thread-Classes from the list). I tried to read as much as i can about the problem but cant figure out how to get this to work. What am i missing?
edit1: TCP class:
public class TCPClass{
private Thread receiveDataThread;
private String MAC;
private InetAddress IP;
private Socket socket = new Socket();
private int tcpSendPort;
private int timeOut = 10;
private ObjectOutputStream objectOutputStream;
private BufferedReader bufferedReader;
private String connectionStatus = "offline";
public TCPClass(DatagramPacket datagramPacket) {
IP = datagramPacket.getAddress();
setConnectionStatusOnline();
tcpSendPort = 50000 + NetworkManager.getNumberOfConnections();
MAC = extractMac(datagramPacket);
}
public void connect(int tcpPort) {
try {
socket = new Socket(IP, tcpPort, null, tcpSendPort);
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
receiveDataThread = new Thread(new ReceiveDataThread(this));
receiveDataThread.start();
InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
System.out.println("on MAC: " + getMAC() + "\non Device:" + toString());
}
if (socket.isConnected()) {
setConnectionStatusConnected();
}
}
}
The NetworkManager creates an object of TCPClass and calls the connect() method.
Ok so after days i figured it out myself.
The main problem was that i was not able to call the addXListener() method of Rcv-Thread from the Controller. I took the Custom Event stuff out of the Rcv-Thread and moved it to the TCP-Class. Now i'm able to add the Listener to these classes. If i want to fire an event from the Rcv-Thread i simply call fireHandlerMethod() from its superclass (TCP-Class) - and everything works as expected.
this is my very first thread on StackOverflow so please be patient!
Starting from a simple thrift service, I want to create a java client/server application, where each node offers one or more services to other nodes in a distributed computing system. I want to start with a simple system where each node is characterized by two strings, "hostname" and "servicename", that identify each from others. I have created this class:
class NodePort <Node, integer> {
private Node node;
private int port;
NodePort(Node node, int port) {
this.node = node;
this.port = port;
}
Node getNode() {
return node;
}
int getPort() {
return port;
}
}
Then, I've written a management thrift service that does two things:
1) registers a node to a server, returning the port used
2) lists all the services available at the moment
typedef i32 int
struct Node {
1: string hostName,
2: string serviceName,
}
service ManagementService {
int NodeRegister(i32 port)
Node getNodeForService(Node node)
}
When NodeRegister is used, the server creates a Map where keys are given by serviceNames and values are NodePorts, and returns the port used by the client.
When getNodeForService is used, it should return a list of services present in the Map registered by a client.
I'm not sure about how to write the implementation of the two methods. I've written this but when I try a test it doesn't work:
import org.apache.thrift.TException;
import it.uniud.atta.profiling.thrift.ManagementService;
public class ManagementServiceImpl implements ManagementService.Iface {
public int NodeRegister(int port) throws TException {
return port;
}
public Node getNodeForService(Node node) throws TException {
return node;
}
}
I'm pretty sure that this doesn't work the way I want, and also I don't really know where to put the Map code. How could I proceed?
Thanks in advance for any help!
edit: I'm adding the content of my "answer to the question with a question" post. Sorry about it, next time i'll read the rules better!
i actually need help writing the test file. So far i've created a standard thrift server listening on a port, and a thrift client. The code is the following:
public class ManagementServiceTest {
public static class Server implements Runnable {
private TServer tserver;
public void run() {
try {
TServerSocket serverTransport = new TServerSocket(7911);
ManagementService.Processor<ManagementServiceHandler> processor = new ManagementService.Processor<ManagementServiceHandler>(new ManagementServiceHandler());
tserver = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).
processor(processor));
System.out.println("Starting server on port 7911 ...");
tserver.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
public void start() {
new Thread(this).start();
}
public void unserve() {
tserver.stop();
}
}
#Test
public void testServerCompletion() {
Server server = new Server();
server.start();
TTransport transport;
try {
Thread.sleep(200);
transport = new TSocket("localhost", 7911);
TProtocol protocol = new TBinaryProtocol(transport);
ManagementService.Client client = new ManagementService.Client(protocol);
transport.open();
// client.getNodes(testNode.hostName, testNode.serviceName);
// System.out.println("Servizi disponibili: " + testNode.serviceName);
//
// for (String key: nodes.keySet()) {
//
// System.out.println("key : " + key);
// System.out.println("value : " + nodes.get(key));
transport.close();
server.unserve();
} catch (Exception e) {
e.printStackTrace();
}
}
}
I'm not sure about what do I have to write after the transport.open() line. Right now, I should have a server open on port 7911 and listening, a transport open and an unused client variable that I need to initialize. I want to use the RegisterNode() method and the getNodes() method, but so far all my attempts have been unsuccessfull. i've tried with:
Node node1;
node1 = client.RegisterNode(1025);
but it returns "The method RegisterNode(Node, int) in the type ManagementService.Client is not applicable for the arguments (String, int)"
So i tried with
Node node1;
node1 = client.RegisterNode(node1, 1025);
but it returns "Type mismatch: cannot convert from int to Node".
I haven't tried with the other method yet, but I guess i'll receive a similar kind of errors.
I'm not sure I've understood how to write a test file... Any hint?
edit: ok, I've managed to solve the problem with this:
int port = 0;
Node node1 = new Node();
node1.hostname = "Node 1";
node1.serviceName = "Hello World Service";
port = client.RegisterNode(node1, 1025);
System.out.println("Node hostname: " + node1.hostName + "Node Port Used: " + port);
it indeed returns the name of the node and the port used.
Now the second method, getNodes(), presents issues as well. I'm using this:
Nodes nodes = new Nodes();
client.getNodes(node1.hostName, node1.serviceName);
System.out.println("Servizi disponibili: " + node1.serviceName);
for (String key: nodes.keySet()) {
System.out.println("key : " + key);
System.out.println("value : " + nodes.get(key));
}
but it returns two errors about keySet() and get() methods not being defined for the tyoe Nodes. I'm not sure on how should I proceed...
I would structure the service differently, like so:
struct Node {
1: string hostName,
2: string serviceName,
}
struct Nodes {
1: map<Node, i32> allNodes
}
service ManagementService {
/** registers a node to a server, returning the port used */
i32 RegisterNode(1 : Node hostAndService, 2 : i32 preferredPort)
/** lists all the services available at the moment.
Optionally specify host and/or service name to narrow the search */
Nodes GetNodes(1: string host, 2: string service)
}
The map<> code would be in both service routines. In RegisterNode() a node is added to the map, in GetNodes() the map would be scanned for the values needed.
Sample code, not tested (not even compiled, to be honest):
public static class ManagementServiceHandler implements ManagementService.Iface {
private Map<Node,int> nodes;
public ManagementServiceHandler()
{
nodes = new Map<Node,int>()
}
/**
* registers a node to a server, returning the port used
*/
public int RegisterNode(Node hostAndService, int preferredPort) {
int port = preferredPort;
// TODO: check whether port can be used
nodes.Add( hostAndService, port);
return port;
}
/**
* lists all the services available at the moment.
* Optionally specify host and/or service name to narrow the search
*/
public Nodes GetNodes(String host, String svcname) {
var Nodes retval = new Nodes();
retval.allNodes = new Map<Node,int>();
for( var node : nodes) {
if( (host.isEmpty() || (host == node.key.host)) {
if( (svcname.isEmpty() || (svcname == node.key.serviceName)) {
retval.allNodes.add(node)
}
}
}
return retval;
}
}
I am currently working on a Java homework. I am asked to create a basic DNS server.
There is an UDPSender class which is a thread listening on port 53.
There is also another thread which is called UDPManager.
UDPManager starts a thread with a nested runnable class which holds an ArrayList of DatagramPacket. The UDPSender aggregates the UDPManager and whenever it receives an UDP packet, it sends it to the manager for him to add it to the arrayList.
import java.net.DatagramPacket;
import java.util.ArrayList;
import java.util.HashMap;
public class UDPManager {
private UDPManagerRunnable manager;
public UDPManager(String hostsFile, String remoteDNS, boolean localResolution) {
manager = new UDPManagerRunnable(hostsFile, remoteDNS, localResolution);
new Thread(manager).start();
}
public void managePacket(DatagramPacket p) {
manager.managePacket(p);
}
public void close() {
manager.close();
}
private class UDPManagerRunnable implements Runnable {
private ArrayList<DatagramPacket> packets;
private HashMap<Integer, String> clients;
private boolean localResolution;
private boolean running;
private String hostsFile;
private String remoteDNS;
public UDPManagerRunnable(String hostsFile, String remoteDNS, boolean localResolution) {
packets = new ArrayList<DatagramPacket>();
clients = new HashMap<Integer, String>();
this.localResolution = localResolution;
this.running = true;
this.hostsFile = hostsFile;
this.remoteDNS = remoteDNS;
}
public void managePacket(DatagramPacket p) {
packets.add(p);
System.out.println("Received packet. "+packets.size());
}
public void close() {
running = false;
}
public void run() {
DatagramPacket currentPacket = null;
while(running) {
if(!packets.isEmpty()) {
currentPacket = packets.remove(0);
byte[] data = currentPacket.getData();
int anCountValue = data[Constant.ANCOUNT_BYTE_INDEX];
if(anCountValue == Constant.ANCOUNT_REQUEST)
this.processRequest(currentPacket);
else if(anCountValue == Constant.ANCOUNT_ONE_ANSWER)
this.processResponse(currentPacket);
}
}
}
private void processRequest(DatagramPacket packet) {
System.out.println("it's a request!");
}
private void processResponse(DatagramPacket packet) {
System.out.println("it's a response!");
}
}
}
This is the UDPManager. The packets are transmitted to the manager correctly as the System.out.println correctly displays "Received packet." and the size of the array does increase. The problem I'm running into is that inside the "run()" it never see the size increasing. The weird thing is that it works perfectly fine in debug.
Any idea why it's acting this way?
Thanks a lot for your help.
The problem is, that your first thread is putting the new data into the packets variable, but for the second thread this is not visible. You should synchronize the access to the array.
When you start a second thread all variables are copied. The second thread is only working on the copies. You need to synchronize access to this variables, so changes are made visible to the other threads.
you should synchronize packets when you access or modify it