I have data retrieved from a server at very high rate, the datas sent are in form of a message that resembles the following format:
$FMSn,par1,par2...,...,...,...,..,...,....,par20 //where n is number ranges from 1 to 12
this message I need to process to parse some data.
but less frequently the server sends other message in different format, that message is not important and could be discarded and the difference between it and the previously described messages in format is that
the previous message starts with $FMS while the other message not.
to distinguish between these messages to know which one is that should be processed, i created a class FMSParser as shown below and i checked if the message header is
$FMS
or not.
my question is, should i create a new object of FMSParser class in the loop in which the messages from the server are received or create one object in the whole
program and in the loop in which the data are recived i just call isValid method and getParam(). in other words in code:
should i choose solution 1 or 2?
solution 1:
loop for messages receiving:
msg = receive message();
fmsParser = new FMSParser(msg);
if (fmsParser.isValid) {
params = fmsParser.getParam();
}
solution 2:
fmsParser = new FMSParser();
loop for messages receiving:
msg = receive message();
if (fmsParser.isValid(msg)) {
params = fmsParser.getParam();
}
code:
private class FMSParser {
private final static String HEADER = "$FMS"
private String[] mSplittedMsg;
FMSParser() {}
public boolean isValidMsg(String msg) {
boolean isValid = false;
this.mSplittedMsg = msg.split(",");
for (int i = 0; i < 12; i++) {
if (splittedMsg[0].equals(HEADER+i)) {
valid = true;
break;
}
}
return valid;
}
public String [] getParam() {
return this.mSplittedMsg;
}
}
If you construct a new FMSParser each time through the loop, it will require memory allocation and garbage collection.
I would choose option 3 which makes the FMSParser immutable, meaning it is thread-safe.
FMSParser fmsParser = new FMSParser();
while (messageIterator.hasNext()) {
String msg = messageIterator.next();
if (fmsParser.isValid(msg)) {
params = fmsParser.getParam(msg);
}
}
Eg:
public class FMSParser {
public boolean isValid(String msg) {
return msg.startsWith("$FMS");
}
public String[] getParams(String msg) {
return msg.split(",");
}
}
Related
I'm trying to execute some code on some parsed JSON using Retrofit, but I am getting an Illegal State Exception. Here is my Retrofit instance:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.pro.coinbase.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
CoinbaseProAPI coinbaseProAPI = retrofit.create(CoinbaseProAPI.class);
The Coinbase Pro API interface:
#GET("products/{productId}/candles")
Call<ArrayList<HistoricRates>> getHistoricRates(#Header("CB-ACCESS-SIGN") String signature,
#Header("CB-ACCESS-TIMESTAMP") String timeStamp,
#Path("productId") String productId,
#Query("start") String intervalStart,
#Query("end") String intervalEnd,
#Query("granularity") int granularity
);
The call request to the server (this is what's causing the error):
Call<ArrayList<HistoricRates>> call = coinbaseProAPI.getHistoricRates(signature, timeStamp, productId, intervalStart, intervalEnd, granularity);
try {
//this is being executed inside a for loop; requests are rate limited so consecutive
//iterations must wait
if (i > 0) {
call.wait(1010);
}
//this is the line the debugger doesn't like:
Response<ArrayList<HistoricRates>> response = call.execute();
if (!response.isSuccessful()) {
Message eMsg = errorHandler.obtainMessage();
String e = R.string.error_header + response.toString();
eMsg.what = 2;
eMsg.obj = e;
errorHandler.sendMessage(eMsg);
} else {
ArrayList<HistoricRates> candles = response.body();
int n = 0;
double[][] aCandles = new double[3][3];
for (HistoricRates historicRates : candles) {
aCandles[n][0] = historicRates.getOpen();
aCandles[n][1] = historicRates.getClose();
aCandles[n][2] = historicRates.getVolume();
n++;
}
selectedAsset.setCandles(aCandles);
}
} catch (Exception e) {
Message eMsg = errorHandler.obtainMessage();
eMsg.what = 2;
eMsg.obj = e.getMessage();
errorHandler.sendMessage(eMsg);
e.printStackTrace();
}
And finally the class object the JSON is being parsed into:
public class HistoricRates {
private int time;
private double low;
private double high;
private double open;
private double close;
private double volume;
public double getOpen() {
return open;
}
public double getClose() {
return close;
}
public double getVolume() {
return volume;
}
}
So from what I gather from similar posts, Illegal State Exception occurs because the object I'm trying to pass to Gson is not of the correct type. But I don't understand how this could be, given that I'm using Retrofit; shouldn't the GsonConverterFactory take care of this for me? Also, even though I have this code enclosed within a try/catch block, it is not actually throwing an exception; it just fails silently. The only reason I even know about the Illegal State Exception is because of the Debug Console. How can I improve my error reporting or is there something else I'm not understanding?
EDIT TO ADD:
Tried Capps99's solution (with added accessor method included in HistoricRatesList so I can get an iterator to loop through the values) Here is what that looks like:
HistoricRatesList candles = response.body();
Iterator candleIterator = candles.getList().iterator();
int n = 0;
double[][] aCandles = new double[3][3];
while (candleIterator.hasNext()) {
HistoricRates historicRates = (HistoricRates) candleIterator.next();
aCandles[n][0] = historicRates.getOpen();
aCandles[n][1] = historicRates.getClose();
aCandles[n][2] = historicRates.getVolume();
n++;
}
Unfortunately I'm still getting an Illegal State Exception. At the request of another commenter, here is the expected JSON response from the server(apologies I should have included this to begin with):
[
//these are all decimal values except for time; which is an integer value
//representing the UNIX epoch time
[time, low, high, open, close, volume],
[time, low, high, open, close, volume],
...
]
Perhaps the trouble is that the server appears to be returning the data in the form of a 2D array, which I don't have the experience to know how to parse properly.
Try this.
Create the following class to parse the list.
public class HistoricRatesList {
List<HistoricRates> historicRates;
}
and then use like this.
#GET("products/{productId}/candles")
Call<HistoricRatesList> getHistoricRates(#Header("CB-ACCESS-SIGN") String signature,
#Header("CB-ACCESS-TIMESTAMP") String timeStamp,
#Path("productId") String productId,
#Query("start") String intervalStart,
#Query("end") String intervalEnd,
#Query("granularity") int granularity
);
I have a small java app and I have used JInterface to essentially expose it as an OTP process in my elixir app. I can call it and get a response successfully.
My problem is that the response I get back in elixir is of a binary but I cannot figure out how to convert a binary to a list of strings which is what the response is.
The code for my OTP node in Java using JInterface is below:
public void performAction(Object requestData, OtpMbox mbox, OtpErlangPid lastPid){
List<String> sentences = paragraphSplitter.splitParagraphIntoSentences((String) requestData, Locale.JAPAN);
mbox.send(lastPid, new OtpErlangBinary(getOtpStrings(sentences)));
System.out.println("OK");
}
private List<OtpErlangString> getOtpStrings(List<String> sentences) {
List<OtpErlangString> erlangStrings = new ArrayList<>();
for(int i = 0; i < sentences.size(); i++){
erlangStrings.add(new OtpErlangString(sentences.get(i)));
}
return erlangStrings;
}
It is necessary to wrap the response in an OtpErlangBinary and I have concerted the strings to OTPErlangString. I have also tried without converting the strings to OTPErlangString.
On the elixir side I can receive the binary response and IO.inspect it.
Does anybody know how to use JInterface to deserialise the results correctly when it's anything other than a single string? Or maybe, if I have made some mistake, how to build the correct response type so that I can deserialise it correctly?
Any help would be really appreciated as I have been trying to figure this out for ages.
Thanks in advance.
I have been playing around with JInterface and Elixir and I think I've got your problem figured out.
So you are trying to send a list of strings from an Elixir/Erlang node to a Java node, but you cannot get it to de-serialize properly.
Elixir has its own types (e.g., atoms, tuples, ..) and Java has its own types (e.g., Object, String, List<String>,..). There needs to be a conversion from the one type to the other if they're supposed to talk to each other. In the end it's just a bunch of 1's and 0's that get sent over the wire anyway.
If an Erlang list is sent to Java, what arrives can always be interpreted as an OtpErlangObject. It's up to you to then try and guess what the actual type is before we can even begin turning it into a Java value.
// We know that everything is at least an OtpErlangObject value!
OtpErlangObject o = mbox.receive();
But given that you know that it's in fact a list, we can turn it into an OtpErlangList value.
// We know o is an Erlang list!
OtpErlangList erlList = (OtpErlangList) o;
The elements of this list however, are still unknown. So at this point its still a list of OtpErlangObjects.
But, we know that it's a list of strings, so we can interpret the list of OtpErlangObjects as list of OtpErlangStrings, and convert those to Java strings.
public static List<String> ErlangListToStringList(OtpErlangList estrs) {
OtpErlangObject[] erlObjs = estrs.elements();
List<String> strs = new LinkedList<String>();
for (OtpErlangObject erlO : erlObjs) {
strs.add(erlO.toString());
}
return strs;
}
Note that I used the term list here a lot, because it's in fact an Erlang list, in Java it's all represented as an array!
My entire code is listed below.
The way to run this is to paste it into a Java IDE, and start a REPL with the following parameters:
iex --name bob#127.0.0.1 --cookie "secret"
Java part:
import com.ericsson.otp.erlang.*;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
public class Main {
public static OtpErlangList StringListToErlangList(List<String> strs) {
OtpErlangObject[] elems = new OtpErlangObject[strs.size()];
int idx = 0;
for (String str : strs) {
elems[idx] = new OtpErlangString(str);
idx++;
}
return new OtpErlangList(elems);
}
public static List<String> ErlangListToStringList(OtpErlangList estrs) {
OtpErlangObject[] erlObjs = estrs.elements();
List<String> strs = new LinkedList<String>();
for (OtpErlangObject erlO : erlObjs) {
strs.add(erlO.toString());
}
return strs;
}
public static void main(String[] args) throws IOException, InterruptedException {
// Do some initial setup.
OtpNode node = new OtpNode("alice", "secret");
OtpMbox mbox = node.createMbox();
mbox.registerName("alice");
// Check that the remote node is actually online.
if (node.ping("bob#127.0.0.1", 2000)) {
System.out.println("remote is up");
} else {
System.out.println("remote is not up");
}
// Create the list of strings that needs to be sent to the other node.
List<String> strs = new LinkedList<String>();
strs.add("foo");
strs.add("bar");
OtpErlangList erlangStrs = StringListToErlangList(strs);
// Create a tuple so the other node can reply to use.
OtpErlangObject[] msg = new OtpErlangObject[2];
msg[0] = mbox.self();
msg[1] = erlangStrs;
OtpErlangTuple tuple = new OtpErlangTuple(msg);
// Send the tuple to the other node.
mbox.send("echo", "bob#127.0.0.1", tuple);
// Await the reply.
while (true) {
try {
System.out.println("Waiting for response!");
OtpErlangObject o = mbox.receive();
if (o instanceof OtpErlangList) {
OtpErlangList erlList = (OtpErlangList) o;
List<String> receivedStrings = ErlangListToStringList(erlList);
for (String s : receivedStrings) {
System.out.println(s);
}
}
if (o instanceof OtpErlangTuple) {
OtpErlangTuple m = (OtpErlangTuple) o;
OtpErlangPid from = (OtpErlangPid) (m.elementAt(0));
OtpErlangList value = (OtpErlangList) m.elementAt(1);
List<String> receivedStrings = ErlangListToStringList(value);
for (String s : receivedStrings) {
System.out.println(s);
}
}
} catch (OtpErlangExit otpErlangExit) {
otpErlangExit.printStackTrace();
} catch (OtpErlangDecodeException e) {
e.printStackTrace();
}
}
}
}
This is how my commands are set up:
public void onMessageReceived(MessageReceivedEvent evt) {
//Objects
User objUser = evt.getAuthor();
MessageChannel objMsgCh = evt.getChannel();
Message objMsg = evt.getMessage();
//Commands
if(objMsg.getContentRaw().equalsIgnoreCase(Ref.prefix+"say " + message))
{
StringBuilder message = new StringBuilder();
for(int i = 1; i < command.length; i++) {
if(i == command.length-1) {
message.append(command[i]);
}else {
message.append(command[i] + " ");
}
}
objMsgCh.sendMessage(message.toString()).queue();
objMsg.delete();
return;
}
}
It doesn't reply with anything and I don't understand why.
I am using JDA (Java Discord API).
Respect for your creativity but I think you are missing some basic java knowledge. Here is what I think you are aiming for:
public void onMessageReceived(MessageReceivedEvent event){
if(event.getMessage().getContentRaw().startsWith("!!say")){
event.getChannel().sendMessage(event.getMessage().getContentRaw().substring(6)).queue();
event.getMessage().delete().queue();
}
}
I think the if condition is logical. Get the Messages as String in raw format and looking for the string starting with "!!say". Then send a new Message to the channel where the message was received where the message is the raw message as the string with the first five characters (the "!!say") are cut off. So the Bot is repeating the whole message beside the command tag.
Hope this brings you forward in your mission.
I worked out how to do it.
public void onMessageReceived(MessageReceivedEvent evt) {
//Objects
User objUser = evt.getAuthor();
MessageChannel objMsgCh = evt.getChannel();
Message objMsg = evt.getMessage();
if(objMsg.getContentRaw().startsWith(Ref.prefix+"say"))
{
String words = objMsg.getContentRaw().substring(Ref.prefix.length() + 4);
String more_words = words;
objMsgCh.sendMessage(more_words).queue();
You don't really need String more_words = words;
And I do (Ref.prefix.length() + 4) so it says everything after !!say but make sure to make it create something like String prefix = "!!"; because my may not be able to it with the prefix in the if statement. The + 4 counts every just after the prefix and the space between user input.
For Example:
if(objMsg.getContentRaw().startsWith(Ref.prefix+"urban")) {
String query = objMsg.getContentRaw().substring(Ref.prefix.length() + 6);
Because "urban" has 5 characters you would put 6 to account for the space.
Hope that helps.
If you plan on using the JDA-Utilities the following code will work for creating a command.
public class sayCommand extends Command {
public sayCommand() {
this.help = "!say <message>";
this.aliases = new String[] {"!s"};
this.name = "say";
}
#Override
protected void execute(CommandEvent event) {
event.getChannel().sendMessage(event.getMessage().getContentDisplay().split("\\s+", 2)[1]).queue();
}
}
With only using one line, you could have the bot easily mimic your argument.
I'm working on gridsim project in Java eclipse. I have found a network flow program, which works only for one-to-one connection between the sender and receiver. If the same user (sender) wish to send a message to any other receiver, the program does not work. Similarly, if a receiver wish to send message to two sender users, it does not work. Here, I'm including all the java files for this work. In order to run the program, we need to include external .jar file path in the project. The gridsim.jar and simjava2.jar files can be downloaded from http://sourceforge.net/projects/gridsim/
The following are the programs. The main program is FlowNetEx01.java
package network.flow.example01;
import gridsim.*;
import gridsim.net.*;
import gridsim.net.flow.*;
import java.util.*;
// Test Driver class for this example
public class FlowNetEx01
{
// Creates main() to run this example
public static void main(String[] args)
{
System.out.println("Starting network example ...");
try
{
int num_user = 4; // number of grid users
Calendar calendar = Calendar.getInstance();
boolean trace_flag = false; // mean trace GridSim events
System.out.println("Initializing GridSim package");
// It is essential to set the network type before calling GridSim.init()
GridSim.initNetworkType(GridSimTags.NET_FLOW_LEVEL);
GridSim.init(num_user, calendar, trace_flag);
// In this example, the topology is:
// user(s) --10Mb/s-- r1 --1.5Mb/s-- r2 --10Mb/s-- GridResource(s)
Router r1 = new FlowRouter("router1", trace_flag); // router 1
Router r2 = new FlowRouter("router2", trace_flag); // router 2
String sender1 = "user1";
String receipient1 = "test1";
String sender2 = "user2";
String receipient2 = "test2";
// these entities are the senders
FlowNetUser user1 = new FlowNetUser(sender1, receipient2, 5.0);
FlowNetUser user2 = new FlowNetUser(sender2, receipient1, 20.0);
// these entities are the receipients
FlowTest test1 = new FlowTest(receipient1, sender2);
FlowTest test2 = new FlowTest(receipient2, sender1);
// The schedulers are redundent and will be stripped out soon
FIFOScheduler userSched1 = new FIFOScheduler("NetUserSched_0");
r1.attachHost(user1, userSched1);
FIFOScheduler userSched2 = new FIFOScheduler("NetUserSched_1");
r1.attachHost(user2, userSched2);
FIFOScheduler testSched1 = new FIFOScheduler("FlowTestSched_0");
r2.attachHost(test1, testSched1);
FIFOScheduler testSched2 = new FIFOScheduler("FlowTestSched_1");
r2.attachHost(test2, testSched2);
//////////////////////////////////////////
// Second step: Creates a physical link
double baud_rate = 1572864; // bits/sec (baud) [1.5Mb/s]
double propDelay = 300; // propagation delay in millisecond
int mtu = Integer.MAX_VALUE;; // max. transmission unit in byte
Link link = new FlowLink("r1_r2_link", baud_rate, propDelay, mtu);
FIFOScheduler r1Sched = new FIFOScheduler("r1_Sched");
FIFOScheduler r2Sched = new FIFOScheduler("r2_Sched");
r1.attachRouter(r2, link, r1Sched, r2Sched);
//////////////////////////////////////////
// Final step: Starts the simulation
GridSim.startGridSimulation();
System.out.println("\nFinish network example ...");
}
catch (Exception e)
{
e.printStackTrace();
System.err.print(e.toString());
System.out.println("Unwanted errors happen");
}
}
} // end class
Program-2:
package network.flow.example01;
import gridsim.*;
import gridsim.net.*;
import gridsim.net.flow.*;
import eduni.simjava.*;
import java.util.*;
public class FlowNetUser extends GridSim
{
private int myID_; // my entity ID
private String name_; // my entity name
private String destName_; // destination name
private int destID_; // destination id
private double wait_; // Delay until I begin sending
public static final int SEND_MSG = 1;
public static final int ACK_MSG = 2;
public FlowNetUser(String name, String destName, Link link, double wait) throws Exception
{
super(name, link);
// get this entity name from Sim_entity
this.name_ = super.get_name();
// get this entity ID from Sim_entity
this.myID_ = super.get_id();
// get the destination entity name
this.destName_ = destName;
// get the waiting time before sending
this.wait_ = wait;
}
public FlowNetUser(String name, String destName, double wait) throws Exception
{
// 10,485,760 baud = 10Mb/s
super(name, new FlowLink(name+"_link",10485760,450,Integer.MAX_VALUE));
// get this entity name from Sim_entity
this.name_ = super.get_name();
// get this entity ID from Sim_entity
this.myID_ = super.get_id();
// get the destination entity name
destName_ = destName;
// get the waiting time before sending
this.wait_ = wait;
}
public void body()
{
int packetSize = 524288000; // packet size in bytes [5MB]
//int packetSize = 52428800; // packet size in bytes [50MB]
//int packetSize = 524288000; // packet size in bytes [500MB]
//int packetSize = 5242880000; // packet size in bytes [5000MB]
int size = 3; // number of packets sent
int i = 0;
// get the destination entity ID
this.destID_ = GridSim.getEntityId(destName_);
//super.sim_pause(this.wait_);
this.gridSimHold(this.wait_);
// sends messages over the other side of the link
for (i = 0; i < size; i++)
{
String msg = "Message_" + i;
IO_data data = new IO_data(msg, packetSize, destID_);
System.out.println(name_ + ".body(): Sending " + msg +
", at time = " + GridSim.clock() );
// sends through Output buffer of this entity
super.send(super.output, GridSimTags.SCHEDULE_NOW,
GridSimTags.FLOW_SUBMIT, data);
//super.sim_pause();
super.sim_pause(10.0);
//this.gridSimHold((Math.random()*10)+1.0);
}
// get the ack back
Object obj = null;
for (i = 0; i < size; i++)
{
// waiting for incoming event in the Input buffer
obj = super.receiveEventObject();
System.out.println(name_ + ".body(): Receives Ack for " + obj);
}
// Wait for other FlowNetUser instances to finish
this.gridSimHold(1000.0);
super.send(destID_, GridSimTags.SCHEDULE_NOW,
GridSimTags.END_OF_SIMULATION);
// shut down I/O ports
shutdownUserEntity();
terminateIOEntities();
System.out.println(this.name_ + ":%%%% Exiting body() at time " +
GridSim.clock() );
}
} // end class
Program-3:
package network.flow.example01;
import java.util.*;
import gridsim.*;
import gridsim.net.*;
import gridsim.net.flow.*;
import gridsim.util.SimReport;
import eduni.simjava.*;
public class FlowTest extends GridSim
{
private int myID_; // my entity ID
private String name_; // my entity name
private String destName_; // destination name
private int destID_; // destination id
private SimReport report_; // logs every activity
public FlowTest(String name, String destName, Link link) throws Exception
{
super(name, link);
// get this entity name from Sim_entity
this.name_ = super.get_name();
// get this entity ID from Sim_entity
this.myID_ = super.get_id();
// get the destination entity name
this.destName_ = destName;
// logs every activity. It will automatically create name.csv file
report_ = new SimReport(name);
report_.write("Creates " + name);
}
public FlowTest(String name, String destName) throws Exception
{
// 10,485,760 baud = 10Mb/s
super(name, new FlowLink(name+"_link",10485760,250,Integer.MAX_VALUE));
// get this entity name from Sim_entity
this.name_ = super.get_name();
// get this entity ID from Sim_entity
this.myID_ = super.get_id();
// get the destination entity name
this.destName_ = destName;
// logs every activity. It will automatically create name.csv file
report_ = new SimReport(name);
report_.write("Creates " + name);
}
public void body()
{
// get the destination entity ID
this.destID_ = GridSim.getEntityId(destName_);
int packetSize = 1500; // packet size in bytes
Sim_event ev = new Sim_event(); // an event
// a loop waiting for incoming events
while ( Sim_system.running() )
{
// get the next event from the Input buffer
super.sim_get_next(ev);
// if an event denotes end of simulation
if (ev.get_tag() == GridSimTags.END_OF_SIMULATION)
{
System.out.println();
write(super.get_name() + ".body(): exiting ...");
break;
}
// if an event denotes another event type
else if (ev.get_tag() == GridSimTags.FLOW_SUBMIT)
{
System.out.println();
write(super.get_name() + ".body(): receive " +
ev.get_data() + ", at time = " + GridSim.clock());
// No need for an ack, it is handled in FlowBuffer now on our behalf
// sends back an ack
IO_data data = new IO_data(ev.get_data(), packetSize, destID_);
write(name_ + ".body(): Sending back " +
ev.get_data() + ", at time = " + GridSim.clock() );
// sends through Output buffer of this entity
super.send(super.output, GridSimTags.SCHEDULE_NOW,
GridSimTags.FLOW_ACK, data);
}
else if (ev.get_tag() == GridSimTags.INFOPKT_SUBMIT)
{
processPingRequest(ev);
}
}
// shut down I/O ports
shutdownUserEntity();
terminateIOEntities();
// don't forget to close the file
if (report_ != null) {
report_.finalWrite();
}
System.out.println(this.name_ + ":%%%% Exiting body() at time " +
GridSim.clock() );
}
private void processPingRequest(Sim_event ev)
{
InfoPacket pkt = (InfoPacket) ev.get_data();
pkt.setTag(GridSimTags.INFOPKT_RETURN);
pkt.setDestID( pkt.getSrcID() );
// sends back to the sender
super.send(super.output, GridSimTags.SCHEDULE_NOW,
GridSimTags.INFOPKT_RETURN,
new IO_data(pkt,pkt.getSize(),pkt.getSrcID()) );
}
private void write(String msg)
{
System.out.println(msg);
if (report_ != null) {
report_.write(msg);
}
}
} // end class
After running these programs, someone can tell us how to extend the required functionality as I mentioned in the beginning.
Personal experience ... GridSim5.2 potentially buggy.
The examples are dated written for version < 4.0, demonstrating not very complex scenarios.
Using version 5.2. According to the API docs every simulation should have at least one TopRegionalRC. This appends a UniqueID to the filename and records the location of the file in two hashmaps one for filename and the other for fileattr. Now the event filename used for the lookup remains unchanged - the lookup fails - compares to the fileattrmap.name_. Consequently, the waiting for ack block is never executed when performing a addmaster operation.
Fix: Since the UniqueId is returned by the initial request to the CTLG this can be appended to the filename for the subsequent event requiring the lookup. Alternatively, add the filename to fileattrmap and the filename+uniqueid to fileattrmap, then test for both in the lookup.
Also, GridSimTags uses -1 to signal END_OF_SIMULATION, but this conflicts with Advanced Reservation (AR) block of tags. That also use negative numbers. GridSimTags has an optional routine to check for duplicates but its use is optional and does not apply to DataGridTags. I created a reversemap for ease of debugging adding validation to ensure no duplicates occur and deprecated the GridSimTags method.
I am now wrestling with the DataGrid user tasks that do not seem to create events, I am also concerned that the delay operations are not effective.
I am trying to send protobuf data from cpp side to java side.
I have multiple message types defined in .proto
On Cpp side, I have enums for every message type and I am adding it to the buf output as follows:
uint8_t* __temp = (uint8_t*)(buf);
*__temp++ = (type) >> 8;
*__temp = (type) & 0x00FF;
How do I get this 'type' that I have added to the buf, so that I can achieve something like
MessageType parseFrom(byte[] data);
It is not clear what is the exact requirement. But I assume you are trying to send different types of messages and the the receiver should be able to parse the correct object out of the received bytes. This can be done as shown in the example below:
message Message1 {
required string a = 1;
required string b = 2;
}
message Message2 {
required int64 id = 1;
required string data = 2;
}
message WrapperMessage {
required int64 commonField = 1;
oneof msg {
Message1 m1 = 2;
Message2 m2 = 3;
}
}
Basically, always WrapperMessage object is sent over the wire which wraps a Message1 or Message2 object.
Then on the receiving side we may parse the WrapperMessage object first and then use HasField method to check if m1 or m2 fields is present in the wrapped object and then parse the Message1 or Message2 object out of it.
"oneof" feature may not be available on older version of protobuf compiler.
Protobuf 3 introduced a new concept, Any, that handles this. A good description can be found here.
Below is the example code for reading and writing with ANY type in Proto 3. Used Bigtable for read and write examples.
public void writeToBigtable(Item item){
try {
RowMutation rowMutation = RowMutation.create("item", String.join("#", item.getHqLine(), item.getPartNo()))
.setCell("item-info-cf", ByteString.copyFromUtf8("item-info-proto"), ByteString.copyFrom(**Any.pack(item).toByteArray()**));
bigtableDataClient.mutateRow(rowMutation);
} catch (RuntimeException exception){
log.error("Error occurred while inserting data into DB");
}
}
public Set<Item> readFromBigtable(String rowKey){
Row row = bigtableDataClient.readRow("item",rowKey,FILTERS.chain().filter(FILTERS.limit().cellsPerColumn(1)));
return row.getCells("item-info-cf", ByteString.copyFromUtf8("item-info-proto"))
.stream()
.map(rowCell->{
Item item = null;
try {
Any any = **Any.parseFrom(rowCell.getValue().toByteArray()**);
if(any.is(Item.class)) {
item = any.unpack(Item.class);
}
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
return item;
}).collect(Collectors.toSet());
}