I am developing a Client-Server-application which uses Google Protocol Buffers.
Unfortunatelly when I am building the protocol buffer response on the server side using the builder pattern I get a IndexOutOfBoundsException:
This is the line where I build the protobuf file:
Builder getVGResonseBuilder = App_getVGResponse.GetVGResponse.newBuilder().getVGBuilder(0);
[some more code that uses the builder patterns]
getVGResponseBuilder.set...
getVGResponseBuilder.set...
the error occures in the first line of code.
here is the protobuf definition (ofc I have compiled it! The compiled calss is App_getVGResponse):
message GetVGResponse {
message VG {
optional string id = 1;
optional string g_id = 2;
optional int64 f_id = 3;
optional string g_name = 4;
}
repeated VG v_gp = 1;
}
Here is a excerpt of my stacktrace
Exception in thread "main" com.google.protobuf.InvalidProtocolBufferException: **Protocol message tag had invalid wire type.**
at com.google.protobuf.InvalidProtocolBufferException.invalidWireType(InvalidProtocolBufferException.java:78)
at com.google.protobuf.UnknownFieldSet$Builder.mergeFieldFrom(UnknownFieldSet.java:498)
at com.google.protobuf.GeneratedMessage$Builder.parseUnknownField(GeneratedMessage.java:439)
and the debugger at runtime shows ma the variable:
e
-> cause: IndexOutOfBoundsException (id=12291)
-> detaiMessage: Index: 0, Size: 0 (id=12324)
-> stackTrace null
personally I create the "child builder" then add it to the parent builder. i.e.
App_GetVGResponse.GetVGResponse.Builder bldr = App_GetVGResponse.GetVGResponse.newBuilder();
App_GetVGResponse.GetVGResponse.VG.Builder childBldr = App_GetVGResponse.GetVGResponse.VG.newBuilder();
childBldr.setId(value);
...........
bldr.addVGp(childBldr);
I think the error is because you get the "child" builder before adding one
Related
I am setting the Correlation ID while sending the message to MQ. And I need to use the CorrelationID from the COA of the message I pushed for the further processing.
I am setting the correlation ID and sending the message to queue using the below code.
MQMessage message = createMQMessage("12345");
message.write("Some message to push".getBytes());
queue.put(message);
private MQMessage createMQMessage(String corrID){
MQMessage message = new MQMessage();
message.messageFlags = MQConstants.MQMF_SEGMENTATION_ALLOWED;
if (ackQueueName != null) {
message.messageType = MQConstants.MQMT_REQUEST;
message.replyToQueueManagerName = ackQueueManagerName;
message.replyToQueueName = ackQueueName;
message.report = MQConstants.MQRO_COA | MQConstants.MQRO_COD;
message.correlationId = corrID.getBytes();
}
return message;
}
I am reading the replyQueue from another application to get the COA and extract the correlation ID for further processing.
But the correlation ID is in byte[] format and I used the below method getHexString to get the string. But all I got is 48 digit Hex format of my correlation ID like
414d5120514d41444556202020202020b5ca0d5b13b3bb20
public static String getHexString(byte[] b) throws Exception {
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
All I need is the approach to convert the 48digit HexString to the Original Correlation ID I set. I tried using the below method to convert, but its giving me the junk data.
public static String hexStringToByteArray(String hex) {
int l = hex.length();
byte[] data = new byte[l/2];
for (int i = 0; i < l; i += 2) {
data[i/2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+ Character.digit(hex.charAt(i+1), 16));
}
return new String(data);
}
Your report options are not explicitly set.
MQRO_COPY_MSG_ID_TO_CORREL_ID This is the default action, and
indicates that if a report or reply is generated as a result of this
message, the MsgId of this message is copied to the CorrelId of the
report or reply message.
Because of the default action, you will never receive the initial Correlation ID of your message. As Roger mentioned in his answer, it is bad practice to set the MsgID programmatically. Simply use the following option to have the CorrelID copied to the report message:
MQRO_PASS_CORREL_ID If a report or reply is generated as a result of
this message, the CorrelId of this message is copied to the CorrelId
of the report or reply message.
message.report = MQConstants.MQRO_COA
| MQConstants.MQRO_COD
| MQConstants.MQRO_PASS_CORREL_ID;
I set the message ID myself, now I am getting it fine
Do NOT set the message's messageId yourself. Let the queue manager create a unique messageId for each message that is put to a queue. If you need to pass information along with the message either (1) put it in the message data/payload or (2) add a Message Property (aka Named Property) to the message.
If you create your own messageId then there is a chance of duplicate messageIds which is a very bad thing and goes against Best Practices. IBM MQ Best Practices says to let the queue manager create a unique messageId.
I took the sample word-count code and tried to submit to a remote nimbus server without submitting to LocalCluster.I used the following code in client side and the following yaml configuration the server and ZK is started separately.
When I submit using the below code in the client side I get the following error, when I ran the ./storm jar file/path/jar-file.jar
ut.pending":5000,"storm.zookeeper.servers":"149.160.221.43","topology.max.task.parallelism":3}
308 [main] WARN backtype.storm.StormSubmitter - Topology submission exception: Field storm.zookeeper.servers must be an Iterable of java.lang.String
Exception in thread "main" InvalidTopologyException(msg:Field storm.zookeeper.servers must be an Iterable of java.lang.String)
at backtype.storm.generated.Nimbus$submitTopology_result.read(Nimbus.java:2466)
at org.apache.thrift7.TServiceClient.receiveBase(TServiceClient.java:78)
at backtype.storm.generated.Nimbus$Client.recv_submitTopology(Nimbus.java:162)
at backtype.storm.generated.Nimbus$Client.submitTopology(Nimbus.java:146)
at backtype.storm.StormSubmitter.submitTopology(StormSubmitter.java:98)
at backtype.storm.StormSubmitter.submitTopology(StormSubmitter.java:58)
at storm.starter.WordCountTopology.main(WordCountTopology.java:110)
Topology building code:
System.setProperty("storm.jar","/Users/lginnali/work/airavata/storm/storm/examples/storm-starter/target/storm-starter-0.10.0-SNAPSHOT.jar");
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("spout", new RandomSentenceSpout(), 5);
BoltDeclarer split = builder.setBolt("split", new SplitSentence(), 8);
split.shuffleGrouping("spout");
builder.setBolt("count", new WordCount(), 12).fieldsGrouping("split", new Fields("word"));
Config conf = new Config();
conf.put(Config.NIMBUS_HOST, "localhost");
conf.put(Config.NIMBUS_THRIFT_PORT,6627);
conf.put(Config.STORM_ZOOKEEPER_PORT,2181);
conf.put(Config.STORM_ZOOKEEPER_SERVERS,"localhost");
conf.setNumWorkers(20);
conf.setMaxSpoutPending(5000);
if (args != null && args.length > 0) {
conf.setNumWorkers(3);
StormSubmitter.submitTopologyWithProgressBar(args[0], conf, builder.createTopology());
}
sample storm.yaml looks like this file.
https://github.com/apache/storm/blob/master/conf/defaults.yaml
Exactly what the exception says: Config.STORM_ZOOKEEPER_SERVERS should be an iterable of strings, and not a string. So try replacing
conf.put(Config.STORM_ZOOKEEPER_SERVERS,"localhost");
with
conf.put(Config.STORM_ZOOKEEPER_SERVERS, Arrays.asList(new String[]{"localhost"}));
The problem can be due to the error in storm.yaml file, Make sure the entry corresponding to storm.zookeeper.server is in the format given below:
storm.zookeeper.server:
(space)-(space)"ip-address" .i.e there should be a space between hyphen and ip-address as well as from the start of new line.
So when an error occurred during runtime, the log always show a link to the specific error and you can click on it to be taken there directly.
I'm looking to exploit this function for my own use (since finding where the log is generated across multiple files can be a pain). Of course you can just put the source in the log key but if I'm able to link it just the way Android Studio / Intellij IDEAS does it with the error output, that would be MASSIVELY helpful. Thanks.
The following code will be a work-around to print the logged function name and line number (in Java):
private static String _FUNC_() {
int STACK_LEVEL = 2;
StackTraceElement traceElement = ((new Exception()).getStackTrace())[STACK_LEVEL];
StringBuilder sb = new StringBuilder();
sb.append("<");
String className = traceElement.getClassName();
className = className.substring(className.lastIndexOf(".") + 1);
sb.append(className);
sb.append(":");
sb.append(traceElement.getMethodName());
sb.append(":");
sb.append(traceElement.getLineNumber());
sb.append("> ");
return sb.toString();
}
Been stumped on this for a while and pulling what is left of my hair out.
Sending non-nested Protobufs from Python to Java and Java to Python without
an issue with WebSockets. My problem is sending a nested version over a WebSocket. I believe my issue is on
the Python encoding side.
Your guidance is appreciated.
.proto file
message Response {
// Reflect back to caller
required string service_name = 1;
// Reflect back to caller
required string method_name = 2;
// Who is responding
required string client_id = 3;
// Status Code
required StatusCd status_cd = 4;
// RPC response proto
optional bytes response_proto = 5;
// Was callback invoked
optional bool callback = 6 [default = false];
// Error, if any
optional string error = 7;
//optional string response_desc = 6;
}
message HeartbeatResult {
required string service = 1;
required string timestamp = 2;
required float status_cd = 3;
required string status_summary = 4;
}
A Heartbeat result is supposed to get sent in the reponse_proto field
of the Response Protobuf. I am able to do this in Java to Java but Python
to Java is not working.
I've included two variations of the python code. Neither of which works.
def GetHeartbeat(self):
print "GetHeartbeat called"
import time
ts = time.time()
import datetime
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
heartbeatResult = rpc_pb2.HeartbeatResult()
heartbeatResult.service = "ALERT_SERVICE"
heartbeatResult.timestamp = st
heartbeatResult.status_cd = rpc_pb2.OK
heartbeatResult.status_summary = "OK"
response = rpc_pb2.Response()
response.service_name = ""
response.method_name = "SendHeartbeatResult"
response.client_id = "ALERT_SERVICE"
response.status_cd = rpc_pb2.OK
response.response_proto = str(heartbeatResult).encode('utf-8')
self.sendMessage(response.SerializeToString())
print "GetHeartbeat finished"
def GetHeartbeat2(self):
print "GetHeartbeat called"
import time
ts = time.time()
import datetime
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
heartbeatResult = rpc_pb2.HeartbeatResult()
heartbeatResult.service = "ALERT_SERVICE"
heartbeatResult.timestamp = st
heartbeatResult.status_cd = rpc_pb2.OK
heartbeatResult.status_summary = "OK"
response = rpc_pb2.Response()
response.service_name = ""
response.method_name = "SendHeartbeatResult"
response.client_id = "ALERT_SERVICE"
response.status_cd = rpc_pb2.OK
response.response_proto = heartbeatResult.SerializeToString()
self.sendMessage(response.SerializeToString())
print "GetHeartbeat finished"
Errors on the Java server side are:
(GetHeartbeat) Protocol message end-group tag did not match expected tag
and
(GetHeartbeat2)
Message: [org.java_websocket.exceptions.InvalidDataException: java.nio.charset.MalformedInputException: Input length = 1
at org.java_websocket.util.Charsetfunctions.stringUtf8(Charsetfunctions.java:80)
at org.java_websocket.WebSocketImpl.deliverMessage(WebSocketImpl.java:561)
at org.java_websocket.WebSocketImpl.decodeFrames(WebSocketImpl.java:328)
at org.java_websocket.WebSocketImpl.decode(WebSocketImpl.java:149)
at org.java_websocket.server.WebSocketServer$WebSocketWorker.run(WebSocketServer.java:593)
Caused by: java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:277)
at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:798)
at org.java_websocket.util.Charsetfunctions.stringUtf8(Charsetfunctions.java:77)
Solution
Also posted this question on protobuf group
Credit to Christopher Head and Ilia Mirkin for providing input on the google group
https://groups.google.com/forum/#!topic/protobuf/Cp7zWiWok9I
response.response_proto = base64.b64encode(heartbeatResult.SerializeToString())
self.sendMessage(response.SerializeToString())
FYI, Ilia also suggested base64 encoding the entire message but this seems to be working at the moment.
I am getting following exception when trying to run my command line application:
java.lang.ExceptionInInitializerError
at org.hibernate.validator.engine.ConfigurationImpl.<clinit>(ConfigurationImpl.java:52)
at org.hibernate.validator.HibernateValidator.createGenericConfiguration(HibernateValidator.java:43)
at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:269)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -2
at java.lang.String.substring(String.java:1937)
at org.hibernate.validator.util.Version.<clinit>(Version.java:39)
... 34 more
Am I doing anything wrong? Please suggest.
This is strange. I pasted the relevant parts of the static initialization block of o.h.v.u.Version in a class with a main and added some poor man's logging traces:
public class VersionTest {
public static void main(String[] args) {
Class clazz = org.hibernate.validator.util.Version.class;
String classFileName = clazz.getSimpleName() + ".class";
System.out.println(String.format("%-16s: %s", "classFileName", classFileName));
String classFilePath = clazz.getCanonicalName().replace('.', '/') + ".class";
System.out.println(String.format("%-16s: %s", "classFilePath", classFilePath));
String pathToThisClass = clazz.getResource(classFileName).toString();
System.out.println(String.format("%-16s: %s", "pathToThisClass", pathToThisClass));
// This is line 39 of `org.hibernate.validator.util.Version`
String pathToManifest = pathToThisClass.substring(0, pathToThisClass.indexOf(classFilePath) - 1)
+ "/META-INF/MANIFEST.MF";
System.out.println(String.format("%-16s: %s", "pathToManifest", pathToManifest));
}
}
And here the output I get when running it:
classFileName : Version.class
classFilePath : org/hibernate/validator/util/Version.class
pathToThisClass : jar:file:/home/pascal/.m2/repository/org/hibernate/hibernate-validator/4.0.2.GA/hibernate-validator-4.0.2.GA.jar!/org/hibernate/validator/util/Version.class
pathToManifest : jar:file:/home/pascal/.m2/repository/org/hibernate/hibernate-validator/4.0.2.GA/hibernate-validator-4.0.2.GA.jar!/META-INF/MANIFEST.MF
In your case, the StringIndexOutOfBoundsException: String index out of range: -2 suggests that:
pathToThisClass.indexOf( classFilePath )
is returning -1, making the pathToThisClass.substring(0, -2) call indeed erroneous.
And this means that org/hibernate/validator/util/Version.class is somehow not part of the pathToThisClass that you get. I don't have a full explanation but this must be related to the fact that you're using One-Jar.
Could you run the above test class and update your question with the output?
So, as you use One-JAR, the problem probably is in incompatibility between One-JAR and Hibernate Validator. However, in the latest version of One-JAR (0.97) it works fine, therefore use the latest version.