diff --git a/activemq-protobuf-test/pom.xml b/activemq-protobuf-test/pom.xml
new file mode 100644
index 0000000000..7db54ebfaa
--- /dev/null
+++ b/activemq-protobuf-test/pom.xml
@@ -0,0 +1,80 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.activemq
+ activemq-parent
+ 6.1.3-SNAPSHOT
+
+
+ org.apache.activemq.protobuf
+ activemq-protobuf-test
+
+ jar
+ ActiveMQ :: Protocol Buffers Tests
+
+
+
+ junit
+ junit
+ test
+
+
+ org.apache.activemq.protobuf
+ activemq-protobuf
+ ${project.version}
+
+
+
+
+
+
+
+ org.apache.activemq.protobuf
+ activemq-protobuf
+ ${project.version}
+
+
+
+
+
+ maven-surefire-plugin
+
+
+ **/*Test.java
+
+
+
+
+ org.apache.activemq.protobuf
+ activemq-protobuf
+ ${project.version}
+
+
+
+ compile
+
+
+
+
+
+
+
+
diff --git a/activemq-protobuf-test/src/main/proto/deferred_decode.proto b/activemq-protobuf-test/src/main/proto/deferred_decode.proto
new file mode 100644
index 0000000000..2535c48060
--- /dev/null
+++ b/activemq-protobuf-test/src/main/proto/deferred_decode.proto
@@ -0,0 +1,40 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You 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.apache.activemq.protobuf;
+option java_outer_classname = "DeferredUnmarshal";
+option deferred_decode = true;
+
+message Foo {
+
+ optional int32 field1 = 1;
+ optional int64 field2 = 2;
+
+}
+
+
+message Bar {
+ option base_type=Foo;
+
+ // These are the Foo fields.
+ optional int32 field1 = 1;
+ optional int64 field2 = 2;
+
+ optional Foo field3 = 3;
+
+}
+
diff --git a/activemq-protobuf-test/src/main/proto/multiple_files_test.proto b/activemq-protobuf-test/src/main/proto/multiple_files_test.proto
new file mode 100644
index 0000000000..fd2a961956
--- /dev/null
+++ b/activemq-protobuf-test/src/main/proto/multiple_files_test.proto
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// A proto file which tests the java_multiple_files option.
+
+
+import "unittest.proto";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "MultipleFilesTestProto";
+
+message MessageWithNoOuter {
+ message NestedMessage {
+ optional int32 i = 1;
+ }
+ enum NestedEnum {
+ BAZ = 3;
+ }
+ optional NestedMessage nested = 1;
+ repeated TestAllTypes foreign = 2;
+ optional NestedEnum nested_enum = 3;
+ optional EnumWithNoOuter foreign_enum = 4;
+}
+
+enum EnumWithNoOuter {
+ FOO = 1;
+ BAR = 2;
+}
+
+service ServiceWithNoOuter {
+ rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
+}
+
+extend TestAllExtensions {
+ optional int32 extension_with_outer = 1234567;
+}
diff --git a/activemq-protobuf-test/src/main/proto/unittest.proto b/activemq-protobuf-test/src/main/proto/unittest.proto
new file mode 100644
index 0000000000..a9b9d945b6
--- /dev/null
+++ b/activemq-protobuf-test/src/main/proto/unittest.proto
@@ -0,0 +1,452 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file we will use for unit testing.
+
+
+import "unittest_import.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Protos optimized for SPEED use a strict superset of the generated code
+// of equivalent ones optimized for CODE_SIZE, so we should optimize all our
+// tests for speed unless explicitly testing code size optimization.
+option optimize_for = SPEED;
+
+option java_outer_classname = "UnittestProto";
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+ message NestedMessage {
+ // The field name "b" fails to compile in proto1 because it conflicts with
+ // a local variable named "b" in one of the generated methods. Doh.
+ // This file needs to compile in proto1 to test backwards-compatibility.
+ optional int32 bb = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ // Singular
+ optional int32 optional_int32 = 1;
+ optional int64 optional_int64 = 2;
+ optional uint32 optional_uint32 = 3;
+ optional uint64 optional_uint64 = 4;
+ optional sint32 optional_sint32 = 5;
+ optional sint64 optional_sint64 = 6;
+ optional fixed32 optional_fixed32 = 7;
+ optional fixed64 optional_fixed64 = 8;
+ optional sfixed32 optional_sfixed32 = 9;
+ optional sfixed64 optional_sfixed64 = 10;
+ optional float optional_float = 11;
+ optional double optional_double = 12;
+ optional bool optional_bool = 13;
+ optional string optional_string = 14;
+ optional bytes optional_bytes = 15;
+
+ optional group OptionalGroup = 16 {
+ optional int32 a = 17;
+ }
+
+ optional NestedMessage optional_nested_message = 18;
+ optional ForeignMessage optional_foreign_message = 19;
+ optional protobuf_unittest_import.ImportMessage optional_import_message = 20;
+
+ optional NestedEnum optional_nested_enum = 21;
+ optional ForeignEnum optional_foreign_enum = 22;
+ optional protobuf_unittest_import.ImportEnum optional_import_enum = 23;
+
+ optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+ optional string optional_cord = 25 [ctype=CORD];
+
+ // Repeated
+ repeated int32 repeated_int32 = 31;
+ repeated int64 repeated_int64 = 32;
+ repeated uint32 repeated_uint32 = 33;
+ repeated uint64 repeated_uint64 = 34;
+ repeated sint32 repeated_sint32 = 35;
+ repeated sint64 repeated_sint64 = 36;
+ repeated fixed32 repeated_fixed32 = 37;
+ repeated fixed64 repeated_fixed64 = 38;
+ repeated sfixed32 repeated_sfixed32 = 39;
+ repeated sfixed64 repeated_sfixed64 = 40;
+ repeated float repeated_float = 41;
+ repeated double repeated_double = 42;
+ repeated bool repeated_bool = 43;
+ repeated string repeated_string = 44;
+ repeated bytes repeated_bytes = 45;
+
+ repeated group RepeatedGroup = 46 {
+ optional int32 a = 47;
+ }
+
+ repeated NestedMessage repeated_nested_message = 48;
+ repeated ForeignMessage repeated_foreign_message = 49;
+ repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50;
+
+ repeated NestedEnum repeated_nested_enum = 51;
+ repeated ForeignEnum repeated_foreign_enum = 52;
+ repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53;
+
+ repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+ repeated string repeated_cord = 55 [ctype=CORD];
+
+ // Singular with defaults
+ optional int32 default_int32 = 61 [default = 41 ];
+ optional int64 default_int64 = 62 [default = 42 ];
+ optional uint32 default_uint32 = 63 [default = 43 ];
+ optional uint64 default_uint64 = 64 [default = 44 ];
+ optional sint32 default_sint32 = 65 [default = -45 ];
+ optional sint64 default_sint64 = 66 [default = 46 ];
+ optional fixed32 default_fixed32 = 67 [default = 47 ];
+ optional fixed64 default_fixed64 = 68 [default = 48 ];
+ optional sfixed32 default_sfixed32 = 69 [default = 49 ];
+ optional sfixed64 default_sfixed64 = 70 [default = -50 ];
+ optional float default_float = 71 [default = 51.5 ];
+ optional double default_double = 72 [default = 52e3 ];
+ optional bool default_bool = 73 [default = true ];
+ optional string default_string = 74 [default = "hello"];
+ optional bytes default_bytes = 75 [default = "world"];
+
+ optional NestedEnum default_nested_enum = 81 [default = BAR ];
+ optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR];
+ optional protobuf_unittest_import.ImportEnum
+ default_import_enum = 83 [default = IMPORT_BAR];
+
+ optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+ optional string default_cord = 85 [ctype=CORD,default="123"];
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+ optional int32 c = 1;
+}
+
+enum ForeignEnum {
+ FOREIGN_FOO = 4;
+ FOREIGN_BAR = 5;
+ FOREIGN_BAZ = 6;
+}
+
+message TestAllExtensions {
+ extensions 1 to max;
+}
+
+extend TestAllExtensions {
+ // Singular
+ optional int32 optional_int32_extension = 1;
+ optional int64 optional_int64_extension = 2;
+ optional uint32 optional_uint32_extension = 3;
+ optional uint64 optional_uint64_extension = 4;
+ optional sint32 optional_sint32_extension = 5;
+ optional sint64 optional_sint64_extension = 6;
+ optional fixed32 optional_fixed32_extension = 7;
+ optional fixed64 optional_fixed64_extension = 8;
+ optional sfixed32 optional_sfixed32_extension = 9;
+ optional sfixed64 optional_sfixed64_extension = 10;
+ optional float optional_float_extension = 11;
+ optional double optional_double_extension = 12;
+ optional bool optional_bool_extension = 13;
+ optional string optional_string_extension = 14;
+ optional bytes optional_bytes_extension = 15;
+
+ optional group OptionalGroup_extension = 16 {
+ optional int32 a = 17;
+ }
+
+ optional TestAllTypes.NestedMessage optional_nested_message_extension = 18;
+ optional ForeignMessage optional_foreign_message_extension = 19;
+ optional protobuf_unittest_import.ImportMessage
+ optional_import_message_extension = 20;
+
+ optional TestAllTypes.NestedEnum optional_nested_enum_extension = 21;
+ optional ForeignEnum optional_foreign_enum_extension = 22;
+ optional protobuf_unittest_import.ImportEnum
+ optional_import_enum_extension = 23;
+
+ optional string optional_string_piece_extension = 24 [ctype=STRING_PIECE];
+ optional string optional_cord_extension = 25 [ctype=CORD];
+
+ // Repeated
+ repeated int32 repeated_int32_extension = 31;
+ repeated int64 repeated_int64_extension = 32;
+ repeated uint32 repeated_uint32_extension = 33;
+ repeated uint64 repeated_uint64_extension = 34;
+ repeated sint32 repeated_sint32_extension = 35;
+ repeated sint64 repeated_sint64_extension = 36;
+ repeated fixed32 repeated_fixed32_extension = 37;
+ repeated fixed64 repeated_fixed64_extension = 38;
+ repeated sfixed32 repeated_sfixed32_extension = 39;
+ repeated sfixed64 repeated_sfixed64_extension = 40;
+ repeated float repeated_float_extension = 41;
+ repeated double repeated_double_extension = 42;
+ repeated bool repeated_bool_extension = 43;
+ repeated string repeated_string_extension = 44;
+ repeated bytes repeated_bytes_extension = 45;
+
+ repeated group RepeatedGroup_extension = 46 {
+ optional int32 a = 47;
+ }
+
+ repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 48;
+ repeated ForeignMessage repeated_foreign_message_extension = 49;
+ repeated protobuf_unittest_import.ImportMessage
+ repeated_import_message_extension = 50;
+
+ repeated TestAllTypes.NestedEnum repeated_nested_enum_extension = 51;
+ repeated ForeignEnum repeated_foreign_enum_extension = 52;
+ repeated protobuf_unittest_import.ImportEnum
+ repeated_import_enum_extension = 53;
+
+ repeated string repeated_string_piece_extension = 54 [ctype=STRING_PIECE];
+ repeated string repeated_cord_extension = 55 [ctype=CORD];
+
+ // Singular with defaults
+ optional int32 default_int32_extension = 61 [default = 41 ];
+ optional int64 default_int64_extension = 62 [default = 42 ];
+ optional uint32 default_uint32_extension = 63 [default = 43 ];
+ optional uint64 default_uint64_extension = 64 [default = 44 ];
+ optional sint32 default_sint32_extension = 65 [default = -45 ];
+ optional sint64 default_sint64_extension = 66 [default = 46 ];
+ optional fixed32 default_fixed32_extension = 67 [default = 47 ];
+ optional fixed64 default_fixed64_extension = 68 [default = 48 ];
+ optional sfixed32 default_sfixed32_extension = 69 [default = 49 ];
+ optional sfixed64 default_sfixed64_extension = 70 [default = -50 ];
+ optional float default_float_extension = 71 [default = 51.5 ];
+ optional double default_double_extension = 72 [default = 52e3 ];
+ optional bool default_bool_extension = 73 [default = true ];
+ optional string default_string_extension = 74 [default = "hello"];
+ optional bytes default_bytes_extension = 75 [default = "world"];
+
+ optional TestAllTypes.NestedEnum
+ default_nested_enum_extension = 81 [default = BAR];
+ optional ForeignEnum
+ default_foreign_enum_extension = 82 [default = FOREIGN_BAR];
+ optional protobuf_unittest_import.ImportEnum
+ default_import_enum_extension = 83 [default = IMPORT_BAR];
+
+ optional string default_string_piece_extension = 84 [ctype=STRING_PIECE,
+ default="abc"];
+ optional string default_cord_extension = 85 [ctype=CORD, default="123"];
+}
+
+// We have separate messages for testing required fields because it's
+// annoying to have to fill in required fields in TestProto in order to
+// do anything with it. Note that we don't need to test every type of
+// required filed because the code output is basically identical to
+// optional fields for all types.
+message TestRequired {
+ required int32 a = 1;
+ optional int32 dummy2 = 2;
+ required int32 b = 3;
+
+ extend TestAllExtensions {
+ optional TestRequired single = 1000;
+ repeated TestRequired multi = 1001;
+ }
+
+ // Pad the field count to 32 so that we can test that IsInitialized()
+ // properly checks multiple elements of has_bits_.
+ optional int32 dummy4 = 4;
+ optional int32 dummy5 = 5;
+ optional int32 dummy6 = 6;
+ optional int32 dummy7 = 7;
+ optional int32 dummy8 = 8;
+ optional int32 dummy9 = 9;
+ optional int32 dummy10 = 10;
+ optional int32 dummy11 = 11;
+ optional int32 dummy12 = 12;
+ optional int32 dummy13 = 13;
+ optional int32 dummy14 = 14;
+ optional int32 dummy15 = 15;
+ optional int32 dummy16 = 16;
+ optional int32 dummy17 = 17;
+ optional int32 dummy18 = 18;
+ optional int32 dummy19 = 19;
+ optional int32 dummy20 = 20;
+ optional int32 dummy21 = 21;
+ optional int32 dummy22 = 22;
+ optional int32 dummy23 = 23;
+ optional int32 dummy24 = 24;
+ optional int32 dummy25 = 25;
+ optional int32 dummy26 = 26;
+ optional int32 dummy27 = 27;
+ optional int32 dummy28 = 28;
+ optional int32 dummy29 = 29;
+ optional int32 dummy30 = 30;
+ optional int32 dummy31 = 31;
+ optional int32 dummy32 = 32;
+
+ required int32 c = 33;
+}
+
+message TestRequiredForeign {
+ optional TestRequired optional_message = 1;
+ repeated TestRequired repeated_message = 2;
+ optional int32 dummy = 3;
+}
+
+// Test that we can use NestedMessage from outside TestAllTypes.
+message TestForeignNested {
+ optional TestAllTypes.NestedMessage foreign_nested = 1;
+}
+
+// TestEmptyMessage is used to test unknown field support.
+message TestEmptyMessage {
+}
+
+// Like above, but declare all field numbers as potential extensions. No
+// actual extensions should ever be defined for this type.
+message TestEmptyMessageWithExtensions {
+ extensions 1 to max;
+}
+
+// Test that really large tag numbers don't break anything.
+message TestReallyLargeTagNumber {
+ // The largest possible tag number is 2^28 - 1, since the wire format uses
+ // three bits to communicate wire type.
+ optional int32 a = 1;
+ optional int32 bb = 268435455;
+}
+
+message TestRecursiveMessage {
+ optional TestRecursiveMessage a = 1;
+ optional int32 i = 2;
+}
+
+// Test that mutual recursion works.
+message TestMutualRecursionA {
+ optional TestMutualRecursionB bb = 1;
+}
+
+message TestMutualRecursionB {
+ optional TestMutualRecursionA a = 1;
+ optional int32 optional_int32 = 2;
+}
+
+// Test that groups have disjoint field numbers from their siblings and
+// parents. This is NOT possible in proto1; only proto2. When outputting
+// proto1, the dup fields should be dropped.
+message TestDupFieldNumber {
+ optional int32 a = 1;
+ optional group Foo = 2 { optional int32 a = 1; }
+ optional group Bar = 3 { optional int32 a = 1; }
+}
+
+
+// Needed for a Python test.
+message TestNestedMessageHasBits {
+ message NestedMessage {
+ repeated int32 nestedmessage_repeated_int32 = 1;
+ repeated ForeignMessage nestedmessage_repeated_foreignmessage = 2;
+ }
+ optional NestedMessage optional_nested_message = 1;
+}
+
+
+// Test an enum that has multiple values with the same number.
+enum TestEnumWithDupValue {
+ FOO1 = 1;
+ BAR1 = 2;
+ BAZ = 3;
+ FOO2 = 1;
+ BAR2 = 2;
+}
+
+// Test an enum with large, unordered values.
+enum TestSparseEnum {
+ SPARSE_A = 123;
+ SPARSE_B = 62374;
+ SPARSE_C = 12589234;
+ SPARSE_D = -15;
+ SPARSE_E = -53452;
+ SPARSE_F = 0;
+ SPARSE_G = 2;
+}
+
+// Test message with CamelCase field names. This violates Protocol Buffer
+// standard style.
+message TestCamelCaseFieldNames {
+ optional int32 PrimitiveField = 1;
+ optional string StringField = 2;
+ optional ForeignEnum EnumField = 3;
+ optional ForeignMessage MessageField = 4;
+ optional string StringPieceField = 5 [ctype=STRING_PIECE];
+ optional string CordField = 6 [ctype=CORD];
+
+ repeated int32 RepeatedPrimitiveField = 7;
+ repeated string RepeatedStringField = 8;
+ repeated ForeignEnum RepeatedEnumField = 9;
+ repeated ForeignMessage RepeatedMessageField = 10;
+ repeated string RepeatedStringPieceField = 11 [ctype=STRING_PIECE];
+ repeated string RepeatedCordField = 12 [ctype=CORD];
+}
+
+
+// We list fields out of order, to ensure that we're using field number and not
+// field index to determine serialization order.
+message TestFieldOrderings {
+ optional string my_string = 11;
+ extensions 2 to 10;
+ optional int64 my_int = 1;
+ extensions 12 to 100;
+ optional float my_float = 101;
+}
+
+
+extend TestFieldOrderings {
+ optional string my_extension_string = 50;
+ optional int32 my_extension_int = 5;
+}
+
+
+message TestExtremeDefaultValues {
+ optional bytes escaped_bytes = 1 [default = "\0\001\a\b\f\n\r\t\v\\\'\"\xfe"];
+ optional uint32 large_uint32 = 2 [default = 0xFFFFFFFF];
+ optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF];
+ optional int32 small_int32 = 4 [default = -0x7FFFFFFF];
+ optional int64 small_int64 = 5 [default = -0x7FFFFFFFFFFFFFFF];
+
+ // The default value here is UTF-8 for "\u1234". (We could also just type
+ // the UTF-8 text directly into this text file rather than escape it, but
+ // lots of people use editors that would be confused by this.)
+ optional string utf8_string = 6 [default = "\341\210\264"];
+}
+
+// Test that RPC services work.
+message FooRequest {}
+message FooResponse {}
+
+service TestService {
+ rpc Foo(FooRequest) returns (FooResponse);
+ rpc Bar(BarRequest) returns (BarResponse);
+}
+
+
+message BarRequest {}
+message BarResponse {}
diff --git a/activemq-protobuf-test/src/main/proto/unittest_embed_optimize_for.proto b/activemq-protobuf-test/src/main/proto/unittest_embed_optimize_for.proto
new file mode 100644
index 0000000000..d2e172347f
--- /dev/null
+++ b/activemq-protobuf-test/src/main/proto/unittest_embed_optimize_for.proto
@@ -0,0 +1,36 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which imports a proto file that uses optimize_for = CODE_SIZE.
+
+import "unittest_optimize_for.proto";
+
+package protobuf_unittest;
+
+// We optimize for speed here, but we are importing a proto that is optimized
+// for code size.
+option optimize_for = SPEED;
+
+message TestEmbedOptimizedForSize {
+ // Test that embedding a message which has optimize_for = CODE_SIZE into
+ // one optimized for speed works.
+ optional TestOptimizedForSize optional_message = 1;
+ repeated TestOptimizedForSize repeated_message = 2;
+}
diff --git a/activemq-protobuf-test/src/main/proto/unittest_import.proto b/activemq-protobuf-test/src/main/proto/unittest_import.proto
new file mode 100644
index 0000000000..58ce42c39d
--- /dev/null
+++ b/activemq-protobuf-test/src/main/proto/unittest_import.proto
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which is imported by unittest.proto to test importing.
+
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do
+// "using namespace unittest_import = protobuf_unittest_import".
+package protobuf_unittest_import;
+
+option optimize_for = SPEED;
+
+// Excercise the java_package option.
+option java_package = "com.google.protobuf.test";
+
+// Do not set a java_outer_classname here to verify that Proto2 works without
+// one.
+
+message ImportMessage {
+ optional int32 d = 1;
+}
+
+enum ImportEnum {
+ IMPORT_FOO = 7;
+ IMPORT_BAR = 8;
+ IMPORT_BAZ = 9;
+}
+
diff --git a/activemq-protobuf-test/src/main/proto/unittest_mset.proto b/activemq-protobuf-test/src/main/proto/unittest_mset.proto
new file mode 100644
index 0000000000..455086d2f0
--- /dev/null
+++ b/activemq-protobuf-test/src/main/proto/unittest_mset.proto
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains messages for testing message_set_wire_format.
+
+package protobuf_unittest;
+
+option optimize_for = SPEED;
+
+// A message with message_set_wire_format.
+message TestMessageSet {
+ option message_set_wire_format = true;
+ extensions 4 to max;
+}
+
+message TestMessageSetContainer {
+ optional TestMessageSet message_set = 1;
+}
+
+message TestMessageSetExtension1 {
+ extend TestMessageSet {
+ optional TestMessageSetExtension1 message_set_extension = 1545008;
+ }
+ optional int32 i = 15;
+}
+
+message TestMessageSetExtension2 {
+ extend TestMessageSet {
+ optional TestMessageSetExtension2 message_set_extension = 1547769;
+ }
+ optional string str = 25;
+}
+
+// MessageSet wire format is equivalent to this.
+message RawMessageSet {
+ repeated group Item = 1 {
+ required int32 type_id = 2;
+ required bytes message = 3;
+ }
+}
+
diff --git a/activemq-protobuf-test/src/main/proto/unittest_optimize_for.proto b/activemq-protobuf-test/src/main/proto/unittest_optimize_for.proto
new file mode 100644
index 0000000000..86e727f33f
--- /dev/null
+++ b/activemq-protobuf-test/src/main/proto/unittest_optimize_for.proto
@@ -0,0 +1,38 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which uses optimize_for = CODE_SIZE.
+
+import "unittest.proto";
+
+package protobuf_unittest;
+
+option optimize_for = CODE_SIZE;
+
+message TestOptimizedForSize {
+ optional int32 i = 1;
+ optional ForeignMessage msg = 19;
+
+ extensions 1000 to max;
+
+ extend TestOptimizedForSize {
+ optional int32 test_extension = 1234;
+ }
+}
diff --git a/activemq-protobuf-test/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/activemq-protobuf-test/src/test/java/com/google/protobuf/GeneratedMessageTest.java
new file mode 100644
index 0000000000..d9845fbabb
--- /dev/null
+++ b/activemq-protobuf-test/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -0,0 +1,119 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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 com.google.protobuf;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+import protobuf_unittest.EnumWithNoOuter;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+
+/**
+ * Unit test for generated messages and generated code. See also
+ * {@link MessageTest}, which tests some generated message functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class GeneratedMessageTest extends TestCase {
+
+
+ public void testAccessors() throws Exception {
+ TestAllTypes builder = new TestAllTypes();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder;
+ TestUtil.assertAllFieldsSet(message);
+ }
+
+ public void testRepeatedSetters() throws Exception {
+ TestAllTypes builder = new TestAllTypes();
+ TestUtil.setAllFields(builder);
+ TestUtil.modifyRepeatedFields(builder);
+ TestAllTypes message = builder;
+ TestUtil.assertRepeatedFieldsModified(message);
+ }
+
+ public void testRepeatedAppend() throws Exception {
+ TestAllTypes builder = new TestAllTypes();
+
+ builder.addAllRepeatedInt32(Arrays.asList(1, 2, 3, 4));
+ builder.addAllRepeatedForeignEnum(Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+
+ ForeignMessage foreignMessage = new ForeignMessage().setC(12);
+ builder.addAllRepeatedForeignMessage(Arrays.asList(foreignMessage));
+
+ TestAllTypes message = builder;
+ assertEquals(message.getRepeatedInt32List(), Arrays.asList(1, 2, 3, 4));
+ assertEquals(message.getRepeatedForeignEnumList(),
+ Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+ assertEquals(1, message.getRepeatedForeignMessageCount());
+ assertEquals(12, message.getRepeatedForeignMessage(0).getC());
+ }
+
+ public void testSettingForeignMessageUsingBuilder() throws Exception {
+ TestAllTypes message = new TestAllTypes()
+ // Pass builder for foreign message instance.
+ .setOptionalForeignMessage(new ForeignMessage().setC(123))
+ ;
+ TestAllTypes expectedMessage = new TestAllTypes()
+ // Create expected version passing foreign message instance explicitly.
+ .setOptionalForeignMessage(new ForeignMessage().setC(123))
+ ;
+ // TODO(ngd): Upgrade to using real #equals method once implemented
+ assertEquals(expectedMessage.toString(), message.toString());
+ }
+
+ public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception {
+ TestAllTypes message = new TestAllTypes()
+ // Pass builder for foreign message instance.
+ .addRepeatedForeignMessage(new ForeignMessage().setC(456))
+ ;
+ TestAllTypes expectedMessage = new TestAllTypes()
+ // Create expected version passing foreign message instance explicitly.
+ .addRepeatedForeignMessage(
+ new ForeignMessage().setC(456))
+ ;
+ assertEquals(expectedMessage.toString(), message.toString());
+ }
+
+ public void testDefaults() throws Exception {
+ TestUtil.assertClear(new TestAllTypes());
+
+ assertEquals("\u1234", new TestExtremeDefaultValues().getUtf8String());
+ }
+
+ // =================================================================
+ // multiple_files_test
+
+ public void testMultipleFilesOption() throws Exception {
+ // We mostly just want to check that things compile.
+ MessageWithNoOuter message =
+ new MessageWithNoOuter()
+ .setNested(new MessageWithNoOuter.NestedMessage().setI(1))
+ .addForeign(new TestAllTypes().setOptionalInt32(1))
+ .setNestedEnum(MessageWithNoOuter.NestedEnum.BAZ)
+ .setForeignEnum(EnumWithNoOuter.BAR)
+ ;
+
+ byte[] data = message.toUnframedByteArray();
+ MessageWithNoOuter newMessage = MessageWithNoOuter.parseUnframed(data);
+ assertEquals(message.toString(), newMessage.toString());
+ }
+}
diff --git a/activemq-protobuf-test/src/test/java/com/google/protobuf/MessageTest.java b/activemq-protobuf-test/src/test/java/com/google/protobuf/MessageTest.java
new file mode 100644
index 0000000000..f306d740ae
--- /dev/null
+++ b/activemq-protobuf-test/src/test/java/com/google/protobuf/MessageTest.java
@@ -0,0 +1,114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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 com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+
+import junit.framework.TestCase;
+
+/**
+ * Misc. unit tests for message operations that apply to both generated
+ * and dynamic messages.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class MessageTest extends TestCase {
+ // =================================================================
+ // Message-merging tests.
+
+ static final TestAllTypes MERGE_SOURCE =
+ new TestAllTypes()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .setOptionalForeignMessage(new ForeignMessage())
+ .addRepeatedString("bar")
+ ;
+
+ static final TestAllTypes MERGE_DEST =
+ new TestAllTypes()
+ .setOptionalInt64(2)
+ .setOptionalString("baz")
+ .setOptionalForeignMessage(new ForeignMessage().setC(3))
+ .addRepeatedString("qux")
+ ;
+
+ static final String MERGE_RESULT_TEXT =
+ "optional_int32: 1\n" +
+ "optional_int64: 2\n" +
+ "optional_string: foo\n" +
+ "optional_foreign_message {\n" +
+ " c: 3\n" +
+ "}\n" +
+ "repeated_string[0]: qux\n" +
+ "repeated_string[1]: bar\n";
+
+ public void testMergeFrom() throws Exception {
+ TestAllTypes result =
+ new TestAllTypes().mergeFrom(MERGE_DEST)
+ .mergeFrom(MERGE_SOURCE);
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+
+ // =================================================================
+ // Required-field-related tests.
+
+ private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+ new TestRequired();
+ private static final TestRequired TEST_REQUIRED_INITIALIZED =
+ new TestRequired().setA(1).setB(2).setC(3);
+
+ public void testRequired() throws Exception {
+ TestRequired builder = new TestRequired();
+
+ assertFalse(builder.isInitialized());
+ builder.setA(1);
+ assertFalse(builder.isInitialized());
+ builder.setB(1);
+ assertFalse(builder.isInitialized());
+ builder.setC(1);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredForeign() throws Exception {
+ TestRequiredForeign builder = new TestRequiredForeign();
+
+ assertTrue(builder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+
+ builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+ }
+
+
+ public void testIsInitialized() throws Exception {
+ assertFalse(new TestRequired().isInitialized());
+ }
+
+}
diff --git a/activemq-protobuf-test/src/test/java/com/google/protobuf/TestUtil.java b/activemq-protobuf-test/src/test/java/com/google/protobuf/TestUtil.java
new file mode 100644
index 0000000000..fe2505d379
--- /dev/null
+++ b/activemq-protobuf-test/src/test/java/com/google/protobuf/TestUtil.java
@@ -0,0 +1,791 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Note: This file contains many lines over 80 characters. It even contains
+// many lines over 100 characters, which fails a presubmit test. However,
+// given the extremely repetitive nature of the file, I (kenton) feel that
+// having similar components of each statement line up is more important than
+// avoiding horizontal scrolling. So, I am bypassing the presubmit check.
+
+package com.google.protobuf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import org.apache.activemq.protobuf.Buffer;
+
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+
+/**
+ * Contains methods for setting all fields of {@code TestAllTypes} to
+ * some vaules as well as checking that all the fields are set to those values.
+ * These are useful for testing various protocol message features, e.g.
+ * set all fields of a message, serialize it, parse it, and check that all
+ * fields are set.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+class TestUtil {
+ private TestUtil() {}
+
+ /** Helper to convert a String to ByteSequence. */
+ private static Buffer toBytes(String str) {
+ try {
+ return new Buffer(str.getBytes("UTF-8"));
+ } catch(java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported.", e);
+ }
+ }
+
+ /**
+ * Get a {@code TestAllTypes} with all fields set as they would be by
+ * {@link #setAllFields(TestAllTypes.Builder)}.
+ */
+ public static TestAllTypes getAllSet() {
+ TestAllTypes builder = new TestAllTypes();
+ setAllFields(builder);
+ return builder;
+ }
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllFieldsSet()}.
+ */
+ public static void setAllFields(protobuf_unittest.UnittestProto.TestAllTypes message) {
+ message.setOptionalInt32 (101);
+ message.setOptionalInt64 (102);
+ message.setOptionalUint32 (103);
+ message.setOptionalUint64 (104);
+ message.setOptionalSint32 (105);
+ message.setOptionalSint64 (106);
+ message.setOptionalFixed32 (107);
+ message.setOptionalFixed64 (108);
+ message.setOptionalSfixed32(109);
+ message.setOptionalSfixed64(110);
+ message.setOptionalFloat (111);
+ message.setOptionalDouble (112);
+ message.setOptionalBool (true);
+ message.setOptionalString ("115");
+ message.setOptionalBytes (toBytes("116"));
+
+ message.setOptionalGroup(
+ new TestAllTypes.OptionalGroup().setA(117));
+ message.setOptionalNestedMessage(
+ new TestAllTypes.NestedMessage().setBb(118));
+ message.setOptionalForeignMessage(
+ new ForeignMessage().setC(119));
+ message.setOptionalImportMessage(
+ new ImportMessage().setD(120));
+
+ message.setOptionalNestedEnum (TestAllTypes.NestedEnum.BAZ);
+ message.setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ);
+ message.setOptionalImportEnum (ImportEnum.IMPORT_BAZ);
+
+ message.setOptionalStringPiece("124");
+ message.setOptionalCord("125");
+
+ // -----------------------------------------------------------------
+
+ message.getRepeatedInt32List().add(201);
+ message.getRepeatedInt64List().add(202L);
+ message.getRepeatedUint32List().add(203);
+ message.getRepeatedUint64List().add(204l);
+ message.getRepeatedSint32List().add(205);
+ message.getRepeatedSint64List().add (206l);
+ message.getRepeatedFixed32List().add (207);
+ message.getRepeatedFixed64List().add (208l);
+ message.getRepeatedSfixed32List().add(209);
+ message.getRepeatedSfixed64List().add(210l);
+ message.getRepeatedFloatList().add (211f);
+ message.getRepeatedDoubleList().add (212d);
+ message.getRepeatedBoolList().add (true);
+ message.getRepeatedStringList().add ("215");
+ message.getRepeatedBytesList().add (toBytes("216"));
+
+ message.getRepeatedGroupList().add(
+ new TestAllTypes.RepeatedGroup().setA(217));
+ message.getRepeatedNestedMessageList().add(
+ new TestAllTypes.NestedMessage().setBb(218));
+ message.getRepeatedForeignMessageList().add(
+ new ForeignMessage().setC(219));
+ message.getRepeatedImportMessageList().add(
+ new ImportMessage().setD(220));
+
+ message.getRepeatedNestedEnumList().add(TestAllTypes.NestedEnum.BAR);
+ message.getRepeatedForeignEnumList().add(ForeignEnum.FOREIGN_BAR);
+ message.getRepeatedImportEnumList().add(ImportEnum.IMPORT_BAR);
+
+ message.getRepeatedStringPieceList().add("224");
+ message.getRepeatedCordList().add("225");
+
+ // Add a second one of each field.
+ message.getRepeatedInt32List().add(301);
+ message.getRepeatedInt64List().add(302L);
+ message.getRepeatedUint32List().add(303);
+ message.getRepeatedUint64List().add(304l);
+ message.getRepeatedSint32List().add(305);
+ message.getRepeatedSint64List().add (306l);
+ message.getRepeatedFixed32List().add (307);
+ message.getRepeatedFixed64List().add (308l);
+ message.getRepeatedSfixed32List().add(309);
+ message.getRepeatedSfixed64List().add(310l);
+ message.getRepeatedFloatList().add (311f);
+ message.getRepeatedDoubleList().add (312d);
+ message.getRepeatedBoolList().add (false);
+ message.getRepeatedStringList().add ("315");
+ message.getRepeatedBytesList().add (toBytes("316"));
+
+ message.getRepeatedGroupList().add(
+ new TestAllTypes.RepeatedGroup().setA(317));
+ message.getRepeatedNestedMessageList().add(
+ new TestAllTypes.NestedMessage().setBb(318));
+ message.getRepeatedForeignMessageList().add(
+ new ForeignMessage().setC(319));
+ message.getRepeatedImportMessageList().add(
+ new ImportMessage().setD(320));
+
+ message.getRepeatedNestedEnumList().add(TestAllTypes.NestedEnum.BAZ);
+ message.getRepeatedForeignEnumList().add(ForeignEnum.FOREIGN_BAZ);
+ message.getRepeatedImportEnumList().add(ImportEnum.IMPORT_BAZ);
+
+ message.getRepeatedStringPieceList().add("324");
+ message.getRepeatedCordList().add("325");
+
+
+ // -----------------------------------------------------------------
+
+ message.setDefaultInt32 (401);
+ message.setDefaultInt64 (402);
+ message.setDefaultUint32 (403);
+ message.setDefaultUint64 (404);
+ message.setDefaultSint32 (405);
+ message.setDefaultSint64 (406);
+ message.setDefaultFixed32 (407);
+ message.setDefaultFixed64 (408);
+ message.setDefaultSfixed32(409);
+ message.setDefaultSfixed64(410);
+ message.setDefaultFloat (411);
+ message.setDefaultDouble (412);
+ message.setDefaultBool (false);
+ message.setDefaultString ("415");
+ message.setDefaultBytes (toBytes("416"));
+
+ message.setDefaultNestedEnum (TestAllTypes.NestedEnum.FOO);
+ message.setDefaultForeignEnum(ForeignEnum.FOREIGN_FOO);
+ message.setDefaultImportEnum (ImportEnum.IMPORT_FOO);
+
+ message.setDefaultStringPiece("424");
+ message.setDefaultCord("425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated fields of {@code message} to contain the values
+ * expected by {@code assertRepeatedFieldsModified()}.
+ */
+ public static void modifyRepeatedFields(TestAllTypes message) {
+ message.getRepeatedInt32List().set(1, 501);
+ message.getRepeatedInt64List().set (1, 502l);
+ message.getRepeatedUint32List().set (1, 503);
+ message.getRepeatedUint64List().set (1, 504l);
+ message.getRepeatedSint32List().set (1, 505);
+ message.getRepeatedSint64List().set (1, 506l);
+ message.getRepeatedFixed32List().set (1, 507);
+ message.getRepeatedFixed64List().set (1, 508l);
+ message.getRepeatedSfixed32List().set(1, 509);
+ message.getRepeatedSfixed64List().set(1, 510l);
+ message.getRepeatedFloatList().set (1, 511f);
+ message.getRepeatedDoubleList().set (1, 512d);
+ message.getRepeatedBoolList().set (1, true);
+ message.getRepeatedStringList().set (1, "515");
+ message.getRepeatedBytesList().set (1, toBytes("516"));
+
+ message.getRepeatedGroupList().set(1,
+ new TestAllTypes.RepeatedGroup().setA(517));
+ message.getRepeatedNestedMessageList().set(1,
+ new TestAllTypes.NestedMessage().setBb(518));
+ message.getRepeatedForeignMessageList().set(1,
+ new ForeignMessage().setC(519));
+ message.getRepeatedImportMessageList().set(1,
+ new ImportMessage().setD(520));
+
+ message.getRepeatedNestedEnumList().set (1, TestAllTypes.NestedEnum.FOO);
+ message.getRepeatedForeignEnumList().set(1, ForeignEnum.FOREIGN_FOO);
+ message.getRepeatedImportEnumList().set (1, ImportEnum.IMPORT_FOO);
+
+ message.getRepeatedStringPieceList().set(1, "524");
+ message.getRepeatedCordList().set(1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields}.
+ */
+ public static void assertAllFieldsSet(TestAllTypes message) {
+ assertTrue(message.hasOptionalInt32 ());
+ assertTrue(message.hasOptionalInt64 ());
+ assertTrue(message.hasOptionalUint32 ());
+ assertTrue(message.hasOptionalUint64 ());
+ assertTrue(message.hasOptionalSint32 ());
+ assertTrue(message.hasOptionalSint64 ());
+ assertTrue(message.hasOptionalFixed32 ());
+ assertTrue(message.hasOptionalFixed64 ());
+ assertTrue(message.hasOptionalSfixed32());
+ assertTrue(message.hasOptionalSfixed64());
+ assertTrue(message.hasOptionalFloat ());
+ assertTrue(message.hasOptionalDouble ());
+ assertTrue(message.hasOptionalBool ());
+ assertTrue(message.hasOptionalString ());
+ assertTrue(message.hasOptionalBytes ());
+
+ assertTrue(message.hasOptionalGroup ());
+ assertTrue(message.hasOptionalNestedMessage ());
+ assertTrue(message.hasOptionalForeignMessage());
+ assertTrue(message.hasOptionalImportMessage ());
+
+ assertTrue(message.getOptionalGroup ().hasA());
+ assertTrue(message.getOptionalNestedMessage ().hasBb());
+ assertTrue(message.getOptionalForeignMessage().hasC());
+ assertTrue(message.getOptionalImportMessage ().hasD());
+
+ assertTrue(message.hasOptionalNestedEnum ());
+ assertTrue(message.hasOptionalForeignEnum());
+ assertTrue(message.hasOptionalImportEnum ());
+
+ assertTrue(message.hasOptionalStringPiece());
+ assertTrue(message.hasOptionalCord());
+
+ assertEquals(101 , message.getOptionalInt32 ());
+ assertEquals(102 , message.getOptionalInt64 ());
+ assertEquals(103 , message.getOptionalUint32 ());
+ assertEquals(104 , message.getOptionalUint64 ());
+ assertEquals(105 , message.getOptionalSint32 ());
+ assertEquals(106 , message.getOptionalSint64 ());
+ assertEquals(107 , message.getOptionalFixed32 ());
+ assertEquals(108 , message.getOptionalFixed64 ());
+ assertEquals(109 , message.getOptionalSfixed32());
+ assertEquals(110 , message.getOptionalSfixed64());
+ assertEquals(111 , message.getOptionalFloat (), 0.0);
+ assertEquals(112 , message.getOptionalDouble (), 0.0);
+ assertEquals(true , message.getOptionalBool ());
+ assertEquals("115", message.getOptionalString ());
+ assertEquals(toBytes("116"), message.getOptionalBytes());
+
+ assertEquals(117, message.getOptionalGroup ().getA());
+ assertEquals(118, message.getOptionalNestedMessage ().getBb());
+ assertEquals(119, message.getOptionalForeignMessage().getC());
+ assertEquals(120, message.getOptionalImportMessage ().getD());
+
+ assertEquals(TestAllTypes.NestedEnum.BAZ, message.getOptionalNestedEnum());
+ assertEquals(ForeignEnum.FOREIGN_BAZ, message.getOptionalForeignEnum());
+ assertEquals(ImportEnum.IMPORT_BAZ, message.getOptionalImportEnum());
+
+ assertEquals("124", message.getOptionalStringPiece());
+ assertEquals("125", message.getOptionalCord());
+
+ // -----------------------------------------------------------------
+
+ assertEquals(2, message.getRepeatedInt32List().size ());
+ assertEquals(2, message.getRepeatedInt64List().size ());
+ assertEquals(2, message.getRepeatedUint32List().size ());
+ assertEquals(2, message.getRepeatedUint64List().size ());
+ assertEquals(2, message.getRepeatedSint32List().size ());
+ assertEquals(2, message.getRepeatedSint64List().size ());
+ assertEquals(2, message.getRepeatedFixed32List().size ());
+ assertEquals(2, message.getRepeatedFixed64List().size ());
+ assertEquals(2, message.getRepeatedSfixed32List().size());
+ assertEquals(2, message.getRepeatedSfixed64List().size());
+ assertEquals(2, message.getRepeatedFloatList().size ());
+ assertEquals(2, message.getRepeatedDoubleList().size ());
+ assertEquals(2, message.getRepeatedBoolList().size ());
+ assertEquals(2, message.getRepeatedStringList().size ());
+ assertEquals(2, message.getRepeatedBytesList().size ());
+
+ assertEquals(2, message.getRepeatedGroupList().size ());
+ assertEquals(2, message.getRepeatedNestedMessageList().size ());
+ assertEquals(2, message.getRepeatedForeignMessageList().size());
+ assertEquals(2, message.getRepeatedImportMessageList().size ());
+ assertEquals(2, message.getRepeatedNestedEnumList().size ());
+ assertEquals(2, message.getRepeatedForeignEnumList().size ());
+ assertEquals(2, message.getRepeatedImportEnumList().size ());
+
+ assertEquals(2, message.getRepeatedStringPieceList().size());
+ assertEquals(2, message.getRepeatedCordList().size());
+
+ assertEquals(201 , (int)message.getRepeatedInt32List().get(0));
+ assertEquals(202 , (long)message.getRepeatedInt64List().get (0));
+ assertEquals(203 , (int)message.getRepeatedUint32List().get (0));
+ assertEquals(204 , (long)message.getRepeatedUint64List().get (0));
+ assertEquals(205 , (int)message.getRepeatedSint32List().get (0));
+ assertEquals(206 , (long)message.getRepeatedSint64List().get (0));
+ assertEquals(207 , (int)message.getRepeatedFixed32List().get (0));
+ assertEquals(208 , (long)message.getRepeatedFixed64List().get (0));
+ assertEquals(209 , (int)message.getRepeatedSfixed32List().get(0));
+ assertEquals(210 , (long)message.getRepeatedSfixed64List().get(0));
+ assertEquals(211 , message.getRepeatedFloatList().get (0), 0.0);
+ assertEquals(212 , message.getRepeatedDoubleList().get (0), 0.0);
+ assertEquals(true , (boolean)message.getRepeatedBoolList().get (0));
+ assertEquals("215", message.getRepeatedStringList().get (0));
+ assertEquals(toBytes("216"), message.getRepeatedBytesList().get(0));
+
+ assertEquals(217, message.getRepeatedGroupList().get (0).getA());
+ assertEquals(218, message.getRepeatedNestedMessageList().get (0).getBb());
+ assertEquals(219, message.getRepeatedForeignMessageList().get(0).getC());
+ assertEquals(220, message.getRepeatedImportMessageList().get (0).getD());
+
+ assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnumList().get (0));
+ assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnumList().get(0));
+ assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnumList().get(0));
+
+ assertEquals("224", message.getRepeatedStringPieceList().get(0));
+ assertEquals("225", message.getRepeatedCordList().get(0));
+
+ assertEquals(301 , (int)message.getRepeatedInt32List().get (1));
+ assertEquals(302 , (long)message.getRepeatedInt64List().get (1));
+ assertEquals(303 , (int)message.getRepeatedUint32List().get (1));
+ assertEquals(304 , (long)message.getRepeatedUint64List().get (1));
+ assertEquals(305 , (int)message.getRepeatedSint32List().get (1));
+ assertEquals(306 , (long)message.getRepeatedSint64List().get (1));
+ assertEquals(307 , (int)message.getRepeatedFixed32List().get (1));
+ assertEquals(308 , (long)message.getRepeatedFixed64List().get (1));
+ assertEquals(309 , (int)message.getRepeatedSfixed32List().get(1));
+ assertEquals(310 , (long)message.getRepeatedSfixed64List().get(1));
+ assertEquals(311 , message.getRepeatedFloatList().get (1), 0.0);
+ assertEquals(312 , message.getRepeatedDoubleList().get (1), 0.0);
+ assertEquals(false, (boolean)message.getRepeatedBoolList().get (1));
+ assertEquals("315", message.getRepeatedStringList().get (1));
+ assertEquals(toBytes("316"), message.getRepeatedBytesList().get(1));
+
+ assertEquals(317, message.getRepeatedGroupList().get (1).getA());
+ assertEquals(318, message.getRepeatedNestedMessageList().get (1).getBb());
+ assertEquals(319, message.getRepeatedForeignMessageList().get(1).getC());
+ assertEquals(320, message.getRepeatedImportMessageList().get (1).getD());
+
+ assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnumList().get (1));
+ assertEquals(ForeignEnum.FOREIGN_BAZ, message.getRepeatedForeignEnumList().get(1));
+ assertEquals(ImportEnum.IMPORT_BAZ, message.getRepeatedImportEnumList().get(1));
+
+ assertEquals("324", message.getRepeatedStringPieceList().get(1));
+ assertEquals("325", message.getRepeatedCordList().get(1));
+
+ // -----------------------------------------------------------------
+
+ assertTrue(message.hasDefaultInt32 ());
+ assertTrue(message.hasDefaultInt64 ());
+ assertTrue(message.hasDefaultUint32 ());
+ assertTrue(message.hasDefaultUint64 ());
+ assertTrue(message.hasDefaultSint32 ());
+ assertTrue(message.hasDefaultSint64 ());
+ assertTrue(message.hasDefaultFixed32 ());
+ assertTrue(message.hasDefaultFixed64 ());
+ assertTrue(message.hasDefaultSfixed32());
+ assertTrue(message.hasDefaultSfixed64());
+ assertTrue(message.hasDefaultFloat ());
+ assertTrue(message.hasDefaultDouble ());
+ assertTrue(message.hasDefaultBool ());
+ assertTrue(message.hasDefaultString ());
+ assertTrue(message.hasDefaultBytes ());
+
+ assertTrue(message.hasDefaultNestedEnum ());
+ assertTrue(message.hasDefaultForeignEnum());
+ assertTrue(message.hasDefaultImportEnum ());
+
+ assertTrue(message.hasDefaultStringPiece());
+ assertTrue(message.hasDefaultCord());
+
+ assertEquals(401 , message.getDefaultInt32 ());
+ assertEquals(402 , message.getDefaultInt64 ());
+ assertEquals(403 , message.getDefaultUint32 ());
+ assertEquals(404 , message.getDefaultUint64 ());
+ assertEquals(405 , message.getDefaultSint32 ());
+ assertEquals(406 , message.getDefaultSint64 ());
+ assertEquals(407 , message.getDefaultFixed32 ());
+ assertEquals(408 , message.getDefaultFixed64 ());
+ assertEquals(409 , message.getDefaultSfixed32());
+ assertEquals(410 , message.getDefaultSfixed64());
+ assertEquals(411 , message.getDefaultFloat (), 0.0);
+ assertEquals(412 , message.getDefaultDouble (), 0.0);
+ assertEquals(false, message.getDefaultBool ());
+ assertEquals("415", message.getDefaultString ());
+ assertEquals(toBytes("416"), message.getDefaultBytes());
+
+ assertEquals(TestAllTypes.NestedEnum.FOO, message.getDefaultNestedEnum ());
+ assertEquals(ForeignEnum.FOREIGN_FOO, message.getDefaultForeignEnum());
+ assertEquals(ImportEnum.IMPORT_FOO, message.getDefaultImportEnum());
+
+ assertEquals("424", message.getDefaultStringPiece());
+ assertEquals("425", message.getDefaultCord());
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are cleared, and that getting the fields returns their
+ * default values.
+ */
+ public static void assertClear(TestAllTypes message) {
+ // hasBlah() should initially be false for all optional fields.
+ assertFalse(message.hasOptionalInt32 ());
+ assertFalse(message.hasOptionalInt64 ());
+ assertFalse(message.hasOptionalUint32 ());
+ assertFalse(message.hasOptionalUint64 ());
+ assertFalse(message.hasOptionalSint32 ());
+ assertFalse(message.hasOptionalSint64 ());
+ assertFalse(message.hasOptionalFixed32 ());
+ assertFalse(message.hasOptionalFixed64 ());
+ assertFalse(message.hasOptionalSfixed32());
+ assertFalse(message.hasOptionalSfixed64());
+ assertFalse(message.hasOptionalFloat ());
+ assertFalse(message.hasOptionalDouble ());
+ assertFalse(message.hasOptionalBool ());
+ assertFalse(message.hasOptionalString ());
+ assertFalse(message.hasOptionalBytes ());
+
+ assertFalse(message.hasOptionalGroup ());
+ assertFalse(message.hasOptionalNestedMessage ());
+ assertFalse(message.hasOptionalForeignMessage());
+ assertFalse(message.hasOptionalImportMessage ());
+
+ assertFalse(message.hasOptionalNestedEnum ());
+ assertFalse(message.hasOptionalForeignEnum());
+ assertFalse(message.hasOptionalImportEnum ());
+
+ assertFalse(message.hasOptionalStringPiece());
+ assertFalse(message.hasOptionalCord());
+
+ // Optional fields without defaults are set to zero or something like it.
+ assertEquals(0 , message.getOptionalInt32 ());
+ assertEquals(0 , message.getOptionalInt64 ());
+ assertEquals(0 , message.getOptionalUint32 ());
+ assertEquals(0 , message.getOptionalUint64 ());
+ assertEquals(0 , message.getOptionalSint32 ());
+ assertEquals(0 , message.getOptionalSint64 ());
+ assertEquals(0 , message.getOptionalFixed32 ());
+ assertEquals(0 , message.getOptionalFixed64 ());
+ assertEquals(0 , message.getOptionalSfixed32());
+ assertEquals(0 , message.getOptionalSfixed64());
+ assertEquals(0 , message.getOptionalFloat (), 0.0);
+ assertEquals(0 , message.getOptionalDouble (), 0.0);
+ assertEquals(false, message.getOptionalBool ());
+ assertEquals(null , message.getOptionalString ());
+ assertEquals(null, message.getOptionalBytes());
+ assertEquals(null, message.getOptionalNestedEnum ());
+ assertEquals(null, message.getOptionalForeignEnum());
+ assertEquals(null, message.getOptionalImportEnum());
+ assertEquals(null, message.getOptionalStringPiece());
+ assertEquals(null, message.getOptionalCord());
+
+ // Embedded messages should also be clear.
+ assertFalse(message.getOptionalGroup ().hasA());
+ assertFalse(message.getOptionalNestedMessage ().hasBb());
+ assertFalse(message.getOptionalForeignMessage().hasC());
+ assertFalse(message.getOptionalImportMessage ().hasD());
+
+ assertEquals(0, message.getOptionalGroup ().getA());
+ assertEquals(0, message.getOptionalNestedMessage ().getBb());
+ assertEquals(0, message.getOptionalForeignMessage().getC());
+ assertEquals(0, message.getOptionalImportMessage ().getD());
+
+
+
+ // Repeated fields are empty.
+ assertEquals(0, message.getRepeatedInt32List().size ());
+ assertEquals(0, message.getRepeatedInt64List().size ());
+ assertEquals(0, message.getRepeatedUint32List().size ());
+ assertEquals(0, message.getRepeatedUint64List().size ());
+ assertEquals(0, message.getRepeatedSint32List().size ());
+ assertEquals(0, message.getRepeatedSint64List().size ());
+ assertEquals(0, message.getRepeatedFixed32List().size ());
+ assertEquals(0, message.getRepeatedFixed64List().size ());
+ assertEquals(0, message.getRepeatedSfixed32List().size());
+ assertEquals(0, message.getRepeatedSfixed64List().size());
+ assertEquals(0, message.getRepeatedFloatList().size ());
+ assertEquals(0, message.getRepeatedDoubleList().size ());
+ assertEquals(0, message.getRepeatedBoolList().size ());
+ assertEquals(0, message.getRepeatedStringList().size ());
+ assertEquals(0, message.getRepeatedBytesList().size ());
+
+ assertEquals(0, message.getRepeatedGroupList().size ());
+ assertEquals(0, message.getRepeatedNestedMessageList().size ());
+ assertEquals(0, message.getRepeatedForeignMessageList().size());
+ assertEquals(0, message.getRepeatedImportMessageList().size ());
+ assertEquals(0, message.getRepeatedNestedEnumList().size ());
+ assertEquals(0, message.getRepeatedForeignEnumList().size ());
+ assertEquals(0, message.getRepeatedImportEnumList().size ());
+
+ assertEquals(0, message.getRepeatedStringPieceList().size());
+ assertEquals(0, message.getRepeatedCordList().size());
+
+ // hasBlah() should also be false for all default fields.
+ assertFalse(message.hasDefaultInt32 ());
+ assertFalse(message.hasDefaultInt64 ());
+ assertFalse(message.hasDefaultUint32 ());
+ assertFalse(message.hasDefaultUint64 ());
+ assertFalse(message.hasDefaultSint32 ());
+ assertFalse(message.hasDefaultSint64 ());
+ assertFalse(message.hasDefaultFixed32 ());
+ assertFalse(message.hasDefaultFixed64 ());
+ assertFalse(message.hasDefaultSfixed32());
+ assertFalse(message.hasDefaultSfixed64());
+ assertFalse(message.hasDefaultFloat ());
+ assertFalse(message.hasDefaultDouble ());
+ assertFalse(message.hasDefaultBool ());
+ assertFalse(message.hasDefaultString ());
+ assertFalse(message.hasDefaultBytes ());
+
+ assertFalse(message.hasDefaultNestedEnum ());
+ assertFalse(message.hasDefaultForeignEnum());
+ assertFalse(message.hasDefaultImportEnum ());
+
+ assertFalse(message.hasDefaultStringPiece());
+ assertFalse(message.hasDefaultCord());
+
+ // Fields with defaults have their default values (duh).
+ assertEquals( 41 , message.getDefaultInt32 ());
+ assertEquals( 42 , message.getDefaultInt64 ());
+ assertEquals( 43 , message.getDefaultUint32 ());
+ assertEquals( 44 , message.getDefaultUint64 ());
+ assertEquals(-45 , message.getDefaultSint32 ());
+ assertEquals( 46 , message.getDefaultSint64 ());
+ assertEquals( 47 , message.getDefaultFixed32 ());
+ assertEquals( 48 , message.getDefaultFixed64 ());
+ assertEquals( 49 , message.getDefaultSfixed32());
+ assertEquals(-50 , message.getDefaultSfixed64());
+ assertEquals( 51.5 , message.getDefaultFloat (), 0.0);
+ assertEquals( 52e3 , message.getDefaultDouble (), 0.0);
+ assertEquals(true , message.getDefaultBool ());
+ assertEquals("hello", message.getDefaultString ());
+ assertEquals(toBytes("world"), message.getDefaultBytes());
+
+ assertEquals(TestAllTypes.NestedEnum.BAR, message.getDefaultNestedEnum ());
+ assertEquals(ForeignEnum.FOREIGN_BAR, message.getDefaultForeignEnum());
+ assertEquals(ImportEnum.IMPORT_BAR, message.getDefaultImportEnum());
+
+ assertEquals("abc", message.getDefaultStringPiece());
+ assertEquals("123", message.getDefaultCord());
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields}
+ * followed by {@code modifyRepeatedFields}.
+ */
+ public static void assertRepeatedFieldsModified(TestAllTypes message) {
+ // ModifyRepeatedFields only sets the second repeated element of each
+ // field. In addition to verifying this, we also verify that the first
+ // element and size were *not* modified.
+ assertEquals(2, message.getRepeatedInt32List().size ());
+ assertEquals(2, message.getRepeatedInt64List().size ());
+ assertEquals(2, message.getRepeatedUint32List().size ());
+ assertEquals(2, message.getRepeatedUint64List().size ());
+ assertEquals(2, message.getRepeatedSint32List().size ());
+ assertEquals(2, message.getRepeatedSint64List().size ());
+ assertEquals(2, message.getRepeatedFixed32List().size ());
+ assertEquals(2, message.getRepeatedFixed64List().size ());
+ assertEquals(2, message.getRepeatedSfixed32List().size());
+ assertEquals(2, message.getRepeatedSfixed64List().size());
+ assertEquals(2, message.getRepeatedFloatList().size ());
+ assertEquals(2, message.getRepeatedDoubleList().size ());
+ assertEquals(2, message.getRepeatedBoolList().size ());
+ assertEquals(2, message.getRepeatedStringList().size ());
+ assertEquals(2, message.getRepeatedBytesList().size ());
+
+ assertEquals(2, message.getRepeatedGroupList().size ());
+ assertEquals(2, message.getRepeatedNestedMessageList().size ());
+ assertEquals(2, message.getRepeatedForeignMessageList().size());
+ assertEquals(2, message.getRepeatedImportMessageList().size ());
+ assertEquals(2, message.getRepeatedNestedEnumList().size ());
+ assertEquals(2, message.getRepeatedForeignEnumList().size ());
+ assertEquals(2, message.getRepeatedImportEnumList().size ());
+
+ assertEquals(2, message.getRepeatedStringPieceList().size());
+ assertEquals(2, message.getRepeatedCordList().size());
+
+ assertEquals(201 , (int)message.getRepeatedInt32List().get (0));
+ assertEquals(202L , (long)message.getRepeatedInt64List().get (0));
+ assertEquals(203 , (int)message.getRepeatedUint32List().get (0));
+ assertEquals(204L , (long)message.getRepeatedUint64List().get (0));
+ assertEquals(205 , (int)message.getRepeatedSint32List().get (0));
+ assertEquals(206L , (long)message.getRepeatedSint64List().get (0));
+ assertEquals(207 , (int)message.getRepeatedFixed32List().get (0));
+ assertEquals(208L , (long)message.getRepeatedFixed64List().get (0));
+ assertEquals(209 , (int)message.getRepeatedSfixed32List().get(0));
+ assertEquals(210L , (long)message.getRepeatedSfixed64List().get(0));
+ assertEquals(Float.valueOf(211F) , Float.valueOf(message.getRepeatedFloatList().get(0)));
+ assertEquals(Double.valueOf(212D), Double.valueOf(message.getRepeatedDoubleList().get(0)));
+ assertEquals(true , (boolean)message.getRepeatedBoolList().get (0));
+ assertEquals("215", message.getRepeatedStringList().get (0));
+ assertEquals(toBytes("216"), message.getRepeatedBytesList().get(0));
+
+ assertEquals(217, message.getRepeatedGroupList().get (0).getA());
+ assertEquals(218, message.getRepeatedNestedMessageList().get (0).getBb());
+ assertEquals(219, message.getRepeatedForeignMessageList().get(0).getC());
+ assertEquals(220, message.getRepeatedImportMessageList().get (0).getD());
+
+ assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnumList().get (0));
+ assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnumList().get(0));
+ assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnumList().get(0));
+
+ assertEquals("224", message.getRepeatedStringPieceList().get(0));
+ assertEquals("225", message.getRepeatedCordList().get(0));
+
+ // Actually verify the second (modified) elements now.
+ assertEquals(501 , (int)message.getRepeatedInt32List().get (1));
+ assertEquals(502L , (long)message.getRepeatedInt64List().get (1));
+ assertEquals(503 , (int)message.getRepeatedUint32List().get (1));
+ assertEquals(504L , (long)message.getRepeatedUint64List().get (1));
+ assertEquals(505 , (int)message.getRepeatedSint32List().get (1));
+ assertEquals(506L , (long)message.getRepeatedSint64List().get (1));
+ assertEquals(507 , (int)message.getRepeatedFixed32List().get (1));
+ assertEquals(508L , (long)message.getRepeatedFixed64List().get (1));
+ assertEquals(509 , (int)message.getRepeatedSfixed32List().get(1));
+ assertEquals(510L , (long)message.getRepeatedSfixed64List().get(1));
+ assertEquals(Float.valueOf(511F) , Float.valueOf(message.getRepeatedFloatList().get(1)));
+ assertEquals(Double.valueOf(512D) , Double.valueOf(message.getRepeatedDoubleList().get(1)));
+ assertEquals(true , (boolean)message.getRepeatedBoolList().get (1));
+ assertEquals("515", message.getRepeatedStringList().get (1));
+ assertEquals(toBytes("516"), message.getRepeatedBytesList().get(1));
+
+ assertEquals(517, message.getRepeatedGroupList().get (1).getA());
+ assertEquals(518, message.getRepeatedNestedMessageList().get (1).getBb());
+ assertEquals(519, message.getRepeatedForeignMessageList().get(1).getC());
+ assertEquals(520, message.getRepeatedImportMessageList().get (1).getD());
+
+ assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnumList().get (1));
+ assertEquals(ForeignEnum.FOREIGN_FOO, message.getRepeatedForeignEnumList().get(1));
+ assertEquals(ImportEnum.IMPORT_FOO, message.getRepeatedImportEnumList().get(1));
+
+ assertEquals("524", message.getRepeatedStringPieceList().get(1));
+ assertEquals("525", message.getRepeatedCordList().get(1));
+ }
+
+ // ===================================================================
+ // Like above, but for extensions
+
+ // Java gets confused with things like assertEquals(int, Integer): it can't
+ // decide whether to call assertEquals(int, int) or assertEquals(Object,
+ // Object). So we define these methods to help it.
+ private static void assertEqualsExactType(int a, int b) {
+ assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(long a, long b) {
+ assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(float a, float b) {
+ assertEquals(a, b, 0.0);
+ }
+ private static void assertEqualsExactType(double a, double b) {
+ assertEquals(a, b, 0.0);
+ }
+ private static void assertEqualsExactType(boolean a, boolean b) {
+ assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(String a, String b) {
+ assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(Buffer a, Buffer b) {
+ assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(TestAllTypes.NestedEnum a,
+ TestAllTypes.NestedEnum b) {
+ assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ForeignEnum a, ForeignEnum b) {
+ assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ImportEnum a, ImportEnum b) {
+ assertEquals(a, b);
+ }
+
+ /**
+ * @param filePath The path relative to
+ * {@link com.google.testing.util.TestUtil#getDefaultSrcDir}.
+ */
+ public static String readTextFromFile(String filePath) {
+ return readBytesFromFile(filePath).toStringUtf8();
+ }
+
+ private static File getTestDataDir() {
+ // Search each parent directory looking for "src/google/protobuf".
+ File ancestor = new File(".");
+ try {
+ ancestor = ancestor.getCanonicalFile();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Couldn't get canonical name of working directory.", e);
+ }
+ while (ancestor != null && ancestor.exists()) {
+ if (new File(ancestor, "src/google/protobuf").exists()) {
+ return new File(ancestor, "src/google/protobuf/testdata");
+ }
+ ancestor = ancestor.getParentFile();
+ }
+
+ throw new RuntimeException(
+ "Could not find golden files. This test must be run from within the " +
+ "protobuf source package so that it can read test data files from the " +
+ "C++ source tree.");
+ }
+
+ /**
+ * @param filePath The path relative to
+ * {@link com.google.testing.util.TestUtil#getDefaultSrcDir}.
+ */
+ public static Buffer readBytesFromFile(String filename) {
+ File fullPath = new File(getTestDataDir(), filename);
+ try(RandomAccessFile file = new RandomAccessFile(fullPath, "r")) {
+ byte[] content = new byte[(int) file.length()];
+ file.readFully(content);
+ return new Buffer(content);
+ } catch (IOException e) {
+ // Throw a RuntimeException here so that we can call this function from
+ // static initializers.
+ throw new IllegalArgumentException(
+ "Couldn't read file: " + fullPath.getPath(), e);
+ }
+ }
+
+ /**
+ * Get the bytes of the "golden message". This is a serialized TestAllTypes
+ * with all fields set as they would be by
+ * {@link setAllFields(TestAllTypes.Builder)}, but it is loaded from a file
+ * on disk rather than generated dynamically. The file is actually generated
+ * by C++ code, so testing against it verifies compatibility with C++.
+ */
+ public static Buffer getGoldenMessage() {
+ if (goldenMessage == null) {
+ goldenMessage = readBytesFromFile("golden_message");
+ }
+ return goldenMessage;
+ }
+ private static Buffer goldenMessage = null;
+}
diff --git a/activemq-protobuf-test/src/test/java/com/google/protobuf/WireFormatTest.java b/activemq-protobuf-test/src/test/java/com/google/protobuf/WireFormatTest.java
new file mode 100644
index 0000000000..7724141ce7
--- /dev/null
+++ b/activemq-protobuf-test/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -0,0 +1,60 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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 com.google.protobuf;
+
+import junit.framework.TestCase;
+
+import org.apache.activemq.protobuf.Buffer;
+import org.apache.activemq.protobuf.CodedInputStream;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+/**
+ * Tests related to parsing and serialization.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class WireFormatTest extends TestCase {
+ public void testSerialization() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ byte[] rawBytes = message.toUnframedByteArray();
+ assertEquals(rawBytes.length, message.serializedSizeUnframed());
+
+ TestAllTypes message2 = TestAllTypes.parseUnframed(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+ }
+
+ private void assertFieldsInOrder(Buffer data) throws Exception {
+ try(CodedInputStream input = new CodedInputStream(data)) {
+ int previousTag = 0;
+
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ assertTrue(tag > previousTag);
+ input.skipField(tag);
+ }
+ }
+ }
+
+}
+
diff --git a/activemq-protobuf-test/src/test/java/com/google/protobuf/multiple_files_test.proto b/activemq-protobuf-test/src/test/java/com/google/protobuf/multiple_files_test.proto
new file mode 100644
index 0000000000..1dbadfe0aa
--- /dev/null
+++ b/activemq-protobuf-test/src/test/java/com/google/protobuf/multiple_files_test.proto
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// A proto file which tests the java_multiple_files option.
+
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "MultipleFilesTestProto";
+
+message MessageWithNoOuter {
+ message NestedMessage {
+ optional int32 i = 1;
+ }
+ enum NestedEnum {
+ BAZ = 3;
+ }
+ optional NestedMessage nested = 1;
+ repeated TestAllTypes foreign = 2;
+ optional NestedEnum nested_enum = 3;
+ optional EnumWithNoOuter foreign_enum = 4;
+}
+
+enum EnumWithNoOuter {
+ FOO = 1;
+ BAR = 2;
+}
+
+service ServiceWithNoOuter {
+ rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
+}
+
+extend TestAllExtensions {
+ optional int32 extension_with_outer = 1234567;
+}
diff --git a/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java b/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java
new file mode 100644
index 0000000000..d269253a0c
--- /dev/null
+++ b/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import junit.framework.TestCase;
+
+import org.apache.activemq.protobuf.DeferredUnmarshal.Bar;
+import org.apache.activemq.protobuf.DeferredUnmarshal.Foo;
+
+public class DeferredUnmarshalTest extends TestCase {
+
+ public void testDeferredDecoding() throws InvalidProtocolBufferException {
+
+ Foo foo = new Foo();
+ foo.setField1(5);
+ foo.setField2(20);
+
+ Bar bar = new Bar();
+
+ // There is no decoding pending so its' considered decoded.
+ assertTrue(bar.isDecoded());
+
+ bar.setField1(25);
+ bar.setField2(220);
+ bar.setField3(foo);
+
+ // The message should not be encoded yet.
+ assertFalse(bar.isEncoded());
+
+ // The message should be encoded now..
+ byte[] encodedForm = bar.toUnframedByteArray();
+ assertTrue(bar.isEncoded());
+
+ // Repeated encoding operations should just give back the same byte[]
+ assertTrue(encodedForm == bar.toUnframedByteArray());
+
+ // Decoding does not occur until a field is accessed. The new message should
+ // still be considered encoded.
+ Bar bar2 = Bar.parseUnframed(encodedForm);
+ assertTrue(bar2.isEncoded());
+ assertFalse(bar2.isDecoded());
+
+ // This should now decode the message.
+ assertEquals(25, bar2.getField1());
+ assertTrue(bar2.isDecoded());
+
+ // Since bar2 still has not been modified it should still spit out the same
+ // byte[]
+ assertTrue(encodedForm == bar2.toUnframedByteArray());
+
+ // Nested messages should remain un-decoded.
+ assertFalse(bar2.getField3().isDecoded());
+
+ // Changing a field should remove the encoding.
+ bar2.setField1(35);
+ assertFalse(bar2.isEncoded());
+ assertTrue(bar2.isDecoded());
+
+ }
+
+}
diff --git a/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java b/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java
new file mode 100644
index 0000000000..992b0822ef
--- /dev/null
+++ b/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import org.apache.activemq.protobuf.DeferredUnmarshal.Bar;
+import org.apache.activemq.protobuf.DeferredUnmarshal.Foo;
+
+import junit.framework.TestCase;
+
+public class EqualsTest extends TestCase {
+
+ public void testDeferredUnmarshal() {
+
+ Bar bar1 = createBar();
+ Bar bar2 = createBar();
+
+ // They should have the same hash and equal the same value.
+ assertTrue(bar1.hashCode() == bar2.hashCode());
+ assertTrue(bar1.equals(bar2));
+
+ // Change bar2 a little.
+
+ bar2.setField2(35);
+
+ assertFalse(bar1.hashCode() == bar2.hashCode());
+ assertFalse(bar1.equals(bar2));
+
+ }
+
+ private Bar createBar() {
+ Bar bar;
+ Foo foo = new Foo();
+ foo.setField1(5);
+ foo.setField2(20);
+
+ bar = new Bar();
+ bar.setField1(25);
+ bar.setField2(220);
+ bar.setField3(foo);
+ return bar;
+ }
+
+}
diff --git a/activemq-protobuf/README.txt b/activemq-protobuf/README.txt
new file mode 100644
index 0000000000..e467c04c63
--- /dev/null
+++ b/activemq-protobuf/README.txt
@@ -0,0 +1,25 @@
+=======================================================================
+The AcitveMQ Protocol Buffers Java Implementation
+=======================================================================
+
+Protocol Buffers is a data interchange format developed by
+Google. You can get more information about Protocol Buffers
+at:
+
+ http://code.google.com/apis/protocolbuffers/
+
+
+Unfortunately the the main Protocol Buffer's project made the
+Java API cumbersome to use since the messages are immutable. They
+Justify this decision by highlighting the fact it reduces end user
+error that occur with Mutable messages.
+
+This module brings you a slimmed down lean and mean API to accessing
+Protocol Buffer data structures. It provides little protection
+from end users 'hurting themselves', but it does give power user
+and easier to use API.
+
+In addition, this module provides a Java based code generator so
+that it's easier to code generate your Protocol Buffer classes in
+a java based build system like Ant or Maven.
+
diff --git a/activemq-protobuf/pom.xml b/activemq-protobuf/pom.xml
new file mode 100644
index 0000000000..c1d10fe71f
--- /dev/null
+++ b/activemq-protobuf/pom.xml
@@ -0,0 +1,90 @@
+
+
+
+
+ 4.0.0
+
+ org.apache.activemq
+ activemq-parent
+ 6.1.3-SNAPSHOT
+
+
+ org.apache.activemq.protobuf
+ activemq-protobuf
+ maven-plugin
+
+ ActiveMQ :: Protocol Buffers and Compiler
+
+
+ A Simpler Protocol Buffer Java API. Includes a Proto to Java compiler.
+
+
+
+
+ org.apache.maven
+ maven-plugin-api
+ ${maven-core-version}
+ true
+
+
+ org.apache.maven
+ maven-core
+ ${maven-core-version}
+ true
+
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-plugin-plugin
+
+ amqprotobuf
+
+
+
+ maven-surefire-plugin
+
+
+ **/*Test.java
+
+
+
+
+ org.codehaus.mojo
+ javacc-maven-plugin
+
+
+ javacc
+
+ javacc
+
+
+
+
+
+
+
+
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/AsciiBuffer.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/AsciiBuffer.java
new file mode 100644
index 0000000000..8248b1d83d
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/AsciiBuffer.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+
+final public class AsciiBuffer extends Buffer {
+
+ private int hashCode;
+
+ public AsciiBuffer(Buffer other) {
+ super(other);
+ }
+
+ public AsciiBuffer(byte[] data, int offset, int length) {
+ super(data, offset, length);
+ }
+
+ public AsciiBuffer(byte[] data) {
+ super(data);
+ }
+
+ public AsciiBuffer(String input) {
+ super(encode(input));
+ }
+
+ public AsciiBuffer compact() {
+ if (length != data.length) {
+ return new AsciiBuffer(toByteArray());
+ }
+ return this;
+ }
+
+ public String toString()
+ {
+ return decode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if( obj==this )
+ return true;
+
+ if( obj==null || obj.getClass()!=AsciiBuffer.class )
+ return false;
+
+ return equals((Buffer)obj);
+ }
+
+ @Override
+ public int hashCode() {
+ if( hashCode==0 ) {
+ hashCode = super.hashCode();;
+ }
+ return hashCode;
+ }
+
+ static public byte[] encode(String value)
+ {
+ int size = value.length();
+ byte rc[] = new byte[size];
+ for( int i=0; i < size; i++ ) {
+ rc[i] = (byte)(value.charAt(i)&0xFF);
+ }
+ return rc;
+ }
+ static public String decode(Buffer value)
+ {
+ int size = value.getLength();
+ char rc[] = new char[size];
+ for( int i=0; i < size; i++ ) {
+ rc[i] = (char)(value.byteAt(i) & 0xFF );
+ }
+ return new String(rc);
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java
new file mode 100644
index 0000000000..9f10bfac2e
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java
@@ -0,0 +1,334 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_END_GROUP;
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED;
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_START_GROUP;
+import static org.apache.activemq.protobuf.WireFormat.makeTag;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+abstract public class BaseMessage implements Message {
+
+ protected int memoizedSerializedSize = -1;
+
+ abstract public T clone() throws CloneNotSupportedException;
+
+ public void clear() {
+ memoizedSerializedSize = -1;
+ }
+
+ public boolean isInitialized() {
+ return missingFields().isEmpty();
+ }
+
+ @SuppressWarnings("unchecked")
+ public T assertInitialized() throws UninitializedMessageException {
+ java.util.ArrayList missingFields = missingFields();
+ if (!missingFields.isEmpty()) {
+ throw new UninitializedMessageException(missingFields);
+ }
+ return getThis();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected T checktInitialized() throws InvalidProtocolBufferException {
+ java.util.ArrayList missingFields = missingFields();
+ if (!missingFields.isEmpty()) {
+ throw new UninitializedMessageException(missingFields).asInvalidProtocolBufferException();
+ }
+ return getThis();
+ }
+
+ public ArrayList missingFields() {
+ load();
+ return new ArrayList();
+ }
+
+ protected void loadAndClear() {
+ memoizedSerializedSize = -1;
+ }
+
+ protected void load() {
+ }
+
+ @SuppressWarnings("unchecked")
+ public T mergeFrom(T other) {
+ return getThis();
+ }
+
+ public void writeUnframed(CodedOutputStream output) throws java.io.IOException {
+ // if (encodedForm == null) {
+ // encodedForm = new byte[serializedSizeUnframed()];
+ // com.google.protobuf.CodedOutputStream original = output;
+ // output =
+ // com.google.protobuf.CodedOutputStream.newInstance(encodedForm);
+ // if (hasField1()) {
+ // output.writeInt32(1, getField1());
+ // }
+ // if (hasField2()) {
+ // output.writeInt64(2, getField2());
+ // }
+ // if (hasField3()) {
+ // writeMessage(output, 3, getField3());
+ // }
+ // output.checkNoSpaceLeft();
+ // output = original;
+ // }
+ // output.writeRawBytes(encodedForm);
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // Write related helpers.
+ // /////////////////////////////////////////////////////////////////
+
+ public void writeFramed(CodedOutputStream output) throws IOException {
+ output.writeRawVarint32(serializedSizeUnframed());
+ writeUnframed(output);
+ }
+
+ public Buffer toUnframedBuffer() {
+ try {
+ int size = serializedSizeUnframed();
+ BufferOutputStream baos = new BufferOutputStream(size);
+ CodedOutputStream output = new CodedOutputStream(baos);
+ writeUnframed(output);
+ Buffer rc = baos.toBuffer();
+ if( rc.length != size ) {
+ throw new IllegalStateException("Did not write as much data as expected.");
+ }
+ return rc;
+ } catch (IOException e) {
+ throw new RuntimeException("Serializing to a byte array threw an IOException " + "(should never happen).", e);
+ }
+ }
+
+ public Buffer toFramedBuffer() {
+ try {
+ int size = serializedSizeFramed();
+ BufferOutputStream baos = new BufferOutputStream(size);
+ CodedOutputStream output = new CodedOutputStream(baos);
+ writeFramed(output);
+ Buffer rc = baos.toBuffer();
+ if( rc.length != size ) {
+ throw new IllegalStateException("Did not write as much data as expected.");
+ }
+ return rc;
+ } catch (IOException e) {
+ throw new RuntimeException("Serializing to a byte array threw an IOException " + "(should never happen).", e);
+ }
+ }
+
+ public byte[] toUnframedByteArray() {
+ return toUnframedBuffer().toByteArray();
+ }
+
+ public byte[] toFramedByteArray() {
+ return toFramedBuffer().toByteArray();
+ }
+
+ public void writeFramed(OutputStream output) throws IOException {
+ CodedOutputStream codedOutput = new CodedOutputStream(output);
+ writeFramed(codedOutput);
+ codedOutput.flush();
+ }
+
+ public void writeUnframed(OutputStream output) throws IOException {
+ CodedOutputStream codedOutput = new CodedOutputStream(output);
+ writeUnframed(codedOutput);
+ codedOutput.flush();
+ }
+
+ public int serializedSizeFramed() {
+ int t = serializedSizeUnframed();
+ return CodedOutputStream.computeRawVarint32Size(t) + t;
+
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // Read related helpers.
+ // /////////////////////////////////////////////////////////////////
+
+ public T mergeFramed(CodedInputStream input) throws IOException {
+ int length = input.readRawVarint32();
+ int oldLimit = input.pushLimit(length);
+ T rc = mergeUnframed(input);
+ input.checkLastTagWas(0);
+ input.popLimit(oldLimit);
+ return rc;
+ }
+
+ public T mergeUnframed(Buffer data) throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = new CodedInputStream(data);
+ mergeUnframed(input);
+ input.checkLastTagWas(0);
+ return getThis();
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException("An IOException was thrown (should never happen in this method).", e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private T getThis() {
+ return (T) this;
+ }
+
+ public T mergeFramed(Buffer data) throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = new CodedInputStream(data);
+ mergeFramed(input);
+ input.checkLastTagWas(0);
+ return getThis();
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException("An IOException was thrown (should never happen in this method).", e);
+ }
+ }
+
+ public T mergeUnframed(byte[] data) throws InvalidProtocolBufferException {
+ return mergeUnframed(new Buffer(data));
+ }
+
+ public T mergeFramed(byte[] data) throws InvalidProtocolBufferException {
+ return mergeFramed(new Buffer(data));
+ }
+
+ public T mergeUnframed(InputStream input) throws IOException {
+ CodedInputStream codedInput = new CodedInputStream(input);
+ mergeUnframed(codedInput);
+ return getThis();
+ }
+
+ public T mergeFramed(InputStream input) throws IOException {
+ int length = readRawVarint32(input);
+ byte[] data = new byte[length];
+ int pos = 0;
+ while (pos < length) {
+ int r = input.read(data, pos, length - pos);
+ if (r < 0) {
+ throw new InvalidProtocolBufferException("Input stream ended before a full message frame could be read.");
+ }
+ pos += r;
+ }
+ return mergeUnframed(data);
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // Internal implementation methods.
+ // /////////////////////////////////////////////////////////////////
+ static protected void addAll(Iterable values, Collection super T> list) {
+ if (values instanceof Collection) {
+ @SuppressWarnings("unsafe")
+ Collection collection = (Collection) values;
+ list.addAll(collection);
+ } else {
+ for (T value : values) {
+ list.add(value);
+ }
+ }
+ }
+
+ static protected void writeGroup(CodedOutputStream output, int tag, BaseMessage message) throws IOException {
+ output.writeTag(tag, WIRETYPE_START_GROUP);
+ message.writeUnframed(output);
+ output.writeTag(tag, WIRETYPE_END_GROUP);
+ }
+
+ static protected T readGroup(CodedInputStream input, int tag, T group) throws IOException {
+ group.mergeUnframed(input);
+ input.checkLastTagWas(makeTag(tag, WIRETYPE_END_GROUP));
+ return group;
+ }
+
+ static protected int computeGroupSize(int tag, BaseMessage message) {
+ return CodedOutputStream.computeTagSize(tag) * 2 + message.serializedSizeUnframed();
+ }
+
+ static protected void writeMessage(CodedOutputStream output, int tag, BaseMessage message) throws IOException {
+ output.writeTag(tag, WIRETYPE_LENGTH_DELIMITED);
+ message.writeFramed(output);
+ }
+
+ static protected int computeMessageSize(int tag, BaseMessage message) {
+ return CodedOutputStream.computeTagSize(tag) + message.serializedSizeFramed();
+ }
+
+ protected List prefix(List missingFields, String prefix) {
+ ArrayList rc = new ArrayList(missingFields.size());
+ for (String v : missingFields) {
+ rc.add(prefix + v);
+ }
+ return rc;
+ }
+
+ /**
+ * Read a raw Varint from the stream. If larger than 32 bits, discard the
+ * upper bits.
+ */
+ static public int readRawVarint32(InputStream is) throws IOException {
+ byte tmp = readRawByte(is);
+ if (tmp >= 0) {
+ return tmp;
+ }
+ int result = tmp & 0x7f;
+ if ((tmp = readRawByte(is)) >= 0) {
+ result |= tmp << 7;
+ } else {
+ result |= (tmp & 0x7f) << 7;
+ if ((tmp = readRawByte(is)) >= 0) {
+ result |= tmp << 14;
+ } else {
+ result |= (tmp & 0x7f) << 14;
+ if ((tmp = readRawByte(is)) >= 0) {
+ result |= tmp << 21;
+ } else {
+ result |= (tmp & 0x7f) << 21;
+ result |= (tmp = readRawByte(is)) << 28;
+ if (tmp < 0) {
+ // Discard upper 32 bits.
+ for (int i = 0; i < 5; i++) {
+ if (readRawByte(is) >= 0)
+ return result;
+ }
+ throw new InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.");
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ static protected byte readRawByte(InputStream is) throws IOException {
+ int rc = is.read();
+ if (rc == -1) {
+ throw new InvalidProtocolBufferException("While parsing a protocol message, the input ended unexpectedly " + "in the middle of a field. This could mean either than the " + "input has been truncated or that an embedded message "
+ + "misreported its own length.");
+ }
+ return (byte) rc;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Buffer.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Buffer.java
new file mode 100644
index 0000000000..e274b0982c
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Buffer.java
@@ -0,0 +1,211 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import java.util.List;
+
+public class Buffer implements Comparable {
+
+ final public byte[] data;
+ final public int offset;
+ final public int length;
+
+ public Buffer(Buffer other) {
+ this(other.data, other.offset, other.length);
+ }
+
+ public Buffer(byte data[]) {
+ this(data, 0, data.length);
+ }
+
+ public Buffer(byte data[], int offset, int length) {
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ @Deprecated
+ public Buffer(String value) {
+ this(UTF8Buffer.encode(value));
+ }
+
+ public final Buffer slice(int low, int high) {
+ int sz;
+
+ if (high < 0) {
+ sz = length + high;
+ } else {
+ sz = high - low;
+ }
+
+ if (sz < 0) {
+ sz = 0;
+ }
+
+ return new Buffer(data, offset + low, sz);
+ }
+
+ public final byte[] getData() {
+ return data;
+ }
+
+ public final int getLength() {
+ return length;
+ }
+
+ public final int getOffset() {
+ return offset;
+ }
+
+ public Buffer compact() {
+ if (length != data.length) {
+ return new Buffer(toByteArray());
+ }
+ return this;
+ }
+
+ final public byte[] toByteArray() {
+ byte[] data = this.data;
+ int length = this.length;
+ if (length != data.length) {
+ byte t[] = new byte[length];
+ System.arraycopy(data, offset, t, 0, length);
+ data = t;
+ }
+ return data;
+ }
+
+ public byte byteAt(int i) {
+ return data[offset + i];
+ }
+
+
+ @Override
+ public int hashCode() {
+ byte[] target = new byte[4];
+ for (int i = 0; i < length; i++) {
+ target[i % 4] ^= data[offset + i];
+ }
+ return target[0] << 24 | target[1] << 16 | target[2] << 8 | target[3];
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+
+ if (obj == null || obj.getClass() != Buffer.class)
+ return false;
+
+ return equals((Buffer) obj);
+ }
+
+ final public boolean equals(Buffer obj) {
+ if (length != obj.length) {
+ return false;
+ }
+ for (int i = 0; i < length; i++) {
+ if (obj.data[obj.offset + i] != data[offset + i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ final public BufferInputStream newInput() {
+ return new BufferInputStream(this);
+ }
+
+ final public BufferOutputStream newOutput() {
+ return new BufferOutputStream(this);
+ }
+
+ final public boolean isEmpty() {
+ return length == 0;
+ }
+
+ final public boolean contains(byte value) {
+ return indexOf(value, 0) >= 0;
+ }
+
+ final public int indexOf(byte value, int pos) {
+ for (int i = pos; i < length; i++) {
+ if (data[offset + i] == value) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ final public static Buffer join(List items, Buffer seperator) {
+ if (items.isEmpty())
+ return new Buffer(seperator.data, 0, 0);
+
+ int size = 0;
+ for (Buffer item : items) {
+ size += item.length;
+ }
+ size += seperator.length * (items.size() - 1);
+
+ int pos = 0;
+ byte data[] = new byte[size];
+ for (Buffer item : items) {
+ if (pos != 0) {
+ System.arraycopy(seperator.data, seperator.offset, data, pos, seperator.length);
+ pos += seperator.length;
+ }
+ System.arraycopy(item.data, item.offset, data, pos, item.length);
+ pos += item.length;
+ }
+
+ return new Buffer(data, 0, size);
+ }
+
+ @Deprecated
+ public String toStringUtf8() {
+ return UTF8Buffer.decode(this);
+ }
+
+ public int compareTo(Buffer o) {
+ int minLength = Math.min(length, o.length);
+ if (offset == o.offset) {
+ int pos = offset;
+ int limit = minLength + offset;
+ while (pos < limit) {
+ byte b1 = data[pos];
+ byte b2 = o.data[pos];
+ if (b1 != b2) {
+ return b1 - b2;
+ }
+ pos++;
+ }
+ } else {
+ int offset1 = offset;
+ int offset2 = o.offset;
+ while ( minLength-- != 0) {
+ byte b1 = data[offset1++];
+ byte b2 = o.data[offset2++];
+ if (b1 != b2) {
+ return b1 - b2;
+ }
+ }
+ }
+ return length - o.length;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BufferInputStream.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BufferInputStream.java
new file mode 100644
index 0000000000..c13093ec8f
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BufferInputStream.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Very similar to the java.io.ByteArrayInputStream but this version is not
+ * thread safe.
+ */
+final public class BufferInputStream extends InputStream {
+
+ byte buffer[];
+ int limit;
+ int pos;
+ int mark;
+
+ public BufferInputStream(byte data[]) {
+ this(data, 0, data.length);
+ }
+
+ public BufferInputStream(Buffer sequence) {
+ this(sequence.getData(), sequence.getOffset(), sequence.getLength());
+ }
+
+ public BufferInputStream(byte data[], int offset, int size) {
+ this.buffer = data;
+ this.mark = offset;
+ this.pos = offset;
+ this.limit = offset + size;
+ }
+
+ public int read() throws IOException {
+ if (pos < limit) {
+ return buffer[pos++] & 0xff;
+ } else {
+ return -1;
+ }
+ }
+
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte b[], int off, int len) {
+ if (pos < limit) {
+ len = Math.min(len, limit - pos);
+ System.arraycopy(buffer, pos, b, off, len);
+ pos += len;
+ return len;
+ } else {
+ return -1;
+ }
+ }
+
+ public Buffer readBuffer(int len) {
+ Buffer rc=null;
+ if (pos < limit) {
+ len = Math.min(len, limit - pos);
+ rc = new Buffer(buffer, pos, len);
+ pos += len;
+ }
+ return rc;
+ }
+
+ public long skip(long len) throws IOException {
+ if (pos < limit) {
+ len = Math.min(len, limit - pos);
+ if (len > 0) {
+ pos += len;
+ }
+ return len;
+ } else {
+ return -1;
+ }
+ }
+
+ public int available() {
+ return limit - pos;
+ }
+
+ public boolean markSupported() {
+ return true;
+ }
+
+ public void mark(int markpos) {
+ mark = pos;
+ }
+
+ public void reset() {
+ pos = mark;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BufferOutputStream.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BufferOutputStream.java
new file mode 100644
index 0000000000..d6b1d1816a
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BufferOutputStream.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * Very similar to the java.io.ByteArrayOutputStream but this version
+ * is not thread safe and the resulting data is returned in a Buffer
+ * to avoid an extra byte[] allocation. It also does not re-grow it's
+ * internal buffer.
+ */
+final public class BufferOutputStream extends OutputStream {
+
+ byte buffer[];
+ int offset;
+ int limit;
+ int pos;
+
+ public BufferOutputStream(int size) {
+ this(new byte[size]);
+ }
+
+ public BufferOutputStream(byte[] buffer) {
+ this.buffer = buffer;
+ this.limit = buffer.length;
+ }
+
+ public BufferOutputStream(Buffer data) {
+ this.buffer = data.data;
+ this.pos = this.offset = data.offset;
+ this.limit = data.offset+data.length;
+ }
+
+
+ public void write(int b) throws IOException {
+ int newPos = pos + 1;
+ checkCapacity(newPos);
+ buffer[pos] = (byte) b;
+ pos = newPos;
+ }
+
+ public void write(byte b[], int off, int len) throws IOException {
+ int newPos = pos + len;
+ checkCapacity(newPos);
+ System.arraycopy(b, off, buffer, pos, len);
+ pos = newPos;
+ }
+
+ public Buffer getNextBuffer(int len) throws IOException {
+ int newPos = pos + len;
+ checkCapacity(newPos);
+ return new Buffer(buffer, pos, len);
+ }
+
+ /**
+ * Ensures the the buffer has at least the minimumCapacity specified.
+ * @param i
+ * @throws EOFException
+ */
+ private void checkCapacity(int minimumCapacity) throws IOException {
+ if( minimumCapacity > limit ) {
+ throw new EOFException("Buffer limit reached.");
+ }
+ }
+
+ public void reset() {
+ pos = offset;
+ }
+
+ public Buffer toBuffer() {
+ return new Buffer(buffer, offset, pos);
+ }
+
+ public byte[] toByteArray() {
+ return toBuffer().toByteArray();
+ }
+
+ public int size() {
+ return offset-pos;
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/CodedInputStream.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/CodedInputStream.java
new file mode 100644
index 0000000000..b8bb699253
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/CodedInputStream.java
@@ -0,0 +1,418 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.apache.activemq.protobuf;
+
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Reads and decodes protocol message fields.
+ *
+ * This class contains two kinds of methods: methods that read specific protocol
+ * message constructs and field types (e.g. {@link #readTag()} and
+ * {@link #readInt32()}) and methods that read low-level values (e.g.
+ * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
+ * encoded protocol messages, you should use the former methods, but if you are
+ * reading some other format of your own design, use the latter.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class CodedInputStream extends FilterInputStream {
+
+ private int lastTag = 0;
+ private int limit = Integer.MAX_VALUE;
+ private int pos;
+ private BufferInputStream bis;
+
+ public CodedInputStream(InputStream in) {
+ super(in);
+ if( in.getClass() == BufferInputStream.class ) {
+ bis = (BufferInputStream)in;
+ }
+ }
+
+ public CodedInputStream(Buffer data) {
+ this(new BufferInputStream(data));
+ limit = data.length;
+ }
+
+ public CodedInputStream(byte[] data) {
+ this(new BufferInputStream(data));
+ limit = data.length;
+ }
+
+ /**
+ * Attempt to read a field tag, returning zero if we have reached EOF.
+ * Protocol message parsers use this to read tags, since a protocol message
+ * may legally end wherever a tag occurs, and zero is not a valid tag
+ * number.
+ */
+ public int readTag() throws IOException {
+ if( pos >= limit ) {
+ lastTag=0;
+ return 0;
+ }
+ try {
+ lastTag = readRawVarint32();
+ if (lastTag == 0) {
+ // If we actually read zero, that's not a valid tag.
+ throw InvalidProtocolBufferException.invalidTag();
+ }
+ return lastTag;
+ } catch (EOFException e) {
+ lastTag=0;
+ return 0;
+ }
+ }
+
+
+ /**
+ * Verifies that the last call to readTag() returned the given tag value.
+ * This is used to verify that a nested group ended with the correct end
+ * tag.
+ *
+ * @throws InvalidProtocolBufferException
+ * {@code value} does not match the last tag.
+ */
+ public void checkLastTagWas(int value) throws InvalidProtocolBufferException {
+ if (lastTag != value) {
+ throw InvalidProtocolBufferException.invalidEndTag();
+ }
+ }
+
+ /**
+ * Reads and discards a single field, given its tag value.
+ *
+ * @return {@code false} if the tag is an endgroup tag, in which case
+ * nothing is skipped. Otherwise, returns {@code true}.
+ */
+ public boolean skipField(int tag) throws IOException {
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ readInt32();
+ return true;
+ case WireFormat.WIRETYPE_FIXED64:
+ readRawLittleEndian64();
+ return true;
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ skipRawBytes(readRawVarint32());
+ return true;
+ case WireFormat.WIRETYPE_START_GROUP:
+ skipMessage();
+ checkLastTagWas(WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
+ return true;
+ case WireFormat.WIRETYPE_END_GROUP:
+ return false;
+ case WireFormat.WIRETYPE_FIXED32:
+ readRawLittleEndian32();
+ return true;
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ /**
+ * Reads and discards an entire message. This will read either until EOF or
+ * until an endgroup tag, whichever comes first.
+ */
+ public void skipMessage() throws IOException {
+ while (true) {
+ int tag = readTag();
+ if (tag == 0 || !skipField(tag))
+ return;
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Read a {@code double} field value from the stream. */
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readRawLittleEndian64());
+ }
+
+ /** Read a {@code float} field value from the stream. */
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readRawLittleEndian32());
+ }
+
+ /** Read a {@code uint64} field value from the stream. */
+ public long readUInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ /** Read an {@code int64} field value from the stream. */
+ public long readInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ /** Read an {@code int32} field value from the stream. */
+ public int readInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ /** Read a {@code fixed64} field value from the stream. */
+ public long readFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ /** Read a {@code fixed32} field value from the stream. */
+ public int readFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ /** Read a {@code bool} field value from the stream. */
+ public boolean readBool() throws IOException {
+ return readRawVarint32() != 0;
+ }
+
+ /** Read a {@code string} field value from the stream. */
+ public String readString() throws IOException {
+ int size = readRawVarint32();
+ Buffer data = readRawBytes(size);
+ return new String(data.data, data.offset, data.length, "UTF-8");
+ }
+
+ /** Read a {@code bytes} field value from the stream. */
+ public Buffer readBytes() throws IOException {
+ int size = readRawVarint32();
+ return readRawBytes(size);
+ }
+
+ /** Read a {@code uint32} field value from the stream. */
+ public int readUInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ /**
+ * Read an enum field value from the stream. Caller is responsible for
+ * converting the numeric value to an actual enum.
+ */
+ public int readEnum() throws IOException {
+ return readRawVarint32();
+ }
+
+ /** Read an {@code sfixed32} field value from the stream. */
+ public int readSFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ /** Read an {@code sfixed64} field value from the stream. */
+ public long readSFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ /** Read an {@code sint32} field value from the stream. */
+ public int readSInt32() throws IOException {
+ return decodeZigZag32(readRawVarint32());
+ }
+
+ /** Read an {@code sint64} field value from the stream. */
+ public long readSInt64() throws IOException {
+ return decodeZigZag64(readRawVarint64());
+ }
+
+ // =================================================================
+
+ /**
+ * Read a raw Varint from the stream. If larger than 32 bits, discard the
+ * upper bits.
+ */
+ public int readRawVarint32() throws IOException {
+ byte tmp = readRawByte();
+ if (tmp >= 0) {
+ return tmp;
+ }
+ int result = tmp & 0x7f;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 7;
+ } else {
+ result |= (tmp & 0x7f) << 7;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 14;
+ } else {
+ result |= (tmp & 0x7f) << 14;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 21;
+ } else {
+ result |= (tmp & 0x7f) << 21;
+ result |= (tmp = readRawByte()) << 28;
+ if (tmp < 0) {
+ // Discard upper 32 bits.
+ for (int i = 0; i < 5; i++) {
+ if (readRawByte() >= 0)
+ return result;
+ }
+ throw InvalidProtocolBufferException.malformedVarint();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /** Read a raw Varint from the stream. */
+ public long readRawVarint64() throws IOException {
+ int shift = 0;
+ long result = 0;
+ while (shift < 64) {
+ byte b = readRawByte();
+ result |= (long) (b & 0x7F) << shift;
+ if ((b & 0x80) == 0)
+ return result;
+ shift += 7;
+ }
+ throw InvalidProtocolBufferException.malformedVarint();
+ }
+
+ /** Read a 32-bit little-endian integer from the stream. */
+ public int readRawLittleEndian32() throws IOException {
+ byte b1 = readRawByte();
+ byte b2 = readRawByte();
+ byte b3 = readRawByte();
+ byte b4 = readRawByte();
+ return (((int) b1 & 0xff)) | (((int) b2 & 0xff) << 8) | (((int) b3 & 0xff) << 16) | (((int) b4 & 0xff) << 24);
+ }
+
+ /** Read a 64-bit little-endian integer from the stream. */
+ public long readRawLittleEndian64() throws IOException {
+ byte b1 = readRawByte();
+ byte b2 = readRawByte();
+ byte b3 = readRawByte();
+ byte b4 = readRawByte();
+ byte b5 = readRawByte();
+ byte b6 = readRawByte();
+ byte b7 = readRawByte();
+ byte b8 = readRawByte();
+ return (((long) b1 & 0xff)) | (((long) b2 & 0xff) << 8) | (((long) b3 & 0xff) << 16) | (((long) b4 & 0xff) << 24) | (((long) b5 & 0xff) << 32) | (((long) b6 & 0xff) << 40) | (((long) b7 & 0xff) << 48) | (((long) b8 & 0xff) << 56);
+ }
+
+ /**
+ * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into
+ * values that can be efficiently encoded with varint. (Otherwise, negative
+ * values must be sign-extended to 64 bits to be varint encoded, thus always
+ * taking 10 bytes on the wire.)
+ *
+ * @param n
+ * An unsigned 32-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ * @return A signed 32-bit integer.
+ */
+ public static int decodeZigZag32(int n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ /**
+ * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into
+ * values that can be efficiently encoded with varint. (Otherwise, negative
+ * values must be sign-extended to 64 bits to be varint encoded, thus always
+ * taking 10 bytes on the wire.)
+ *
+ * @param n
+ * An unsigned 64-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ * @return A signed 64-bit integer.
+ */
+ public static long decodeZigZag64(long n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ /**
+ * Read one byte from the input.
+ *
+ * @throws InvalidProtocolBufferException
+ * The end of the stream or the current limit was reached.
+ */
+ public byte readRawByte() throws IOException {
+ if( pos >= limit ) {
+ throw new EOFException();
+ }
+ int rc = in.read();
+ if( rc < 0 ) {
+ throw new EOFException();
+ }
+ pos++;
+ return (byte)( rc & 0xFF);
+ }
+
+ /**
+ * Read a fixed size of bytes from the input.
+ *
+ * @throws InvalidProtocolBufferException
+ * The end of the stream or the current limit was reached.
+ */
+ public Buffer readRawBytes(int size) throws IOException {
+ if( size == 0) {
+ return new Buffer(new byte[]{});
+ }
+ if( this.pos+size > limit ) {
+ throw new EOFException();
+ }
+
+ // If the underlying stream is a ByteArrayInputStream
+ // then we can avoid an array copy.
+ if( bis!=null ) {
+ Buffer rc = bis.readBuffer(size);
+ if( rc==null || rc.getLength() < size ) {
+ throw new EOFException();
+ }
+ this.pos += rc.getLength();
+ return rc;
+ }
+
+ // Otherwise we, have to do it the old fasioned way
+ byte[] rc = new byte[size];
+ int c;
+ int pos=0;
+ while( pos < size ) {
+ c = in.read(rc, pos, size-pos);
+ if( c < 0 ) {
+ throw new EOFException();
+ }
+ this.pos += c;
+ pos += c;
+ }
+
+ return new Buffer(rc);
+ }
+
+ /**
+ * Reads and discards {@code size} bytes.
+ *
+ * @throws InvalidProtocolBufferException
+ * The end of the stream or the current limit was reached.
+ */
+ public void skipRawBytes(int size) throws IOException {
+ int pos = 0;
+ while (pos < size) {
+ int n = (int) in.skip(size - pos);
+ pos += n;
+ }
+ }
+
+ public int pushLimit(int limit) {
+ int rc = this.limit;
+ this.limit = pos+limit;
+ return rc;
+ }
+
+ public void popLimit(int limit) {
+ this.limit = limit;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/CodedOutputStream.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/CodedOutputStream.java
new file mode 100644
index 0000000000..f705c83bbe
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/CodedOutputStream.java
@@ -0,0 +1,481 @@
+//Protocol Buffers - Google's data interchange format
+//Copyright 2008 Google Inc.
+//http://code.google.com/p/protobuf/
+//
+//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.apache.activemq.protobuf;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Encodes and writes protocol message fields.
+ *
+ *
+ * This class contains two kinds of methods: methods that write specific
+ * protocol message constructs and field types (e.g. {@link #writeTag} and
+ * {@link #writeInt32}) and methods that write low-level values (e.g.
+ * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are writing
+ * encoded protocol messages, you should use the former methods, but if you are
+ * writing some other format of your own design, use the latter.
+ *
+ *
+ * This class is totally unsynchronized.
+ *
+ * @author kneton@google.com Kenton Varda
+ */
+public final class CodedOutputStream extends FilterOutputStream {
+
+ private BufferOutputStream bos;
+
+ public CodedOutputStream(OutputStream os) {
+ super(os);
+ if( os instanceof BufferOutputStream ) {
+ bos = (BufferOutputStream)os;
+ }
+ }
+
+ public CodedOutputStream(byte[] data) {
+ super(new BufferOutputStream(data));
+ }
+
+ public CodedOutputStream(Buffer data) {
+ super(new BufferOutputStream(data));
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Write a {@code double} field, including tag, to the stream. */
+ public void writeDouble(int fieldNumber, double value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeRawLittleEndian64(Double.doubleToRawLongBits(value));
+ }
+
+ /** Write a {@code float} field, including tag, to the stream. */
+ public void writeFloat(int fieldNumber, float value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeRawLittleEndian32(Float.floatToRawIntBits(value));
+ }
+
+ /** Write a {@code uint64} field, including tag, to the stream. */
+ public void writeUInt64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int64} field, including tag, to the stream. */
+ public void writeInt64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int32} field, including tag, to the stream. */
+ public void writeInt32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ if (value >= 0) {
+ writeRawVarint32(value);
+ } else {
+ // Must sign-extend.
+ writeRawVarint64(value);
+ }
+ }
+
+ /** Write a {@code fixed64} field, including tag, to the stream. */
+ public void writeFixed64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write a {@code fixed32} field, including tag, to the stream. */
+ public void writeFixed32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write a {@code bool} field, including tag, to the stream. */
+ public void writeBool(int fieldNumber, boolean value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawByte(value ? 1 : 0);
+ }
+
+ /** Write a {@code string} field, including tag, to the stream. */
+ public void writeString(int fieldNumber, String value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ // Unfortunately there does not appear to be any way to tell Java to
+ // encode
+ // UTF-8 directly into our buffer, so we have to let it create its own
+ // byte
+ // array and then copy.
+ byte[] bytes = value.getBytes("UTF-8");
+ writeRawVarint32(bytes.length);
+ writeRawBytes(bytes);
+ }
+
+ /** Write a {@code bytes} field, including tag, to the stream. */
+ public void writeBytes(int fieldNumber, Buffer value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeRawVarint32(value.length);
+ writeRawBytes(value.data, value.offset, value.length);
+ }
+
+ /** Write a {@code uint32} field, including tag, to the stream. */
+ public void writeUInt32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint32(value);
+ }
+
+ /**
+ * Write an enum field, including tag, to the stream. Caller is responsible
+ * for converting the enum value to its numeric value.
+ */
+ public void writeEnum(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint32(value);
+ }
+
+ /** Write an {@code sfixed32} field, including tag, to the stream. */
+ public void writeSFixed32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write an {@code sfixed64} field, including tag, to the stream. */
+ public void writeSFixed64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write an {@code sint32} field, including tag, to the stream. */
+ public void writeSInt32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint32(encodeZigZag32(value));
+ }
+
+ /** Write an {@code sint64} field, including tag, to the stream. */
+ public void writeSInt64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint64(encodeZigZag64(value));
+ }
+
+ // =================================================================
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * double} field, including tag.
+ */
+ public static int computeDoubleSize(int fieldNumber, double value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * float} field, including tag.
+ */
+ public static int computeFloatSize(int fieldNumber, float value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * uint64} field, including tag.
+ */
+ public static int computeUInt64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an {@code
+ * int64} field, including tag.
+ */
+ public static int computeInt64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an {@code
+ * int32} field, including tag.
+ */
+ public static int computeInt32Size(int fieldNumber, int value) {
+ if (value >= 0) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ } else {
+ // Must sign-extend.
+ return computeTagSize(fieldNumber) + 10;
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * fixed64} field, including tag.
+ */
+ public static int computeFixed64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * fixed32} field, including tag.
+ */
+ public static int computeFixed32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code bool}
+ * field, including tag.
+ */
+ public static int computeBoolSize(int fieldNumber, boolean value) {
+ return computeTagSize(fieldNumber) + 1;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * string} field, including tag.
+ */
+ public static int computeStringSize(int fieldNumber, String value) {
+ try {
+ byte[] bytes = value.getBytes("UTF-8");
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(bytes.length) + bytes.length;
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported.", e);
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * bytes} field, including tag.
+ */
+ public static int computeBytesSize(int fieldNumber, Buffer value) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(value.length) + value.length;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a {@code
+ * uint32} field, including tag.
+ */
+ public static int computeUInt32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an enum field,
+ * including tag. Caller is responsible for converting the enum value to its
+ * numeric value.
+ */
+ public static int computeEnumSize(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an {@code
+ * sfixed32} field, including tag.
+ */
+ public static int computeSFixed32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an {@code
+ * sfixed64} field, including tag.
+ */
+ public static int computeSFixed64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an {@code
+ * sint32} field, including tag.
+ */
+ public static int computeSInt32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(encodeZigZag32(value));
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an {@code
+ * sint64} field, including tag.
+ */
+ public static int computeSInt64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + computeRawVarint64Size(encodeZigZag64(value));
+ }
+
+ /** Write a single byte. */
+ public void writeRawByte(byte value) throws IOException {
+ out.write(value);
+ }
+
+ /** Write a single byte, represented by an integer value. */
+ public void writeRawByte(int value) throws IOException {
+ writeRawByte((byte) value);
+ }
+
+ /** Write an array of bytes. */
+ public void writeRawBytes(byte[] value) throws IOException {
+ writeRawBytes(value, 0, value.length);
+ }
+
+ /** Write part of an array of bytes. */
+ public void writeRawBytes(byte[] value, int offset, int length) throws IOException {
+ out.write(value, offset, length);
+ }
+
+ public void writeRawBytes(Buffer data) throws IOException {
+ out.write(data.data, data.offset, data.length);
+ }
+
+ /** Encode and write a tag. */
+ public void writeTag(int fieldNumber, int wireType) throws IOException {
+ writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType));
+ }
+
+ /** Compute the number of bytes that would be needed to encode a tag. */
+ public static int computeTagSize(int fieldNumber) {
+ return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0));
+ }
+
+ /**
+ * Encode and write a varint. {@code value} is treated as unsigned, so it
+ * won't be sign-extended if negative.
+ */
+ public void writeRawVarint32(int value) throws IOException {
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ writeRawByte(value);
+ return;
+ } else {
+ writeRawByte((value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a varint.
+ * {@code value} is treated as unsigned, so it won't be sign-extended if
+ * negative.
+ */
+ public static int computeRawVarint32Size(int value) {
+ if ((value & (0xffffffff << 7)) == 0)
+ return 1;
+ if ((value & (0xffffffff << 14)) == 0)
+ return 2;
+ if ((value & (0xffffffff << 21)) == 0)
+ return 3;
+ if ((value & (0xffffffff << 28)) == 0)
+ return 4;
+ return 5;
+ }
+
+ /** Encode and write a varint. */
+ public void writeRawVarint64(long value) throws IOException {
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ writeRawByte((int) value);
+ return;
+ } else {
+ writeRawByte(((int) value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ /** Compute the number of bytes that would be needed to encode a varint. */
+ public static int computeRawVarint64Size(long value) {
+ if ((value & (0xffffffffffffffffL << 7)) == 0)
+ return 1;
+ if ((value & (0xffffffffffffffffL << 14)) == 0)
+ return 2;
+ if ((value & (0xffffffffffffffffL << 21)) == 0)
+ return 3;
+ if ((value & (0xffffffffffffffffL << 28)) == 0)
+ return 4;
+ if ((value & (0xffffffffffffffffL << 35)) == 0)
+ return 5;
+ if ((value & (0xffffffffffffffffL << 42)) == 0)
+ return 6;
+ if ((value & (0xffffffffffffffffL << 49)) == 0)
+ return 7;
+ if ((value & (0xffffffffffffffffL << 56)) == 0)
+ return 8;
+ if ((value & (0xffffffffffffffffL << 63)) == 0)
+ return 9;
+ return 10;
+ }
+
+ /** Write a little-endian 32-bit integer. */
+ public void writeRawLittleEndian32(int value) throws IOException {
+ writeRawByte((value) & 0xFF);
+ writeRawByte((value >> 8) & 0xFF);
+ writeRawByte((value >> 16) & 0xFF);
+ writeRawByte((value >> 24) & 0xFF);
+ }
+
+ public static final int LITTLE_ENDIAN_32_SIZE = 4;
+
+ /** Write a little-endian 64-bit integer. */
+ public void writeRawLittleEndian64(long value) throws IOException {
+ writeRawByte((int) (value) & 0xFF);
+ writeRawByte((int) (value >> 8) & 0xFF);
+ writeRawByte((int) (value >> 16) & 0xFF);
+ writeRawByte((int) (value >> 24) & 0xFF);
+ writeRawByte((int) (value >> 32) & 0xFF);
+ writeRawByte((int) (value >> 40) & 0xFF);
+ writeRawByte((int) (value >> 48) & 0xFF);
+ writeRawByte((int) (value >> 56) & 0xFF);
+ }
+
+ public static final int LITTLE_ENDIAN_64_SIZE = 8;
+
+ /**
+ * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into
+ * values that can be efficiently encoded with varint. (Otherwise, negative
+ * values must be sign-extended to 64 bits to be varint encoded, thus always
+ * taking 10 bytes on the wire.)
+ *
+ * @param n
+ * A signed 32-bit integer.
+ * @return An unsigned 32-bit integer, stored in a signed int because Java
+ * has no explicit unsigned support.
+ */
+ public static int encodeZigZag32(int n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 31);
+ }
+
+ /**
+ * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into
+ * values that can be efficiently encoded with varint. (Otherwise, negative
+ * values must be sign-extended to 64 bits to be varint encoded, thus always
+ * taking 10 bytes on the wire.)
+ *
+ * @param n
+ * A signed 64-bit integer.
+ * @return An unsigned 64-bit integer, stored in a signed int because Java
+ * has no explicit unsigned support.
+ */
+ public static long encodeZigZag64(long n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 63);
+ }
+
+ public void checkNoSpaceLeft() {
+ }
+
+ public Buffer getNextBuffer(int size) throws IOException {
+ if( bos==null ) {
+ return null;
+ }
+ return bos.getNextBuffer(size);
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java
new file mode 100644
index 0000000000..2815d98701
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import java.io.IOException;
+
+abstract public class DeferredDecodeMessage extends BaseMessage {
+
+ protected Buffer encodedForm;
+ protected boolean decoded = true;
+
+ @Override
+ public T mergeFramed(CodedInputStream input) throws IOException {
+ int length = input.readRawVarint32();
+ int oldLimit = input.pushLimit(length);
+ T rc = mergeUnframed(input.readRawBytes(length));
+ input.popLimit(oldLimit);
+ return rc;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public T mergeUnframed(Buffer data) throws InvalidProtocolBufferException {
+ encodedForm = data;
+ decoded = false;
+ return (T) this;
+ }
+
+ @Override
+ public Buffer toUnframedBuffer() {
+ if (encodedForm == null) {
+ encodedForm = super.toUnframedBuffer();
+ }
+ return encodedForm;
+ }
+
+ protected void load() {
+ if (!decoded) {
+ decoded = true;
+ try {
+ Buffer originalForm = encodedForm;
+ encodedForm=null;
+ CodedInputStream input = new CodedInputStream(originalForm);
+ mergeUnframed(input);
+ input.checkLastTagWas(0);
+ // We need to reset the encoded form because the mergeUnframed
+ // from a stream clears it out.
+ encodedForm = originalForm;
+ checktInitialized();
+ } catch (Throwable e) {
+ throw new RuntimeException("Deferred message decoding failed: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ protected void loadAndClear() {
+ super.loadAndClear();
+ load();
+ encodedForm = null;
+ }
+
+ public void clear() {
+ super.clear();
+ encodedForm = null;
+ decoded = true;
+ }
+
+ public boolean isDecoded() {
+ return decoded;
+ }
+
+ public boolean isEncoded() {
+ return encodedForm != null;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/InvalidProtocolBufferException.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/InvalidProtocolBufferException.java
new file mode 100644
index 0000000000..f6246056d0
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/InvalidProtocolBufferException.java
@@ -0,0 +1,66 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.apache.activemq.protobuf;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a protocol message being parsed is invalid in some way, e.g. it
+ * contains a malformed varint or a negative byte length.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class InvalidProtocolBufferException extends IOException {
+ private static final long serialVersionUID = 5685337441004132240L;
+
+ public InvalidProtocolBufferException(String description) {
+ super(description);
+ }
+
+ static InvalidProtocolBufferException truncatedMessage() {
+ return new InvalidProtocolBufferException("While parsing a protocol message, the input ended unexpectedly " + "in the middle of a field. This could mean either than the " + "input has been truncated or that an embedded message "
+ + "misreported its own length.");
+ }
+
+ static InvalidProtocolBufferException negativeSize() {
+ return new InvalidProtocolBufferException("CodedInputStream encountered an embedded string or message " + "which claimed to have negative size.");
+ }
+
+ static InvalidProtocolBufferException malformedVarint() {
+ return new InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.");
+ }
+
+ static InvalidProtocolBufferException invalidTag() {
+ return new InvalidProtocolBufferException("Protocol message contained an invalid tag (zero).");
+ }
+
+ static InvalidProtocolBufferException invalidEndTag() {
+ return new InvalidProtocolBufferException("Protocol message end-group tag did not match expected tag.");
+ }
+
+ static InvalidProtocolBufferException invalidWireType() {
+ return new InvalidProtocolBufferException("Protocol message tag had invalid wire type.");
+ }
+
+ static InvalidProtocolBufferException recursionLimitExceeded() {
+ return new InvalidProtocolBufferException("Protocol message had too many levels of nesting. May be malicious. " + "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
+ }
+
+ static InvalidProtocolBufferException sizeLimitExceeded() {
+ return new InvalidProtocolBufferException("Protocol message was too large. May be malicious. " + "Use CodedInputStream.setSizeLimit() to increase the size limit.");
+ }
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Message.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Message.java
new file mode 100644
index 0000000000..9a6fbfddc3
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Message.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public interface Message {
+
+ public T clone() throws CloneNotSupportedException;
+
+ public int serializedSizeUnframed();
+
+ public int serializedSizeFramed();
+
+ public void clear();
+
+ public T assertInitialized() throws UninitializedMessageException;
+
+ public T mergeFrom(T other);
+
+
+ public T mergeUnframed(byte[] data) throws InvalidProtocolBufferException;
+
+ public T mergeFramed(byte[] data) throws InvalidProtocolBufferException;
+
+ public T mergeUnframed(Buffer buffer) throws InvalidProtocolBufferException;
+
+ public T mergeFramed(Buffer buffer) throws InvalidProtocolBufferException;
+
+ public T mergeUnframed(InputStream input) throws IOException;
+
+ public T mergeFramed(InputStream input) throws IOException;
+
+ public T mergeUnframed(CodedInputStream input) throws IOException;
+
+ public T mergeFramed(CodedInputStream input) throws IOException;
+
+
+ public Buffer toUnframedBuffer();
+
+ public Buffer toFramedBuffer();
+
+ public byte[] toUnframedByteArray();
+
+ public byte[] toFramedByteArray();
+
+ public void writeUnframed(CodedOutputStream output) throws java.io.IOException;
+
+ public void writeFramed(CodedOutputStream output) throws java.io.IOException;
+
+ public void writeUnframed(OutputStream output) throws IOException;
+
+ public void writeFramed(OutputStream output) throws java.io.IOException;
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/MessageBuffer.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/MessageBuffer.java
new file mode 100644
index 0000000000..d95700d749
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/MessageBuffer.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public interface MessageBuffer extends PBMessage {
+
+ public int serializedSizeUnframed();
+
+ public int serializedSizeFramed();
+
+ public Buffer toUnframedBuffer();
+
+ public Buffer toFramedBuffer();
+
+ public byte[] toUnframedByteArray();
+
+ public byte[] toFramedByteArray();
+
+ public void writeUnframed(CodedOutputStream output) throws java.io.IOException;
+
+ public void writeFramed(CodedOutputStream output) throws java.io.IOException;
+
+ public void writeUnframed(OutputStream output) throws IOException;
+
+ public void writeFramed(OutputStream output) throws java.io.IOException;
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/MessageBufferSupport.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/MessageBufferSupport.java
new file mode 100644
index 0000000000..f49a0e1cd5
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/MessageBufferSupport.java
@@ -0,0 +1,140 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+
+
+final public class MessageBufferSupport {
+
+ public static final String FORZEN_ERROR_MESSAGE = "Modification not allowed after object has been fozen. Try modifying a copy of this object.";
+
+ static public Buffer toUnframedBuffer(MessageBuffer message) {
+ try {
+ int size = message.serializedSizeUnframed();
+ BufferOutputStream baos = new BufferOutputStream(size);
+ CodedOutputStream output = new CodedOutputStream(baos);
+ message.writeUnframed(output);
+ Buffer rc = baos.toBuffer();
+ assert rc.length == size : "Did not write as much data as expected.";
+ return rc;
+ } catch (IOException e) {
+ throw new RuntimeException("Serializing to a byte array threw an IOException " + "(should never happen).", e);
+ }
+ }
+
+ static public Buffer toFramedBuffer(MessageBuffer message) {
+ try {
+ int size = message.serializedSizeFramed();
+ BufferOutputStream baos = new BufferOutputStream(size);
+ CodedOutputStream output = new CodedOutputStream(baos);
+ message.writeFramed(output);
+ Buffer rc = baos.toBuffer();
+ assert rc.length==size : "Did not write as much data as expected.";
+ return rc;
+ } catch (IOException e) {
+ throw new RuntimeException("Serializing to a byte array threw an IOException " + "(should never happen).", e);
+ }
+ }
+
+ public static void writeMessage(CodedOutputStream output, int tag, MessageBuffer message) throws IOException {
+ output.writeTag(tag, WIRETYPE_LENGTH_DELIMITED);
+ message.writeFramed(output);
+ }
+
+ public static int computeMessageSize(int tag, MessageBuffer message) {
+ return CodedOutputStream.computeTagSize(tag) + message.serializedSizeFramed();
+ }
+
+ public static Buffer readFrame(java.io.InputStream input) throws IOException {
+ int length = readRawVarint32(input);
+ byte[] data = new byte[length];
+ int pos = 0;
+ while (pos < length) {
+ int r = input.read(data, pos, length - pos);
+ if (r < 0) {
+ throw new InvalidProtocolBufferException("Input stream ended before a full message frame could be read.");
+ }
+ pos += r;
+ }
+ return new Buffer(data);
+ }
+
+ /**
+ * Read a raw Varint from the stream. If larger than 32 bits, discard the
+ * upper bits.
+ */
+ static public int readRawVarint32(InputStream is) throws IOException {
+ byte tmp = readRawByte(is);
+ if (tmp >= 0) {
+ return tmp;
+ }
+ int result = tmp & 0x7f;
+ if ((tmp = readRawByte(is)) >= 0) {
+ result |= tmp << 7;
+ } else {
+ result |= (tmp & 0x7f) << 7;
+ if ((tmp = readRawByte(is)) >= 0) {
+ result |= tmp << 14;
+ } else {
+ result |= (tmp & 0x7f) << 14;
+ if ((tmp = readRawByte(is)) >= 0) {
+ result |= tmp << 21;
+ } else {
+ result |= (tmp & 0x7f) << 21;
+ result |= (tmp = readRawByte(is)) << 28;
+ if (tmp < 0) {
+ // Discard upper 32 bits.
+ for (int i = 0; i < 5; i++) {
+ if (readRawByte(is) >= 0)
+ return result;
+ }
+ throw new InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.");
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ static public byte readRawByte(InputStream is) throws IOException {
+ int rc = is.read();
+ if (rc == -1) {
+ throw new InvalidProtocolBufferException("While parsing a protocol message, the input ended unexpectedly " + "in the middle of a field. This could mean either than the " + "input has been truncated or that an embedded message "
+ + "misreported its own length.");
+ }
+ return (byte) rc;
+ }
+
+ static public void addAll(Iterable values, Collection super T> list) {
+ if (values instanceof Collection) {
+ @SuppressWarnings("unsafe")
+ Collection collection = (Collection) values;
+ list.addAll(collection);
+ } else {
+ for (T value : values) {
+ list.add(value);
+ }
+ }
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/PBMessage.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/PBMessage.java
new file mode 100644
index 0000000000..6996f67eec
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/PBMessage.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+public interface PBMessage {
+ public Bean copy();
+ public boolean frozen();
+ public Buffer freeze();
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UTF8Buffer.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UTF8Buffer.java
new file mode 100644
index 0000000000..62c0deeb0b
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UTF8Buffer.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf;
+
+import java.io.UnsupportedEncodingException;
+
+final public class UTF8Buffer extends Buffer {
+
+ int hashCode;
+ String value;
+
+ public UTF8Buffer(Buffer other) {
+ super(other);
+ }
+
+ public UTF8Buffer(byte[] data, int offset, int length) {
+ super(data, offset, length);
+ }
+
+ public UTF8Buffer(byte[] data) {
+ super(data);
+ }
+
+ public UTF8Buffer(String input) {
+ super(encode(input));
+ }
+
+ public UTF8Buffer compact() {
+ if (length != data.length) {
+ return new UTF8Buffer(toByteArray());
+ }
+ return this;
+ }
+
+ public String toString()
+ {
+ if( value==null ) {
+ value = decode(this);
+ }
+ return value;
+ }
+
+ @Override
+ public int compareTo(Buffer other) {
+ // Do a char comparison.. not a byte for byte comparison.
+ return toString().compareTo(other.toString());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if( obj==this )
+ return true;
+
+ if( obj==null || obj.getClass()!=UTF8Buffer.class )
+ return false;
+
+ return equals((Buffer)obj);
+ }
+
+ @Override
+ public int hashCode() {
+ if( hashCode==0 ) {
+ hashCode = super.hashCode();;
+ }
+ return hashCode;
+ }
+
+ static public byte[] encode(String value)
+ {
+ try {
+ return value.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("A UnsupportedEncodingException was thrown for teh UTF-8 encoding. (This should never happen)");
+ }
+ }
+
+ static public String decode(Buffer buffer)
+ {
+ try {
+ return new String(buffer.getData(), buffer.getOffset(), buffer.getLength(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("A UnsupportedEncodingException was thrown for teh UTF-8 encoding. (This should never happen)");
+ }
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UninitializedMessageException.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UninitializedMessageException.java
new file mode 100644
index 0000000000..3e17dae0f2
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UninitializedMessageException.java
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.apache.activemq.protobuf;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Thrown when attempting to build a protocol message that is missing required
+ * fields. This is a {@code RuntimeException} because it normally represents a
+ * programming error: it happens when some code which constructs a message fails
+ * to set all the fields. {@code parseFrom()} methods do not throw this;
+ * they throw an {@link InvalidProtocolBufferException} if required fields are
+ * missing, because it is not a programming error to receive an incomplete
+ * message. In other words, {@code UninitializedMessageException} should never
+ * be thrown by correct code, but {@code InvalidProtocolBufferException} might
+ * be.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class UninitializedMessageException extends RuntimeException {
+
+ public UninitializedMessageException(List missingFields) {
+ super(buildDescription(missingFields));
+ this.missingFields = missingFields;
+ }
+
+ private final List missingFields;
+
+ /**
+ * Get a list of human-readable names of required fields missing from this
+ * message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
+ */
+ public List getMissingFields() {
+ return Collections.unmodifiableList(missingFields);
+ }
+
+ /**
+ * Converts this exception to an {@link InvalidProtocolBufferException}.
+ * When a parsed message is missing required fields, this should be thrown
+ * instead of {@code UninitializedMessageException}.
+ */
+ public InvalidProtocolBufferException asInvalidProtocolBufferException() {
+ return new InvalidProtocolBufferException(getMessage());
+ }
+
+ /** Construct the description string for this exception. */
+ private static String buildDescription(List missingFields) {
+ StringBuilder description = new StringBuilder("Message missing required fields: ");
+ boolean first = true;
+ for (String field : missingFields) {
+ if (first) {
+ first = false;
+ } else {
+ description.append(", ");
+ }
+ description.append(field);
+ }
+ return description.toString();
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/WireFormat.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/WireFormat.java
new file mode 100644
index 0000000000..3018bb778a
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/WireFormat.java
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.apache.activemq.protobuf;
+
+/**
+ * This class is used internally by the Protocol Buffer library and generated
+ * message implementations. It is public only because those generated messages
+ * do not reside in the {@code protocol2} package. Others should not use this
+ * class directly.
+ *
+ * This class contains constants and helper functions useful for dealing with
+ * the Protocol Buffer wire format.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class WireFormat {
+ // Do not allow instantiation.
+ private WireFormat() {
+ }
+
+ public static final int WIRETYPE_VARINT = 0;
+ public static final int WIRETYPE_FIXED64 = 1;
+ public static final int WIRETYPE_LENGTH_DELIMITED = 2;
+ public static final int WIRETYPE_START_GROUP = 3;
+ public static final int WIRETYPE_END_GROUP = 4;
+ public static final int WIRETYPE_FIXED32 = 5;
+
+ public static final int TAG_TYPE_BITS = 3;
+ public static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
+
+ /** Given a tag value, determines the wire type (the lower 3 bits). */
+ public static int getTagWireType(int tag) {
+ return tag & TAG_TYPE_MASK;
+ }
+
+ /** Given a tag value, determines the field number (the upper 29 bits). */
+ public static int getTagFieldNumber(int tag) {
+ return tag >>> TAG_TYPE_BITS;
+ }
+
+ /** Makes a tag value given a field number and wire type. */
+ public static int makeTag(int fieldNumber, int wireType) {
+ return (fieldNumber << TAG_TYPE_BITS) | wireType;
+ }
+
+ // Field numbers for feilds in MessageSet wire format.
+ public static final int MESSAGE_SET_ITEM = 1;
+ public static final int MESSAGE_SET_TYPE_ID = 2;
+ public static final int MESSAGE_SET_MESSAGE = 3;
+
+ // Tag numbers.
+ public static final int MESSAGE_SET_ITEM_TAG = makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
+ public static final int MESSAGE_SET_ITEM_END_TAG = makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
+ public static final int MESSAGE_SET_TYPE_ID_TAG = makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
+ public static final int MESSAGE_SET_MESSAGE_TAG = makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/AltJavaGenerator.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/AltJavaGenerator.java
new file mode 100644
index 0000000000..8bba8bc98f
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/AltJavaGenerator.java
@@ -0,0 +1,2405 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_FIXED32;
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_FIXED64;
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED;
+import static org.apache.activemq.protobuf.WireFormat.WIRETYPE_VARINT;
+import static org.apache.activemq.protobuf.WireFormat.makeTag;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.activemq.protobuf.compiler.parser.ParseException;
+import org.apache.activemq.protobuf.compiler.parser.ProtoParser;
+
+public class AltJavaGenerator {
+
+ private File out = new File(".");
+ private File[] path = new File[]{new File(".")};
+
+ private ProtoDescriptor proto;
+ private String javaPackage;
+ private String outerClassName;
+ private PrintWriter w;
+ private int indent;
+ private ArrayList errors = new ArrayList();
+ private boolean multipleFiles;
+ private boolean auto_clear_optional_fields;
+
+ public static void main(String[] args) {
+
+ AltJavaGenerator generator = new AltJavaGenerator();
+ args = CommandLineSupport.setOptions(generator, args);
+
+ if (args.length == 0) {
+ System.out.println("No proto files specified.");
+ }
+ for (int i = 0; i < args.length; i++) {
+ try {
+ System.out.println("Compiling: "+args[i]);
+ generator.compile(new File(args[i]));
+ } catch (CompilerException e) {
+ System.out.println("Protocol Buffer Compiler failed with the following error(s):");
+ for (String error : e.getErrors() ) {
+ System.out.println("");
+ System.out.println(error);
+ }
+ System.out.println("");
+ System.out.println("Compile failed. For more details see error messages listed above.");
+ return;
+ }
+ }
+
+ }
+
+ interface Closure {
+ void execute() throws CompilerException;
+ }
+
+ public void compile(File file) throws CompilerException {
+
+ // Parse the proto file
+ FileInputStream is=null;
+ try {
+ is = new FileInputStream(file);
+ ProtoParser parser = new ProtoParser(is);
+ proto = parser.ProtoDescriptor();
+ proto.setName(file.getName());
+ loadImports(proto, file.getParentFile());
+ proto.validate(errors);
+ } catch (FileNotFoundException e) {
+ errors.add("Failed to open: "+file.getPath()+":"+e.getMessage());
+ } catch (ParseException e) {
+ errors.add("Failed to parse: "+file.getPath()+":"+e.getMessage());
+ } finally {
+ try { is.close(); } catch (Throwable ignore){}
+ }
+
+ if (!errors.isEmpty()) {
+ throw new CompilerException(errors);
+ }
+
+ // Load the options..
+ javaPackage = javaPackage(proto);
+ outerClassName = javaClassName(proto);
+// optimizeFor = getOption(proto.getOptions(), "optimize_for", "SPEED");
+ multipleFiles = isMultipleFilesEnabled(proto);
+// deferredDecode = Boolean.parseBoolean(getOption(proto.getOptions(), "deferred_decode", "false"));
+ auto_clear_optional_fields = Boolean.parseBoolean(getOption(proto.getOptions(), "auto_clear_optional_fields", "false"));
+
+ if( multipleFiles ) {
+ generateProtoFile();
+ } else {
+ writeFile(outerClassName, new Closure(){
+ public void execute() throws CompilerException {
+ generateProtoFile();
+ }
+ });
+ }
+
+ if (!errors.isEmpty()) {
+ throw new CompilerException(errors);
+ }
+
+ }
+
+ private void writeFile(String className, Closure closure) throws CompilerException {
+ PrintWriter oldWriter = w;
+ // Figure out the java file name..
+ File outputFile = out;
+ if (javaPackage != null) {
+ String packagePath = javaPackage.replace('.', '/');
+ outputFile = new File(outputFile, packagePath);
+ }
+ outputFile = new File(outputFile, className + ".java");
+
+ // Start writing the output file..
+ outputFile.getParentFile().mkdirs();
+
+ FileOutputStream fos=null;
+ try {
+ fos = new FileOutputStream(outputFile);
+ w = new PrintWriter(fos);
+ closure.execute();
+ w.flush();
+ } catch (FileNotFoundException e) {
+ errors.add("Failed to write to: "+outputFile.getPath()+":"+e.getMessage());
+ } finally {
+ try { fos.close(); } catch (Throwable ignore){}
+ w = oldWriter;
+ }
+ }
+
+ private void loadImports(ProtoDescriptor proto, File protoDir) {
+ LinkedHashMap children = new LinkedHashMap();
+ for (String imp : proto.getImports()) {
+ File file = new File(protoDir, imp);
+ for (int i = 0; i < path.length && !file.exists(); i++) {
+ file = new File(path[i], imp);
+ }
+ if ( !file.exists() ) {
+ errors.add("Cannot load import: "+imp);
+ }
+
+ FileInputStream is=null;
+ try {
+ is = new FileInputStream(file);
+ ProtoParser parser = new ProtoParser(is);
+ ProtoDescriptor child = parser.ProtoDescriptor();
+ child.setName(file.getName());
+ loadImports(child, file.getParentFile());
+ children.put(imp, child);
+ } catch (ParseException e) {
+ errors.add("Failed to parse: "+file.getPath()+":"+e.getMessage());
+ } catch (FileNotFoundException e) {
+ errors.add("Failed to open: "+file.getPath()+":"+e.getMessage());
+ } finally {
+ try { is.close(); } catch (Throwable ignore){}
+ }
+ }
+ proto.setImportProtoDescriptors(children);
+ }
+
+
+ private void generateProtoFile() throws CompilerException {
+ if( multipleFiles ) {
+ for (EnumDescriptor value : proto.getEnums().values()) {
+ final EnumDescriptor o = value;
+ String className = uCamel(o.getName());
+ writeFile(className, new Closure(){
+ public void execute() throws CompilerException {
+ generateFileHeader();
+ generateEnum(o);
+ }
+ });
+ }
+ for (MessageDescriptor value : proto.getMessages().values()) {
+ final MessageDescriptor o = value;
+ String className = uCamel(o.getName());
+ writeFile(className, new Closure(){
+ public void execute() throws CompilerException {
+ generateFileHeader();
+ generateMessageBean(o);
+ }
+ });
+ }
+
+ } else {
+ generateFileHeader();
+
+ p("public class " + outerClassName + " {");
+ indent();
+
+ for (EnumDescriptor enumType : proto.getEnums().values()) {
+ generateEnum(enumType);
+ }
+ for (MessageDescriptor m : proto.getMessages().values()) {
+ generateMessageBean(m);
+ }
+
+ unindent();
+ p("}");
+ }
+ }
+
+ private void generateFileHeader() {
+ p("//");
+ p("// Generated by protoc, do not edit by hand.");
+ p("//");
+ if (javaPackage != null) {
+ p("package " + javaPackage + ";");
+ p("");
+ }
+ }
+
+ private void generateMessageBean(MessageDescriptor m) {
+
+ String className = uCamel(m.getName());
+ String beanClassName = className+"Bean";
+ String bufferClassName = className+"Buffer";
+ p();
+
+ String staticOption = "static ";
+ if( multipleFiles && m.getParent()==null ) {
+ staticOption="";
+ }
+
+ String extendsClause = " extends org.apache.activemq.protobuf.PBMessage<"+className+"."+beanClassName+", "+className+"."+bufferClassName+">";
+ for (EnumFieldDescriptor enumFeild : m.getAssociatedEnumFieldDescriptors()) {
+ String name = uCamel(enumFeild.getParent().getName());
+ name = name+"."+name+"Creatable";
+ extendsClause += ", "+name;
+ }
+
+ p(staticOption+"public interface " + className + extendsClause +" {");
+ p();
+ indent();
+
+ for (EnumDescriptor enumType : m.getEnums().values()) {
+ generateEnum(enumType);
+ }
+
+ // Generate the Nested Messages.
+ for (MessageDescriptor subMessage : m.getMessages().values()) {
+ generateMessageBean(subMessage);
+ }
+
+ // Generate the Group Messages
+ for (FieldDescriptor field : m.getFields().values()) {
+ if( field.isGroup() ) {
+ generateMessageBean(field.getGroup());
+ }
+ }
+
+ // Generate the field getters
+ for (FieldDescriptor field : m.getFields().values()) {
+ generateFieldGetterSignatures(field);
+ }
+
+ p("public "+beanClassName+" copy();");
+ p("public "+bufferClassName+" freeze();");
+ p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, String prefix);");
+
+
+ p();
+ p("static public final class "+beanClassName+" implements "+className+" {");
+ p();
+ indent();
+
+ p(""+bufferClassName+" frozen;");
+ p(""+beanClassName+" bean;");
+ p();
+ p("public "+beanClassName+"() {");
+ indent();
+ p("this.bean = this;");
+ unindent();
+ p("}");
+ p();
+ p("public "+beanClassName+"("+beanClassName+" copy) {");
+ indent();
+ p("this.bean = copy;");
+ unindent();
+ p("}");
+ p();
+ p("public "+beanClassName+" copy() {");
+ indent();
+ p("return new "+beanClassName+"(bean);");
+ unindent();
+ p("}");
+ p();
+
+ generateMethodFreeze(m, bufferClassName);
+
+ p("private void copyCheck() {");
+ indent();
+ p("assert frozen==null : org.apache.activemq.protobuf.MessageBufferSupport.FORZEN_ERROR_MESSAGE;");
+ p("if (bean != this) {");
+ indent();
+ p("copy(bean);");
+ unindent();
+ p("}");
+ unindent();
+ p("}");
+ p();
+
+ generateMethodCopyFromBean(m, beanClassName);
+
+ // Generate the field accessors..
+ for (FieldDescriptor field : m.getFields().values()) {
+ generateFieldAccessor(beanClassName, field);
+ }
+
+ generateMethodToString(m);
+
+ generateMethodMergeFromStream(m, beanClassName);
+
+ generateBeanEquals(m, beanClassName);
+
+ generateMethodMergeFromBean(m, className);
+
+ generateMethodClear(m);
+
+ generateReadWriteExternal(m);
+
+ for (EnumFieldDescriptor enumFeild : m.getAssociatedEnumFieldDescriptors()) {
+ String enumName = uCamel(enumFeild.getParent().getName());
+ p("public "+enumName+" to"+enumName+"() {");
+ indent();
+ p("return "+enumName+"."+enumFeild.getName()+";");
+ unindent();
+ p("}");
+ p();
+ }
+
+ unindent();
+ p("}");
+ p();
+
+ p("static public final class "+bufferClassName+" implements org.apache.activemq.protobuf.MessageBuffer<"+className+"."+beanClassName+", "+className+"."+bufferClassName+">, "+className+" {");
+ p();
+ indent();
+
+ p("private "+beanClassName+" bean;");
+ p("private org.apache.activemq.protobuf.Buffer buffer;");
+ p("private int size=-1;");
+ p("private int hashCode;");
+ p();
+ p("private "+bufferClassName+"(org.apache.activemq.protobuf.Buffer buffer) {");
+ indent();
+ p("this.buffer = buffer;");
+ unindent();
+ p("}");
+ p();
+ p("private "+bufferClassName+"("+beanClassName+" bean) {");
+ indent();
+ p("this.bean = bean;");
+ unindent();
+ p("}");
+ p();
+ p("public "+beanClassName+" copy() {");
+ indent();
+ p("return bean().copy();");
+ unindent();
+ p("}");
+ p();
+ p("public "+bufferClassName+" freeze() {");
+ indent();
+ p("return this;");
+ unindent();
+ p("}");
+ p();
+ p("private "+beanClassName+" bean() {");
+ indent();
+ p("if (bean == null) {");
+ indent();
+ p("try {");
+ indent();
+ p("bean = new "+beanClassName+"().mergeUnframed(new org.apache.activemq.protobuf.CodedInputStream(buffer));");
+ p("bean.frozen=this;");
+ unindent();
+ p("} catch (org.apache.activemq.protobuf.InvalidProtocolBufferException e) {");
+ indent();
+ p("throw new RuntimeException(e);");
+ unindent();
+ p("} catch (java.io.IOException e) {");
+ indent();
+ p("throw new RuntimeException(\"An IOException was thrown (should never happen in this method).\", e);");
+ unindent();
+ p("}");
+ unindent();
+ p("}");
+ p("return bean;");
+ unindent();
+ p("}");
+ p();
+
+ p("public String toString() {");
+ indent();
+ p("return bean().toString();");
+ unindent();
+ p("}");
+ p();
+ p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, String prefix) {");
+ indent();
+ p("return bean().toString(sb, prefix);");
+ unindent();
+ p("}");
+ p();
+
+ for (FieldDescriptor field : m.getFields().values()) {
+ generateBufferGetters(field);
+ }
+
+ generateMethodWrite(m);
+
+ generateMethodSerializedSize(m);
+
+ generateMethodParseFrom(m, bufferClassName, beanClassName);
+
+ generateBufferEquals(m, bufferClassName);
+
+ p("public boolean frozen() {");
+ indent();
+ p("return true;");
+ unindent();
+ p("}");
+
+ for (EnumFieldDescriptor enumFeild : m.getAssociatedEnumFieldDescriptors()) {
+ String enumName = uCamel(enumFeild.getParent().getName());
+ p("public "+enumName+" to"+enumName+"() {");
+ indent();
+ p("return "+enumName+"."+enumFeild.getName()+";");
+ unindent();
+ p("}");
+ p();
+ }
+
+ unindent();
+ p("}");
+ p();
+
+
+// generateMethodVisitor(m);
+// generateMethodType(m, className);
+
+
+ unindent();
+ p("}");
+ p();
+
+ }
+
+
+ private void generateMethodFreeze(MessageDescriptor m, String bufferClassName) {
+ p("public boolean frozen() {");
+ indent();
+ p("return frozen!=null;");
+ unindent();
+ p("}");
+ p();
+ p("public "+bufferClassName+" freeze() {");
+ indent();
+ p("if( frozen==null ) {");
+ indent();
+ p("frozen = new "+bufferClassName+"(bean);");
+ p("assert deepFreeze();");
+ unindent();
+ p("}");
+ p("return frozen;");
+ unindent();
+ p("}");
+ p();
+ p("private boolean deepFreeze() {");
+ indent();
+ p("frozen.serializedSizeUnframed();");
+ p("return true;");
+ unindent();
+ p("}");
+ p();
+
+ }
+
+ /**
+ * @param m
+ * @param className
+ */
+ private void generateMethodCopyFromBean(MessageDescriptor m, String className) {
+ p("private void copy("+className+" other) {");
+ indent();
+ p("this.bean = this;");
+ for (FieldDescriptor field : m.getFields().values()) {
+ String lname = lCamel(field.getName());
+ String type = field.getRule()==FieldDescriptor.REPEATED_RULE ? javaCollectionType(field):javaType(field);
+ boolean primitive = field.getTypeDescriptor()==null || field.getTypeDescriptor().isEnum();
+ if( field.isRepeated() ) {
+ if( primitive ) {
+ p("this.f_" + lname + " = other.f_" + lname + ";");
+ p("if( this.f_" + lname + " !=null && !other.frozen()) {");
+ indent();
+ p("this.f_" + lname + " = new java.util.ArrayList<"+type+">(this.f_" + lname + ");");
+ unindent();
+ p("}");
+ } else {
+ p("this.f_" + lname + " = other.f_" + lname + ";");
+ p("if( this.f_" + lname + " !=null) {");
+ indent();
+ p("this.f_" + lname + " = new java.util.ArrayList<"+type+">(other.f_" + lname + ".size());");
+ p("for( "+type+" e : other.f_" + lname + ") {");
+ indent();
+ p("this.f_" + lname + ".add(e.copy());");
+ unindent();
+ p("}");
+ unindent();
+ p("}");
+ }
+ } else {
+ if( primitive ) {
+ p("this.f_" + lname + " = other.f_" + lname + ";");
+ p("this.b_" + lname + " = other.b_" + lname + ";");
+ } else {
+ p("this.f_" + lname + " = other.f_" + lname + ";");
+ p("if( this.f_" + lname + " !=null ) {");
+ indent();
+ p("this.f_" + lname + " = this.f_" + lname + ".copy();");
+ unindent();
+ p("}");
+ }
+ }
+ }
+ unindent();
+ p("}");
+ p();
+ }
+
+
+ /**
+ * If the java_visitor message option is set, then this method generates a visitor method. The option
+ * speifiies the class name of the visitor and optionally the return value and exceptions thrown by the visitor.
+ *
+ * Examples:
+ *
+ * option java_visitor = "org.apache.kahadb.store.Visitor";
+ * generates:
+ * public void visit(org.apache.kahadb.store.Visitor visitor) {
+ * visitor.visit(this);
+ * }
+ *
+ * option java_visitor = "org.apache.kahadb.store.Visitor:int:java.io.IOException";
+ * generates:
+ * public int visit(org.apache.kahadb.store.Visitor visitor) throws java.io.IOException {
+ * return visitor.visit(this);
+ * }
+ *
+ * @param m
+ */
+ private void generateMethodVisitor(MessageDescriptor m) {
+ String javaVisitor = getOption(m.getOptions(), "java_visitor", null);
+ if( javaVisitor!=null ) {
+ String returns = "void";
+ String throwsException = null;
+
+ StringTokenizer st = new StringTokenizer(javaVisitor, ":");
+ String vistorClass = st.nextToken();
+ if( st.hasMoreTokens() ) {
+ returns = st.nextToken();
+ }
+ if( st.hasMoreTokens() ) {
+ throwsException = st.nextToken();
+ }
+
+ String throwsClause = "";
+ if( throwsException!=null ) {
+ throwsClause = "throws "+throwsException+" ";
+ }
+
+ p("public "+returns+" visit("+vistorClass+" visitor) "+throwsClause+ "{");
+ indent();
+ if( "void".equals(returns) ) {
+ p("visitor.visit(this);");
+ } else {
+ p("return visitor.visit(this);");
+ }
+ unindent();
+ p("}");
+ p();
+ }
+ }
+
+ private void generateMethodType(MessageDescriptor m, String className) {
+ String typeEnum = getOption(m.getOptions(), "java_type_method", null);
+ if( typeEnum!=null ) {
+
+ TypeDescriptor typeDescriptor = m.getType(typeEnum);
+ if( typeDescriptor == null ) {
+ typeDescriptor = m.getProtoDescriptor().getType(typeEnum);
+ }
+ if( typeDescriptor == null || !typeDescriptor.isEnum() ) {
+ errors.add("The java_type_method option on the "+m.getName()+" message does not point to valid enum type");
+ return;
+ }
+
+
+ String constant = constantCase(className);
+ EnumDescriptor enumDescriptor = (EnumDescriptor)typeDescriptor;
+ if( enumDescriptor.getFields().get(constant) == null ) {
+ errors.add("The java_type_method option on the "+m.getName()+" message does not points to the "+typeEnum+" enum but it does not have an entry for "+constant);
+ }
+
+ String type = javaType(typeDescriptor);
+
+ p("public "+type+" type() {");
+ indent();
+ p("return "+type+"."+constant+";");
+ unindent();
+ p("}");
+ p();
+ }
+ }
+
+ private void generateMethodParseFrom(MessageDescriptor m, String bufferClassName, String beanClassName) {
+ p("public static "+beanClassName+" parseUnframed(org.apache.activemq.protobuf.CodedInputStream data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException, java.io.IOException {");
+ indent();
+ p("return new "+beanClassName+"().mergeUnframed(data);");
+ unindent();
+ p("}");
+ p();
+ p("public static "+beanClassName+" parseUnframed(java.io.InputStream data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException, java.io.IOException {");
+ indent();
+ p("return parseUnframed(new org.apache.activemq.protobuf.CodedInputStream(data));");
+ unindent();
+ p("}");
+ p();
+ p("public static "+bufferClassName+" parseUnframed(org.apache.activemq.protobuf.Buffer data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException {");
+ indent();
+ p("return new "+bufferClassName+"(data);");
+ unindent();
+ p("}");
+ p();
+ p("public static "+bufferClassName+" parseUnframed(byte[] data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException {");
+ indent();
+ p("return parseUnframed(new org.apache.activemq.protobuf.Buffer(data));");
+ unindent();
+ p("}");
+ p();
+ p("public static "+bufferClassName+" parseFramed(org.apache.activemq.protobuf.CodedInputStream data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException, java.io.IOException {");
+ indent();
+ p("int length = data.readRawVarint32();");
+ p("int oldLimit = data.pushLimit(length);");
+ p(""+bufferClassName+" rc = parseUnframed(data.readRawBytes(length));");
+ p("data.popLimit(oldLimit);");
+ p("return rc;");
+ unindent();
+ p("}");
+ p();
+ p("public static "+bufferClassName+" parseFramed(org.apache.activemq.protobuf.Buffer data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException {");
+ indent();
+ p("try {");
+ indent();
+ p("org.apache.activemq.protobuf.CodedInputStream input = new org.apache.activemq.protobuf.CodedInputStream(data);");
+ p(""+bufferClassName+" rc = parseFramed(input);");
+ p("input.checkLastTagWas(0);");
+ p("return rc;");
+ unindent();
+ p("} catch (org.apache.activemq.protobuf.InvalidProtocolBufferException e) {");
+ indent();
+ p("throw e;");
+ unindent();
+ p("} catch (java.io.IOException e) {");
+ indent();
+ p("throw new RuntimeException(\"An IOException was thrown (should never happen in this method).\", e);");
+ unindent();
+ p("}");
+ unindent();
+ p("}");
+ p();
+ p("public static "+bufferClassName+" parseFramed(byte[] data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException {");
+ indent();
+ p("return parseFramed(new org.apache.activemq.protobuf.Buffer(data));");
+ unindent();
+ p("}");
+ p();
+ p("public static "+bufferClassName+" parseFramed(java.io.InputStream data) throws org.apache.activemq.protobuf.InvalidProtocolBufferException, java.io.IOException {");
+ indent();
+ p("return parseUnframed(org.apache.activemq.protobuf.MessageBufferSupport.readFrame(data));");
+ unindent();
+ p("}");
+ p();
+
+ }
+
+ private void generateBeanEquals(MessageDescriptor m, String className) {
+ p("public boolean equals(Object obj) {");
+ indent();
+ p("if( obj==this )");
+ p(" return true;");
+ p("");
+ p("if( obj==null || obj.getClass()!="+className+".class )");
+ p(" return false;");
+ p("");
+ p("return equals(("+className+")obj);");
+ unindent();
+ p("}");
+ p("");
+
+ p("public boolean equals("+className+" obj) {");
+ indent();
+ for (FieldDescriptor field : m.getFields().values()) {
+ String uname = uCamel(field.getName());
+ String getterMethod="get"+uname+"()";
+ String hasMethod = "has"+uname+"()";
+
+ if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+ getterMethod = "get"+uname+"List()";
+ }
+
+ p("if ("+hasMethod+" ^ obj."+hasMethod+" ) ");
+ p(" return false;");
+
+
+
+ if( field.getRule() != FieldDescriptor.REPEATED_RULE && (field.isNumberType() || field.getType()==FieldDescriptor.BOOL_TYPE) ) {
+ p("if ("+hasMethod+" && ( "+getterMethod+"!=obj."+getterMethod+" ))");
+ } else {
+ p("if ("+hasMethod+" && ( !"+getterMethod+".equals(obj."+getterMethod+") ))");
+ }
+ p(" return false;");
+ }
+ p("return true;");
+ unindent();
+ p("}");
+ p("");
+ p("public int hashCode() {");
+ indent();
+ int hc = className.hashCode();
+ p("int rc="+hc+";");
+ int counter=0;
+ for (FieldDescriptor field : m.getFields().values()) {
+ counter++;
+
+ String uname = uCamel(field.getName());
+ String getterMethod="get"+uname+"()";
+ String hasMethod = "has"+uname+"()";
+
+ if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+ getterMethod = "get"+uname+"List()";
+ }
+
+ p("if ("+hasMethod+") {");
+ indent();
+
+ if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+ p("rc ^= ( "+uname.hashCode()+"^"+getterMethod+".hashCode() );");
+ } else if( field.isInteger32Type() ) {
+ p("rc ^= ( "+uname.hashCode()+"^"+getterMethod+" );");
+ } else if( field.isInteger64Type() ) {
+ p("rc ^= ( "+uname.hashCode()+"^(new Long("+getterMethod+")).hashCode() );");
+ } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) {
+ p("rc ^= ( "+uname.hashCode()+"^(new Double("+getterMethod+")).hashCode() );");
+ } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) {
+ p("rc ^= ( "+uname.hashCode()+"^(new Double("+getterMethod+")).hashCode() );");
+ } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) {
+ p("rc ^= ( "+uname.hashCode()+"^ ("+getterMethod+"? "+counter+":-"+counter+") );");
+ } else {
+ p("rc ^= ( "+uname.hashCode()+"^"+getterMethod+".hashCode() );");
+ }
+ unindent();
+ p("}");
+ }
+ p("return rc;");
+ unindent();
+ p("}");
+ p("");
+ }
+
+ private void generateBufferEquals(MessageDescriptor m, String className) {
+ p("public boolean equals(Object obj) {");
+ indent();
+ p("if( obj==this )");
+ p(" return true;");
+ p("");
+ p("if( obj==null || obj.getClass()!="+className+".class )");
+ p(" return false;");
+ p("");
+ p("return equals(("+className+")obj);");
+ unindent();
+ p("}");
+ p("");
+
+ p("public boolean equals("+className+" obj) {");
+ indent();
+ p("return toUnframedBuffer().equals(obj.toUnframedBuffer());");
+ unindent();
+ p("}");
+ p("");
+ p("public int hashCode() {");
+ indent();
+ int hc = className.hashCode();
+ p("if( hashCode==0 ) {");
+ p("hashCode="+hc+" ^ toUnframedBuffer().hashCode();");
+ p("}");
+ p("return hashCode;");
+ unindent();
+ p("}");
+ p("");
+ }
+
+ /**
+ * @param m
+ */
+ private void generateMethodSerializedSize(MessageDescriptor m) {
+
+ p("public int serializedSizeFramed() {");
+ indent();
+ p("int t = serializedSizeUnframed();");
+ p("return org.apache.activemq.protobuf.CodedOutputStream.computeRawVarint32Size(t) + t;");
+ unindent();
+ p("}");
+ p();
+ p("public int serializedSizeUnframed() {");
+ indent();
+ p("if (buffer != null) {");
+ indent();
+ p("return buffer.length;");
+ unindent();
+ p("}");
+ p("if (size != -1)");
+ p(" return size;");
+ p();
+ p("size = 0;");
+ for (FieldDescriptor field : m.getFields().values()) {
+
+ String uname = uCamel(field.getName());
+ String getter="get"+uname+"()";
+ String type = javaType(field);
+
+ if( !field.isRequired() ) {
+ p("if (has"+uname+"()) {");
+ indent();
+ }
+
+ if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+ p("for ("+type+" i : get"+uname+"List()) {");
+ indent();
+ getter = "i";
+ }
+
+ if( field.getType()==FieldDescriptor.STRING_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeStringSize("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.BYTES_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeBytesSize("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeBoolSize("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeDoubleSize("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeFloatSize("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.INT32_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeInt32Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.INT64_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeInt64Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SINT32_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeSInt32Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SINT64_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeSInt64Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.UINT32_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeUInt32Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.UINT64_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeUInt64Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.FIXED32_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeFixed32Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.FIXED64_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeFixed64Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SFIXED32_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeSFixed32Size("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SFIXED64_TYPE ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeSFixed64Size("+field.getTag()+", "+getter+");");
+ } else if( field.getTypeDescriptor().isEnum() ) {
+ p("size += org.apache.activemq.protobuf.CodedOutputStream.computeEnumSize("+field.getTag()+", "+getter+".getNumber());");
+ } else if ( field.getGroup()!=null ) {
+ errors.add("This code generator does not support group fields.");
+// p("size += org.apache.activemq.protobuf.MessageBufferSupport.computeGroupSize("+field.getTag()+", ("+type+"Buffer)"+getter+");");
+ } else {
+ p("size += org.apache.activemq.protobuf.MessageBufferSupport.computeMessageSize("+field.getTag()+", "+getter+".freeze());");
+ }
+ if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+ unindent();
+ p("}");
+ }
+
+ if( !field.isRequired() ) {
+ unindent();
+ p("}");
+ }
+
+ }
+ // TODO: handle unknown fields
+ // size += getUnknownFields().getSerializedSize();");
+ p("return size;");
+ unindent();
+ p("}");
+ p();
+ }
+
+ /**
+ * @param m
+ */
+ private void generateMethodWrite(MessageDescriptor m) {
+
+ p("public org.apache.activemq.protobuf.Buffer toUnframedBuffer() {");
+ indent();
+ p("if( buffer !=null ) {");
+ indent();
+ p("return buffer;");
+ unindent();
+ p("}");
+ p("return org.apache.activemq.protobuf.MessageBufferSupport.toUnframedBuffer(this);");
+ unindent();
+ p("}");
+ p();
+ p("public org.apache.activemq.protobuf.Buffer toFramedBuffer() {");
+ indent();
+ p("return org.apache.activemq.protobuf.MessageBufferSupport.toFramedBuffer(this);");
+ unindent();
+ p("}");
+ p();
+ p("public byte[] toUnframedByteArray() {");
+ indent();
+ p("return toUnframedBuffer().toByteArray();");
+ unindent();
+ p("}");
+ p();
+ p("public byte[] toFramedByteArray() {");
+ indent();
+ p("return toFramedBuffer().toByteArray();");
+ unindent();
+ p("}");
+ p();
+ p("public void writeFramed(org.apache.activemq.protobuf.CodedOutputStream output) throws java.io.IOException {");
+ indent();
+ p("output.writeRawVarint32(serializedSizeUnframed());");
+ p("writeUnframed(output);");
+ unindent();
+ p("}");
+ p();
+ p("public void writeFramed(java.io.OutputStream output) throws java.io.IOException {");
+ indent();
+ p("org.apache.activemq.protobuf.CodedOutputStream codedOutput = new org.apache.activemq.protobuf.CodedOutputStream(output);");
+ p("writeFramed(codedOutput);");
+ p("codedOutput.flush();");
+ unindent();
+ p("}");
+ p();
+
+ p("public void writeUnframed(java.io.OutputStream output) throws java.io.IOException {");
+ indent();
+ p("org.apache.activemq.protobuf.CodedOutputStream codedOutput = new org.apache.activemq.protobuf.CodedOutputStream(output);");
+ p("writeUnframed(codedOutput);");
+ p("codedOutput.flush();");
+ unindent();
+ p("}");
+ p();
+
+ p("public void writeUnframed(org.apache.activemq.protobuf.CodedOutputStream output) throws java.io.IOException {");
+ indent();
+
+ p("if (buffer == null) {");
+ indent();
+ p("int size = serializedSizeUnframed();");
+ p("buffer = output.getNextBuffer(size);");
+ p("org.apache.activemq.protobuf.CodedOutputStream original=null;");
+ p("if( buffer == null ) {");
+ indent();
+ p("buffer = new org.apache.activemq.protobuf.Buffer(new byte[size]);");
+ p("original = output;");
+ p("output = new org.apache.activemq.protobuf.CodedOutputStream(buffer);");
+ unindent();
+ p("}");
+
+ for (FieldDescriptor field : m.getFields().values()) {
+ String uname = uCamel(field.getName());
+ String getter="bean.get"+uname+"()";
+ String type = javaType(field);
+
+ if( !field.isRequired() ) {
+ p("if (bean.has"+uname+"()) {");
+ indent();
+ }
+
+ if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+ p("for ("+type+" i : bean.get"+uname+"List()) {");
+ indent();
+ getter = "i";
+ }
+
+ if( field.getType()==FieldDescriptor.STRING_TYPE ) {
+ p("output.writeString("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.BYTES_TYPE ) {
+ p("output.writeBytes("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) {
+ p("output.writeBool("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) {
+ p("output.writeDouble("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) {
+ p("output.writeFloat("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.INT32_TYPE ) {
+ p("output.writeInt32("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.INT64_TYPE ) {
+ p("output.writeInt64("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SINT32_TYPE ) {
+ p("output.writeSInt32("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SINT64_TYPE ) {
+ p("output.writeSInt64("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.UINT32_TYPE ) {
+ p("output.writeUInt32("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.UINT64_TYPE ) {
+ p("output.writeUInt64("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.FIXED32_TYPE ) {
+ p("output.writeFixed32("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.FIXED64_TYPE ) {
+ p("output.writeFixed64("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SFIXED32_TYPE ) {
+ p("output.writeSFixed32("+field.getTag()+", "+getter+");");
+ } else if( field.getType()==FieldDescriptor.SFIXED64_TYPE ) {
+ p("output.writeSFixed64("+field.getTag()+", "+getter+");");
+ } else if( field.getTypeDescriptor().isEnum() ) {
+ p("output.writeEnum("+field.getTag()+", "+getter+".getNumber());");
+ } else if ( field.getGroup()!=null ) {
+ errors.add("This code generator does not support group fields.");
+// p("writeGroup(output, "+field.getTag()+", "+getter+");");
+ } else {
+ p("org.apache.activemq.protobuf.MessageBufferSupport.writeMessage(output, "+field.getTag()+", "+getter+".freeze());");
+ }
+
+ if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+ unindent();
+ p("}");
+ }
+
+ if( !field.isRequired() ) {
+ unindent();
+ p("}");
+ }
+ }
+
+ p("if( original !=null ) {");
+ indent();
+ p("output.checkNoSpaceLeft();");
+ p("output = original;");
+ p("output.writeRawBytes(buffer);");
+ unindent();
+ p("}");
+ unindent();
+ p("} else {");
+ indent();
+ p("output.writeRawBytes(buffer);");
+ unindent();
+ p("}");
+
+ unindent();
+ p("}");
+ p();
+ }
+
+ /**
+ * @param m
+ * @param className
+ */
+ private void generateMethodMergeFromStream(MessageDescriptor m, String className) {
+ p("public "+className+" mergeUnframed(java.io.InputStream input) throws java.io.IOException {");
+ indent();
+ p("return mergeUnframed(new org.apache.activemq.protobuf.CodedInputStream(input));");
+ unindent();
+ p("}");
+ p();
+ p("public "+className+" mergeUnframed(org.apache.activemq.protobuf.CodedInputStream input) throws java.io.IOException {");
+ indent();
+ {
+ p("copyCheck();");
+ p("while (true) {");
+ indent();
+ {
+ p("int tag = input.readTag();");
+ p("if ((tag & 0x07) == 4) {");
+ p(" return this;");
+ p("}");
+
+ p("switch (tag) {");
+ p("case 0:");
+ p(" return this;");
+ p("default: {");
+
+ p(" break;");
+ p("}");
+
+ for (FieldDescriptor field : m.getFields().values()) {
+ String uname = uCamel(field.getName());
+ String setter = "set" + uname;
+ boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE;
+ if (repeated) {
+ setter = "create" + uname + "List().add";
+ }
+ if (field.getType() == FieldDescriptor.STRING_TYPE) {
+ p("case "
+ + makeTag(field.getTag(),
+ WIRETYPE_LENGTH_DELIMITED) + ":");
+ indent();
+ p(setter + "(input.readString());");
+ } else if (field.getType() == FieldDescriptor.BYTES_TYPE) {
+ p("case "+ makeTag(field.getTag(), WIRETYPE_LENGTH_DELIMITED) + ":");
+ indent();
+ String override = getOption(field.getOptions(), "java_override_type", null);
+ if( "AsciiBuffer".equals(override) ) {
+ p(setter + "(new org.apache.activemq.protobuf.AsciiBuffer(input.readBytes()));");
+ } else if( "UTF8Buffer".equals(override) ) {
+ p(setter + "(new org.apache.activemq.protobuf.UTF8Buffer(input.readBytes()));");
+ } else {
+ p(setter + "(input.readBytes());");
+ }
+ } else if (field.getType() == FieldDescriptor.BOOL_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)+ ":");
+ indent();
+ p(setter + "(input.readBool());");
+ } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64)
+ + ":");
+ indent();
+ p(setter + "(input.readDouble());");
+ } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32)
+ + ":");
+ indent();
+ p(setter + "(input.readFloat());");
+ } else if (field.getType() == FieldDescriptor.INT32_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
+ + ":");
+ indent();
+ p(setter + "(input.readInt32());");
+ } else if (field.getType() == FieldDescriptor.INT64_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
+ + ":");
+ indent();
+ p(setter + "(input.readInt64());");
+ } else if (field.getType() == FieldDescriptor.SINT32_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
+ + ":");
+ indent();
+ p(setter + "(input.readSInt32());");
+ } else if (field.getType() == FieldDescriptor.SINT64_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
+ + ":");
+ indent();
+ p(setter + "(input.readSInt64());");
+ } else if (field.getType() == FieldDescriptor.UINT32_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
+ + ":");
+ indent();
+ p(setter + "(input.readUInt32());");
+ } else if (field.getType() == FieldDescriptor.UINT64_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
+ + ":");
+ indent();
+ p(setter + "(input.readUInt64());");
+ } else if (field.getType() == FieldDescriptor.FIXED32_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32)
+ + ":");
+ indent();
+ p(setter + "(input.readFixed32());");
+ } else if (field.getType() == FieldDescriptor.FIXED64_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64)
+ + ":");
+ indent();
+ p(setter + "(input.readFixed64());");
+ } else if (field.getType() == FieldDescriptor.SFIXED32_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32)
+ + ":");
+ indent();
+ p(setter + "(input.readSFixed32());");
+ } else if (field.getType() == FieldDescriptor.SFIXED64_TYPE) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64)
+ + ":");
+ indent();
+ p(setter + "(input.readSFixed64());");
+ } else if (field.getTypeDescriptor().isEnum()) {
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
+ + ":");
+ indent();
+ String type = javaType(field);
+ p("{");
+ indent();
+ p("int t = input.readEnum();");
+ p("" + type + " value = " + type + ".valueOf(t);");
+ p("if( value !=null ) {");
+ indent();
+ p(setter + "(value);");
+ unindent();
+ p("}");
+ // TODO: else store it as an known
+
+ unindent();
+ p("}");
+
+ } else if (field.getGroup() != null) {
+ errors.add("This code generator does not support group fields.");
+// p("case "+ makeTag(field.getTag(), WIRETYPE_START_GROUP)+ ":");
+// indent();
+// String type = javaType(field);
+// if (repeated) {
+// p(setter + "(readGroup(input, " + field.getTag()+ ", new " + type + "()));");
+// } else {
+// p("if (has" + uname + "()) {");
+// indent();
+// p("readGroup(input, " + field.getTag() + ", get"
+// + uname + "());");
+// unindent();
+// p("} else {");
+// indent();
+// p(setter + "(readGroup(input, " + field.getTag()
+// + ",new " + type + "()));");
+// unindent();
+// p("}");
+// }
+// p("");
+ } else {
+ p("case "+ makeTag(field.getTag(),WIRETYPE_LENGTH_DELIMITED) + ":");
+ indent();
+ String type = javaType(field);
+ if (repeated) {
+ p(setter + "("+javaRelatedType(type, "Buffer")+".parseFramed(input));");
+ } else {
+ p("if (has" + uname + "()) {");
+ indent();
+ p("set" + uname + "(get" + uname + "().copy().mergeFrom("+javaRelatedType(type, "Buffer")+".parseFramed(input)));");
+ unindent();
+ p("} else {");
+ indent();
+ p(setter + "("+javaRelatedType(type, "Buffer")+".parseFramed(input));");
+ unindent();
+ p("}");
+ }
+ }
+ p("break;");
+ unindent();
+ }
+ p("}");
+ }
+ unindent();
+ p("}");
+ }
+ unindent();
+ p("}");
+ }
+
+ /**
+ * @param m
+ * @param className
+ */
+ private void generateMethodMergeFromBean(MessageDescriptor m, String className) {
+ p("public "+className+"Bean mergeFrom("+className+" other) {");
+ indent();
+ p("copyCheck();");
+ for (FieldDescriptor field : m.getFields().values()) {
+ String uname = uCamel(field.getName());
+ p("if (other.has"+uname+"()) {");
+ indent();
+
+ if( field.isScalarType() || field.getTypeDescriptor().isEnum() ) {
+ if( field.isRepeated() ) {
+ p("get"+uname+"List().addAll(other.get"+uname+"List());");
+ } else {
+ p("set"+uname+"(other.get"+uname+"());");
+ }
+ } else {
+
+ String type = javaType(field);
+ // It's complex type...
+ if( field.isRepeated() ) {
+ p("for("+type+" element: other.get"+uname+"List() ) {");
+ indent();
+ p("get"+uname+"List().add(element.copy());");
+ unindent();
+ p("}");
+ } else {
+ p("if (has"+uname+"()) {");
+ indent();
+ p("set"+uname+"(get"+uname+"().copy().mergeFrom(other.get"+uname+"()));");
+ unindent();
+ p("} else {");
+ indent();
+ p("set"+uname+"(other.get"+uname+"().copy());");
+ unindent();
+ p("}");
+ }
+ }
+ unindent();
+ p("}");
+ }
+ p("return this;");
+ unindent();
+ p("}");
+ p();
+ }
+
+ /**
+ * @param m
+ */
+ private void generateMethodClear(MessageDescriptor m) {
+ p("public void clear() {");
+ indent();
+ for (FieldDescriptor field : m.getFields().values()) {
+ String uname = uCamel(field.getName());
+ p("clear" + uname + "();");
+ }
+ unindent();
+ p("}");
+ p();
+ }
+
+ private void generateReadWriteExternal(MessageDescriptor m) {
+
+ p("public void readExternal(java.io.DataInput in) throws java.io.IOException {");
+ indent();
+ p("assert frozen==null : org.apache.activemq.protobuf.MessageBufferSupport.FORZEN_ERROR_MESSAGE;");
+ p("bean = this;");
+ p("frozen = null;");
+
+ for (FieldDescriptor field : m.getFields().values()) {
+ String lname = lCamel(field.getName());
+ String type = javaType(field);
+ boolean repeated = field.getRule()==FieldDescriptor.REPEATED_RULE;
+
+ // Create the fields..
+ if( repeated ) {
+ p("{");
+ indent();
+ p("int size = in.readShort();");
+ p("if( size>=0 ) {");
+ indent();
+ p("f_"+lname+" = new java.util.ArrayList<" + javaCollectionType(field) + ">(size);");
+ p("for(int i=0; i=0 ) {");
+ indent();
+ p("byte b[] = new byte[size];");
+ p("in.readFully(b);");
+ p("f_"+lname+" = new "+type+"(b);");
+ p("b_"+lname+" = true;");
+ unindent();
+ p("} else {");
+ indent();
+ p("f_"+lname+" = null;");
+ p("b_"+lname+" = false;");
+ unindent();
+ p("}");
+ unindent();
+ p("}");
+ } else if (field.getTypeDescriptor().isEnum() ) {
+ p("if( in.readBoolean() ) {");
+ indent();
+ p("f_"+lname+" = " + type + ".valueOf(in.readShort());");
+ p("b_"+lname+" = true;");
+ unindent();
+ p("} else {");
+ indent();
+ p("f_"+lname+" = null;");
+ p("b_"+lname+" = false;");
+ unindent();
+ p("}");
+ } else {
+ p("if( in.readBoolean() ) {");
+ indent();
+ p(""+javaRelatedType(type, "Bean")+" o = new "+javaRelatedType(type, "Bean")+"();");
+ p("o.readExternal(in);");
+ p("f_"+lname+" = o;");
+ unindent();
+ p("} else {");
+ indent();
+ p("f_"+lname+" = null;");
+ unindent();
+ p("}");
+ }
+ }
+ }
+
+ unindent();
+ p("}");
+ p();
+ p("public void writeExternal(java.io.DataOutput out) throws java.io.IOException {");
+ indent();
+ for (FieldDescriptor field : m.getFields().values()) {
+ String lname = lCamel(field.getName());
+ boolean repeated = field.getRule()==FieldDescriptor.REPEATED_RULE;
+
+ // Create the fields..
+ if( repeated ) {
+ p("if( bean.f_"+lname+"!=null ) {");
+ indent();
+ p("out.writeShort(bean.f_"+lname+".size());");
+ p("for(" + javaCollectionType(field) + " o : bean.f_"+lname+") {");
+ indent();
+
+ if( field.isInteger32Type() ) {
+ p("out.writeInt(o);");
+ } else if( field.isInteger64Type() ) {
+ p("out.writeLong(o);");
+ } else if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) {
+ p("out.writeDouble(o);");
+ } else if( field.getType() == FieldDescriptor.FLOAT_TYPE ) {
+ p("out.writeFloat(o);");
+ } else if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
+ p("out.writeBoolean(o);");
+ } else if( field.getType() == FieldDescriptor.STRING_TYPE ) {
+ p("out.writeUTF(o);");
+ } else if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
+ p("out.writeInt(o.getLength());");
+ p("out.write(o.getData(), o.getOffset(), o.getLength());");
+ } else if (field.getTypeDescriptor().isEnum() ) {
+ p("out.writeShort(o.getNumber());");
+ } else {
+ p("o.copy().writeExternal(out);");
+ }
+ unindent();
+ p("}");
+ unindent();
+ p("} else {");
+ indent();
+ p("out.writeShort(-1);");
+ unindent();
+ p("}");
+
+ } else {
+ if( field.isInteger32Type() ) {
+ p("out.writeInt(bean.f_"+lname+");");
+ } else if( field.isInteger64Type() ) {
+ p("out.writeLong(bean.f_"+lname+");");
+ } else if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) {
+ p("out.writeDouble(bean.f_"+lname+");");
+ } else if( field.getType() == FieldDescriptor.FLOAT_TYPE ) {
+ p("out.writeFloat(bean.f_"+lname+");");
+ } else if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
+ p("out.writeBoolean(bean.f_"+lname+");");
+ } else if( field.getType() == FieldDescriptor.STRING_TYPE ) {
+ p("if( bean.f_"+lname+"!=null ) {");
+ indent();
+ p("out.writeBoolean(true);");
+ p("out.writeUTF(bean.f_"+lname+");");
+ unindent();
+ p("} else {");
+ indent();
+ p("out.writeBoolean(false);");
+ unindent();
+ p("}");
+ } else if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
+ p("if( bean.f_"+lname+"!=null ) {");
+ indent();
+ p("out.writeInt(bean.f_"+lname+".getLength());");
+ p("out.write(bean.f_"+lname+".getData(), bean.f_"+lname+".getOffset(), bean.f_"+lname+".getLength());");
+ unindent();
+ p("} else {");
+ indent();
+ p("out.writeInt(-1);");
+ unindent();
+ p("}");
+ } else if (field.getTypeDescriptor().isEnum() ) {
+ p("if( bean.f_"+lname+"!=null ) {");
+ indent();
+ p("out.writeBoolean(true);");
+ p("out.writeShort(bean.f_"+lname+".getNumber());");
+ unindent();
+ p("} else {");
+ indent();
+ p("out.writeBoolean(false);");
+ unindent();
+ p("}");
+ } else {
+ p("if( bean.f_"+lname+"!=null ) {");
+ indent();
+ p("out.writeBoolean(true);");
+ p("bean.f_"+lname+".copy().writeExternal(out);");
+ unindent();
+ p("} else {");
+ indent();
+ p("out.writeBoolean(false);");
+ unindent();
+ p("}");
+ }
+ }
+ }
+
+ unindent();
+ p("}");
+ p();
+
+ }
+
+
+// private void generateMethodAssertInitialized(MessageDescriptor m, String className) {
+//
+// p("public java.util.ArrayList missingFields() {");
+// indent();
+// p("java.util.ArrayList missingFields = super.missingFields();");
+//
+// for (FieldDescriptor field : m.getFields().values()) {
+// String uname = uCamel(field.getName());
+// if( field.isRequired() ) {
+// p("if( !has" + uname + "() ) {");
+// indent();
+// p("missingFields.add(\""+field.getName()+"\");");
+// unindent();
+// p("}");
+// }
+// }
+//
+// if( !deferredDecode ) {
+// for (FieldDescriptor field : m.getFields().values()) {
+// if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) {
+// String uname = uCamel(field.getName());
+// p("if( has" + uname + "() ) {");
+// indent();
+// if( !field.isRepeated() ) {
+// p("try {");
+// indent();
+// p("get" + uname + "().assertInitialized();");
+// unindent();
+// p("} catch (org.apache.activemq.protobuf.UninitializedMessageException e){");
+// indent();
+// p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+".\"));");
+// unindent();
+// p("}");
+// } else {
+// String type = javaCollectionType(field);
+// p("java.util.List<"+type+"> l = get" + uname + "List();");
+// p("for( int i=0; i < l.size(); i++ ) {");
+// indent();
+// p("try {");
+// indent();
+// p("l.get(i).assertInitialized();");
+// unindent();
+// p("} catch (org.apache.activemq.protobuf.UninitializedMessageException e){");
+// indent();
+// p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+"[\"+i+\"]\"));");
+// unindent();
+// p("}");
+// unindent();
+// p("}");
+// }
+// unindent();
+// p("}");
+// }
+// }
+// }
+// p("return missingFields;");
+// unindent();
+// p("}");
+// p();
+// }
+
+ private void generateMethodToString(MessageDescriptor m) {
+
+ p("public String toString() {");
+ indent();
+ p("return toString(new java.lang.StringBuilder(), \"\").toString();");
+ unindent();
+ p("}");
+ p();
+
+ p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, String prefix) {");
+ indent();
+ for (FieldDescriptor field : m.getFields().values()) {
+ String uname = uCamel(field.getName());
+ p("if( has" + uname + "() ) {");
+ indent();
+ if( field.isRepeated() ) {
+ String type = javaCollectionType(field);
+ p("java.util.List<"+type+"> l = get" + uname + "List();");
+ p("for( int i=0; i < l.size(); i++ ) {");
+ indent();
+ if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) {
+ p("sb.append(prefix+\""+field.getName()+"[\"+i+\"] {\\n\");");
+ p("l.get(i).toString(sb, prefix+\" \");");
+ p("sb.append(prefix+\"}\\n\");");
+ } else {
+ p("sb.append(prefix+\""+field.getName()+"[\"+i+\"]: \");");
+ p("sb.append(l.get(i));");
+ p("sb.append(\"\\n\");");
+ }
+ unindent();
+ p("}");
+ } else {
+ if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) {
+ p("sb.append(prefix+\""+field.getName()+" {\\n\");");
+ p("get" + uname + "().toString(sb, prefix+\" \");");
+ p("sb.append(prefix+\"}\\n\");");
+ } else {
+ p("sb.append(prefix+\""+field.getName()+": \");");
+ p("sb.append(get" + uname + "());");
+ p("sb.append(\"\\n\");");
+ }
+ }
+ unindent();
+ p("}");
+ }
+ p("return sb;");
+ unindent();
+ p("}");
+ p();
+
+ }
+
+ /**
+ * @param field
+ * @param className
+ */
+ private void generateBufferGetters(FieldDescriptor field) {
+ String uname = uCamel(field.getName());
+ String type = field.getRule()==FieldDescriptor.REPEATED_RULE ? javaCollectionType(field):javaType(field);
+ boolean repeated = field.getRule()==FieldDescriptor.REPEATED_RULE;
+
+ // Create the fields..
+ p("// " + field.getRule() + " " + field.getType() + " " + field.getName() + " = " + field.getTag() + ";");
+ if( repeated ) {
+ // Create the field accessors
+ p("public boolean has" + uname + "() {");
+ indent();
+ p("return bean().has" + uname + "();");
+ unindent();
+ p("}");
+ p();
+ p("public java.util.List<" + type + "> get" + uname + "List() {");
+ indent();
+ p("return bean().get" + uname + "List();");
+ unindent();
+ p("}");
+ p();
+ p("public int get" + uname + "Count() {");
+ indent();
+ p("return bean().get" + uname + "Count();");
+ unindent();
+ p("}");
+ p();
+ p("public " + type + " get" + uname + "(int index) {");
+ indent();
+ p("return bean().get" + uname + "(index);");
+ unindent();
+ p("}");
+ p();
+ } else {
+ // Create the field accessors
+ p("public boolean has" + uname + "() {");
+ indent();
+ p("return bean().has" + uname + "();");
+ unindent();
+ p("}");
+ p();
+ p("public " + type + " get" + uname + "() {");
+ indent();
+ p("return bean().get" + uname + "();");
+ unindent();
+ p("}");
+ p();
+ }
+ }
+
+ /**
+ * @param field
+ * @param className
+ */
+ private void generateFieldGetterSignatures(FieldDescriptor field) {
+ String uname = uCamel(field.getName());
+ String type = field.getRule()==FieldDescriptor.REPEATED_RULE ? javaCollectionType(field):javaType(field);
+ boolean repeated = field.getRule()==FieldDescriptor.REPEATED_RULE;
+
+ // Create the fields..
+ p("// " + field.getRule() + " " + field.getType() + " " + field.getName() + " = " + field.getTag() + ";");
+ if( repeated ) {
+ // Create the field accessors
+ p("public boolean has" + uname + "();");
+ p("public java.util.List<" + type + "> get" + uname + "List();");
+ p("public int get" + uname + "Count();");
+ p("public " + type + " get" + uname + "(int index);");
+ } else {
+ // Create the field accessors
+ p("public boolean has" + uname + "();");
+ p("public " + type + " get" + uname + "();");
+ }
+ }
+
+
+ /**
+ * @param field
+ * @param className
+ */
+ private void generateFieldAccessor(String beanClassName, FieldDescriptor field) {
+
+ String lname = lCamel(field.getName());
+ String uname = uCamel(field.getName());
+ String type = field.getRule()==FieldDescriptor.REPEATED_RULE ? javaCollectionType(field):javaType(field);
+ String typeDefault = javaTypeDefault(field);
+ boolean primitive = field.getTypeDescriptor()==null || field.getTypeDescriptor().isEnum();
+ boolean repeated = field.getRule()==FieldDescriptor.REPEATED_RULE;
+
+ // Create the fields..
+ p("// " + field.getRule() + " " + field.getType() + " " + field.getName() + " = " + field.getTag() + ";");
+
+ if( repeated ) {
+ p("private java.util.List<" + type + "> f_" + lname + ";");
+ p();
+
+ // Create the field accessors
+ p("public boolean has" + uname + "() {");
+ indent();
+ p("return bean.f_" + lname + "!=null && !bean.f_" + lname + ".isEmpty();");
+ unindent();
+ p("}");
+ p();
+
+ p("public java.util.List<" + type + "> get" + uname + "List() {");
+ indent();
+ p("return bean.f_" + lname + ";");
+ unindent();
+ p("}");
+ p();
+
+ p("public java.util.List<" + type + "> create" + uname + "List() {");
+ indent();
+ p("copyCheck();");
+ p("if( this.f_" + lname + " == null ) {");
+ indent();
+ p("this.f_" + lname + " = new java.util.ArrayList<" + type + ">();");
+ unindent();
+ p("}");
+ p("return bean.f_" + lname + ";");
+ unindent();
+ p("}");
+ p();
+
+ p("public "+beanClassName+" set" + uname + "List(java.util.List<" + type + "> " + lname + ") {");
+ indent();
+ p("copyCheck();");
+ p("this.f_" + lname + " = " + lname + ";");
+ p("return this;");
+ unindent();
+ p("}");
+ p();
+
+ p("public int get" + uname + "Count() {");
+ indent();
+ p("if( bean.f_" + lname + " == null ) {");
+ indent();
+ p("return 0;");
+ unindent();
+ p("}");
+ p("return bean.f_" + lname + ".size();");
+ unindent();
+ p("}");
+ p();
+
+ p("public " + type + " get" + uname + "(int index) {");
+ indent();
+ p("if( bean.f_" + lname + " == null ) {");
+ indent();
+ p("return null;");
+ unindent();
+ p("}");
+ p("return bean.f_" + lname + ".get(index);");
+ unindent();
+ p("}");
+ p();
+
+ p("public "+beanClassName+" set" + uname + "(int index, " + type + " value) {");
+ indent();
+ p("this.create" + uname + "List().set(index, value);");
+ p("return this;");
+ unindent();
+ p("}");
+ p();
+
+ p("public "+beanClassName+" add" + uname + "(" + type + " value) {");
+ indent();
+ p("this.create" + uname + "List().add(value);");
+ p("return this;");
+ unindent();
+ p("}");
+ p();
+
+ p("public "+beanClassName+" addAll" + uname + "(java.lang.Iterable extends " + type + "> collection) {");
+ indent();
+ p("org.apache.activemq.protobuf.MessageBufferSupport.addAll(collection, this.create" + uname + "List());");
+ p("return this;");
+ unindent();
+ p("}");
+ p();
+
+ p("public void clear" + uname + "() {");
+ indent();
+ p("copyCheck();");
+ p("this.f_" + lname + " = null;");
+ unindent();
+ p("}");
+ p();
+
+ } else {
+
+ p("private " + type + " f_" + lname + " = "+typeDefault+";");
+ if (primitive) {
+ p("private boolean b_" + lname + ";");
+ }
+ p();
+
+ // Create the field accessors
+ p("public boolean has" + uname + "() {");
+ indent();
+ if (primitive) {
+ p("return bean.b_" + lname + ";");
+ } else {
+ p("return bean.f_" + lname + "!=null;");
+ }
+ unindent();
+ p("}");
+ p();
+
+ p("public " + type + " get" + uname + "() {");
+ indent();
+ p("return bean.f_" + lname + ";");
+ unindent();
+ p("}");
+ p();
+
+ p("public "+beanClassName+" set" + uname + "(" + type + " " + lname + ") {");
+ indent();
+ p("copyCheck();");
+ if (primitive) {
+ if( auto_clear_optional_fields && field.isOptional() ) {
+ if( field.isStringType() && !"null".equals(typeDefault)) {
+ p("this.b_" + lname + " = ("+lname+" != "+typeDefault+");");
+ } else {
+ p("this.b_" + lname + " = ("+lname+" != "+typeDefault+");");
+ }
+ } else {
+ p("this.b_" + lname + " = true;");
+ }
+ }
+ p("this.f_" + lname + " = " + lname + ";");
+ p("return this;");
+ unindent();
+ p("}");
+ p();
+
+ p("public void clear" + uname + "() {");
+ indent();
+ p("copyCheck();");
+ if (primitive) {
+ p("this.b_" + lname + " = false;");
+ }
+ p("this.f_" + lname + " = " + typeDefault + ";");
+ unindent();
+ p("}");
+ p();
+ }
+
+ }
+
+ private String javaTypeDefault(FieldDescriptor field) {
+ OptionDescriptor defaultOption = field.getOptions().get("default");
+ if( defaultOption!=null ) {
+ if( field.isStringType() ) {
+ return asJavaString(defaultOption.getValue());
+ } else if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
+ return "new "+javaType(field)+"("+asJavaString(defaultOption.getValue())+")";
+ } else if( field.isInteger32Type() ) {
+ int v;
+ if( field.getType() == FieldDescriptor.UINT32_TYPE ) {
+ v = TextFormat.parseUInt32(defaultOption.getValue());
+ } else {
+ v = TextFormat.parseInt32(defaultOption.getValue());
+ }
+ return ""+v;
+ } else if( field.isInteger64Type() ) {
+ long v;
+ if( field.getType() == FieldDescriptor.UINT64_TYPE ) {
+ v = TextFormat.parseUInt64(defaultOption.getValue());
+ } else {
+ v = TextFormat.parseInt64(defaultOption.getValue());
+ }
+ return ""+v+"l";
+ } else if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) {
+ double v = Double.valueOf(defaultOption.getValue());
+ return ""+v+"d";
+ } else if( field.getType() == FieldDescriptor.FLOAT_TYPE ) {
+ float v = Float.valueOf(defaultOption.getValue());
+ return ""+v+"f";
+ } else if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
+ boolean v = Boolean.valueOf(defaultOption.getValue());
+ return ""+v;
+ } else if( field.getTypeDescriptor()!=null && field.getTypeDescriptor().isEnum() ) {
+ return javaType(field)+"."+defaultOption.getValue();
+ }
+ return defaultOption.getValue();
+ } else {
+ if( field.isNumberType() ) {
+ return "0";
+ }
+ if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
+ return "false";
+ }
+ return "null";
+ }
+ }
+
+ static final char HEX_TABLE[] = new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ private String asJavaString(String value) {
+ StringBuilder sb = new StringBuilder(value.length()+2);
+ sb.append("\"");
+ for (int i = 0; i < value.length(); i++) {
+
+ char b = value.charAt(i);
+ switch (b) {
+ // Java does not recognize \a or \v, apparently.
+ case '\b': sb.append("\\b" ); break;
+ case '\f': sb.append("\\f" ); break;
+ case '\n': sb.append("\\n" ); break;
+ case '\r': sb.append("\\r" ); break;
+ case '\t': sb.append("\\t" ); break;
+ case '\\': sb.append("\\\\"); break;
+ case '\'': sb.append("\\\'"); break;
+ case '"' : sb.append("\\\""); break;
+ default:
+ if (b >= 0x20 && b <'Z') {
+ sb.append((char) b);
+ } else {
+ sb.append("\\u");
+ sb.append(HEX_TABLE[(b >>> 12) & 0x0F] );
+ sb.append(HEX_TABLE[(b >>> 8) & 0x0F] );
+ sb.append(HEX_TABLE[(b >>> 4) & 0x0F] );
+ sb.append(HEX_TABLE[b & 0x0F] );
+ }
+ break;
+ }
+
+ }
+ sb.append("\"");
+ return sb.toString();
+ }
+
+ private void generateEnum(EnumDescriptor ed) {
+ String uname = uCamel(ed.getName());
+
+ String staticOption = "static ";
+ if( multipleFiles && ed.getParent()==null ) {
+ staticOption="";
+ }
+
+ // TODO Auto-generated method stub
+ p();
+ p("public "+staticOption+"enum " +uname + " {");
+ indent();
+
+
+ p();
+ int counter=0;
+ for (EnumFieldDescriptor field : ed.getFields().values()) {
+ boolean last = counter+1 == ed.getFields().size();
+ p(field.getName()+"(\""+field.getName()+"\", "+field.getValue()+")"+(last?";":","));
+ counter++;
+ }
+ p();
+ p("private final String name;");
+ p("private final int value;");
+ p();
+ p("private "+uname+"(String name, int value) {");
+ p(" this.name = name;");
+ p(" this.value = value;");
+ p("}");
+ p();
+ p("public final int getNumber() {");
+ p(" return value;");
+ p("}");
+ p();
+ p("public final String toString() {");
+ p(" return name;");
+ p("}");
+ p();
+ p("public static "+uname+" valueOf(int value) {");
+ p(" switch (value) {");
+
+ // It's possible to define multiple ENUM fields with the same value..
+ // we only want to put the first one into the switch statement.
+ HashSet values = new HashSet();
+ for (EnumFieldDescriptor field : ed.getFields().values()) {
+ if( !values.contains(field.getValue()) ) {
+ p(" case "+field.getValue()+":");
+ p(" return "+field.getName()+";");
+ values.add(field.getValue());
+ }
+
+ }
+ p(" default:");
+ p(" return null;");
+ p(" }");
+ p("}");
+ p();
+
+
+ String createMessage = getOption(ed.getOptions(), "java_create_message", null);
+ if( "true".equals(createMessage) ) {
+
+ p("public interface "+uname+"Creatable {");
+ indent();
+ p(""+uname+" to"+uname+"();");
+ unindent();
+ p("}");
+ p();
+
+ p("public "+uname+"Creatable createBean() {");
+ indent();
+ p("switch (this) {");
+ indent();
+ for (EnumFieldDescriptor field : ed.getFields().values()) {
+ p("case "+field.getName()+":");
+ String type = field.getAssociatedType().getName();
+ p(" return new "+javaRelatedType(type, "Bean")+"();");
+ }
+ p("default:");
+ p(" return null;");
+ unindent();
+ p("}");
+ unindent();
+ p("}");
+ p();
+
+ generateParseDelegate(ed, "parseUnframed", "org.apache.activemq.protobuf.Buffer", "org.apache.activemq.protobuf.InvalidProtocolBufferException");
+ generateParseDelegate(ed, "parseFramed", "org.apache.activemq.protobuf.Buffer", "org.apache.activemq.protobuf.InvalidProtocolBufferException");
+ generateParseDelegate(ed, "parseUnframed", "byte[]", "org.apache.activemq.protobuf.InvalidProtocolBufferException");
+ generateParseDelegate(ed, "parseFramed", "byte[]", "org.apache.activemq.protobuf.InvalidProtocolBufferException");
+ generateParseDelegate(ed, "parseFramed", "org.apache.activemq.protobuf.CodedInputStream", "org.apache.activemq.protobuf.InvalidProtocolBufferException, java.io.IOException");
+ generateParseDelegate(ed, "parseFramed", "java.io.InputStream", "org.apache.activemq.protobuf.InvalidProtocolBufferException, java.io.IOException");
+ }
+
+ unindent();
+ p("}");
+ p();
+ }
+
+ private void generateParseDelegate(EnumDescriptor descriptor, String methodName, String inputType, String exceptions) {
+ p("public org.apache.activemq.protobuf.MessageBuffer " + methodName + "(" + inputType + " data) throws " + exceptions + " {");
+ indent();
+ p("switch (this) {");
+ indent();
+ for (EnumFieldDescriptor field : descriptor.getFields().values()) {
+ p("case "+field.getName()+":");
+ String type = constantToUCamelCase(field.getName());
+ p(" return "+javaRelatedType(type, "Buffer")+"."+methodName+"(data);");
+ }
+ p("default:");
+ p(" return null;");
+ unindent();
+ p("}");
+ unindent();
+ p("}");
+ p();
+ }
+
+
+
+ private String javaCollectionType(FieldDescriptor field) {
+ if( field.isInteger32Type() ) {
+ return "java.lang.Integer";
+ }
+ if( field.isInteger64Type() ) {
+ return "java.lang.Long";
+ }
+ if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) {
+ return "java.lang.Double";
+ }
+ if( field.getType() == FieldDescriptor.FLOAT_TYPE ) {
+ return "java.lang.Float";
+ }
+ if( field.getType() == FieldDescriptor.STRING_TYPE ) {
+ // TODO: support handling string fields as buffers.
+// String override = getOption(field.getOptions(), "java_override_type", null);
+// if( "AsciiBuffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.AsciiBuffer";
+// } else if( "UTF8Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.UTF8Buffer";
+// } else if( "Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.Buffer";
+// } else {
+ return "java.lang.String";
+// }
+ }
+ if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
+ String override = getOption(field.getOptions(), "java_override_type", null);
+ if( "AsciiBuffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.AsciiBuffer";
+ } else if( "UTF8Buffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.UTF8Buffer";
+ } else {
+ return "org.apache.activemq.protobuf.Buffer";
+ }
+ }
+ if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
+ return "java.lang.Boolean";
+ }
+
+ TypeDescriptor descriptor = field.getTypeDescriptor();
+ return javaType(descriptor);
+ }
+
+ private String javaType(FieldDescriptor field) {
+ if( field.isInteger32Type() ) {
+ return "int";
+ }
+ if( field.isInteger64Type() ) {
+ return "long";
+ }
+ if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) {
+ return "double";
+ }
+ if( field.getType() == FieldDescriptor.FLOAT_TYPE ) {
+ return "float";
+ }
+ if( field.getType() == FieldDescriptor.STRING_TYPE ) {
+ // TODO: support handling string fields as buffers.
+// String override = getOption(field.getOptions(), "java_override_type", null);
+// if( "AsciiBuffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.AsciiBuffer";
+// } else if( "UTF8Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.UTF8Buffer";
+// } else if( "Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.Buffer";
+// } else {
+ return "java.lang.String";
+// }
+ }
+ if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
+ String override = getOption(field.getOptions(), "java_override_type", null);
+ if( "AsciiBuffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.AsciiBuffer";
+ } else if( "UTF8Buffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.UTF8Buffer";
+ } else {
+ return "org.apache.activemq.protobuf.Buffer";
+ }
+ }
+ if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
+ return "boolean";
+ }
+
+ TypeDescriptor descriptor = field.getTypeDescriptor();
+ return javaType(descriptor);
+ }
+
+ private String javaType(TypeDescriptor descriptor) {
+ ProtoDescriptor p = descriptor.getProtoDescriptor();
+ if( p != proto ) {
+ // Try to keep it short..
+ String othePackage = javaPackage(p);
+ if( equals(othePackage,javaPackage(proto) ) ) {
+ return javaClassName(p)+"."+descriptor.getQName();
+ }
+ // Use the fully qualified class name.
+ return othePackage+"."+javaClassName(p)+"."+descriptor.getQName();
+ }
+ return descriptor.getQName();
+ }
+
+ private String javaRelatedType(String type, String suffix) {
+ int ix = type.lastIndexOf(".");
+ if (ix == -1) {
+ // type = Foo, result = Foo.FooBean
+ return type+"."+type+suffix;
+ }
+ // type = Foo.Bar, result = Foo.Bar.BarBean
+ return type+"."+type.substring(ix+1)+suffix;
+ }
+
+ private boolean equals(String o1, String o2) {
+ if( o1==o2 )
+ return true;
+ if( o1==null || o2==null )
+ return false;
+ return o1.equals(o2);
+ }
+
+ private String javaClassName(ProtoDescriptor proto) {
+ return getOption(proto.getOptions(), "java_outer_classname", uCamel(removeFileExtension(proto.getName())));
+ }
+
+ private boolean isMultipleFilesEnabled(ProtoDescriptor proto) {
+ return "true".equals(getOption(proto.getOptions(), "java_multiple_files", "false"));
+ }
+
+
+ private String javaPackage(ProtoDescriptor proto) {
+ String name = proto.getPackageName();
+ if( name!=null ) {
+ name = name.replace('-', '.');
+ name = name.replace('/', '.');
+ }
+ return getOption(proto.getOptions(), "java_package", name);
+ }
+
+
+ // ----------------------------------------------------------------
+ // Internal Helper methods
+ // ----------------------------------------------------------------
+
+ private void indent() {
+ indent++;
+ }
+
+ private void unindent() {
+ indent--;
+ }
+
+ private void p(String line) {
+ // Indent...
+ for (int i = 0; i < indent; i++) {
+ w.print(" ");
+ }
+ // Then print.
+ w.println(line);
+ }
+
+ private void p() {
+ w.println();
+ }
+
+ private String getOption(Map options, String optionName, String defaultValue) {
+ OptionDescriptor optionDescriptor = options.get(optionName);
+ if (optionDescriptor == null) {
+ return defaultValue;
+ }
+ return optionDescriptor.getValue();
+ }
+
+ static private String removeFileExtension(String name) {
+ return name.replaceAll("\\..*", "");
+ }
+
+ static private String uCamel(String name) {
+ boolean upNext=true;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if( Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) {
+ if( upNext ) {
+ c = Character.toUpperCase(c);
+ upNext=false;
+ }
+ sb.append(c);
+ } else {
+ upNext=true;
+ }
+ }
+ return sb.toString();
+ }
+
+ static private String lCamel(String name) {
+ if( name == null || name.length()<1 )
+ return name;
+ String uCamel = uCamel(name);
+ return uCamel.substring(0,1).toLowerCase()+uCamel.substring(1);
+ }
+
+
+ private String constantToUCamelCase(String name) {
+ boolean upNext=true;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if( Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) {
+ if( upNext ) {
+ c = Character.toUpperCase(c);
+ upNext=false;
+ } else {
+ c = Character.toLowerCase(c);
+ }
+ sb.append(c);
+ } else {
+ upNext=true;
+ }
+ }
+ return sb.toString();
+ }
+
+
+ private String constantCase(String name) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if( i!=0 && Character.isUpperCase(c) ) {
+ sb.append("_");
+ }
+ sb.append(Character.toUpperCase(c));
+ }
+ return sb.toString();
+ }
+
+ public File getOut() {
+ return out;
+ }
+
+ public void setOut(File outputDirectory) {
+ this.out = outputDirectory;
+ }
+
+ public File[] getPath() {
+ return path;
+ }
+
+ public void setPath(File[] path) {
+ this.path = path;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/CommandLineSupport.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/CommandLineSupport.java
new file mode 100644
index 0000000000..1d217ff3ae
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/CommandLineSupport.java
@@ -0,0 +1,115 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+import java.util.ArrayList;
+
+/**
+ * Support utility that can be used to set the properties on any object
+ * using command line arguments.
+ *
+ * @author Hiram Chirino
+ */
+public class CommandLineSupport {
+
+ /**
+ * Sets the properties of an object given the command line args.
+ *
+ * if args contains: --ack-mode=AUTO --url=tcp://localhost:61616 --persistent
+ *
+ * then it will try to call the following setters on the target object.
+ *
+ * target.setAckMode("AUTO");
+ * target.setURL(new URI("tcp://localhost:61616") );
+ * target.setPersistent(true);
+ *
+ * Notice the the proper conversion for the argument is determined by examining the
+ * setter argument type.
+ *
+ * @param target the object that will have it's properties set
+ * @param args the command line options
+ * @return any arguments that are not valid options for the target
+ */
+ static public String[] setOptions(Object target, String []args) {
+ ArrayList rc = new ArrayList();
+
+ for (int i = 0; i < args.length; i++) {
+ if( args[i] == null )
+ continue;
+
+ if( args[i].startsWith("--") ) {
+
+ // --options without a specified value are considered boolean flags that are enabled.
+ String value="true";
+ String name = args[i].substring(2);
+
+ // if --option=value case
+ int p = name.indexOf("=");
+ if( p > 0 ) {
+ value = name.substring(p+1);
+ name = name.substring(0,p);
+ }
+
+ // name not set, then it's an unrecognized option
+ if( name.length()==0 ) {
+ rc.add(args[i]);
+ continue;
+ }
+
+ String propName = convertOptionToPropertyName(name);
+ if( !IntrospectionSupport.setProperty(target, propName, value) ) {
+ rc.add(args[i]);
+ continue;
+ }
+ } else {
+ rc.add(args[i]);
+ }
+
+ }
+
+ String r[] = new String[rc.size()];
+ rc.toArray(r);
+ return r;
+ }
+
+ /**
+ * converts strings like: test-enabled to testEnabled
+ * @param name
+ * @return
+ */
+ private static String convertOptionToPropertyName(String name) {
+ String rc="";
+
+ // Look for '-' and strip and then convert the subsequent char to uppercase
+ int p = name.indexOf("-");
+ while( p > 0 ) {
+ // strip
+ rc += name.substring(0, p);
+ name = name.substring(p+1);
+
+ // can I convert the next char to upper?
+ if( name.length() >0 ) {
+ rc += name.substring(0,1).toUpperCase();
+ name = name.substring(1);
+ }
+
+ p = name.indexOf("-");
+ }
+ return rc+name;
+ }
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/CompilerException.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/CompilerException.java
new file mode 100644
index 0000000000..f1c24f39f2
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/CompilerException.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+import java.util.List;
+
+public class CompilerException extends Exception {
+ private final List errors;
+
+ public CompilerException(List errors) {
+ this.errors = errors;
+ }
+
+ public List getErrors() {
+ return errors;
+ }
+}
\ No newline at end of file
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/EnumDescriptor.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/EnumDescriptor.java
new file mode 100644
index 0000000000..3e6e195aab
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/EnumDescriptor.java
@@ -0,0 +1,136 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class EnumDescriptor implements TypeDescriptor {
+
+ private String name;
+ private Map fields= new LinkedHashMap();
+ private final ProtoDescriptor protoDescriptor;
+ private final MessageDescriptor parent;
+ private Map options = new LinkedHashMap();
+
+ public EnumDescriptor(ProtoDescriptor protoDescriptor, MessageDescriptor parent) {
+ this.protoDescriptor = protoDescriptor;
+ this.parent = parent;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Map getFields() {
+ return fields;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setFields(Map fields) {
+ this.fields = fields;
+ }
+ public ProtoDescriptor getProtoDescriptor() {
+ return protoDescriptor;
+ }
+
+ private String getOption(Map options, String optionName, String defaultValue) {
+ OptionDescriptor optionDescriptor = options.get(optionName);
+ if (optionDescriptor == null) {
+ return defaultValue;
+ }
+ return optionDescriptor.getValue();
+ }
+
+ private String constantToUCamelCase(String name) {
+ boolean upNext=true;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if( Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) {
+ if( upNext ) {
+ c = Character.toUpperCase(c);
+ upNext=false;
+ } else {
+ c = Character.toLowerCase(c);
+ }
+ sb.append(c);
+ } else {
+ upNext=true;
+ }
+ }
+ return sb.toString();
+ }
+
+ public void validate(List errors) {
+ String createMessage = getOption(getOptions(), "java_create_message", null);
+ if( "true".equals(createMessage) ) {
+ for (EnumFieldDescriptor field : getFields().values()) {
+ String type = constantToUCamelCase(field.getName());
+
+ TypeDescriptor typeDescriptor=null;
+ // Find the type def for that guy..
+ if( parent!=null ) {
+ typeDescriptor = parent.getType(type);
+ }
+ if( typeDescriptor == null ) {
+ typeDescriptor = protoDescriptor.getType(type);
+ }
+ if( typeDescriptor == null ) {
+ errors.add("ENUM constant '"+field.getName()+"' did not find expected associated message: "+type);
+ } else {
+ field.associate(typeDescriptor);
+ typeDescriptor.associate(field);
+ }
+ }
+ }
+ }
+
+ public MessageDescriptor getParent() {
+ return parent;
+ }
+
+ public String getQName() {
+ if( parent==null ) {
+ return name;
+ } else {
+ return parent.getQName()+"."+name;
+ }
+ }
+
+ public boolean isEnum() {
+ return true;
+ }
+
+ public Map getOptions() {
+ return options;
+ }
+
+ public void setOptions(Map options) {
+ this.options = options;
+ }
+
+ public void associate(EnumFieldDescriptor desc) {
+ throw new RuntimeException("not supported.");
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/EnumFieldDescriptor.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/EnumFieldDescriptor.java
new file mode 100644
index 0000000000..694492ab2f
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/EnumFieldDescriptor.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+public class EnumFieldDescriptor {
+
+ private String name;
+ private int value;
+ private final EnumDescriptor parent;
+ private TypeDescriptor associatedType;
+
+ public EnumFieldDescriptor(EnumDescriptor parent) {
+ this.parent = parent;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public EnumDescriptor getParent() {
+ return parent;
+ }
+
+ public TypeDescriptor getAssociatedType() {
+ return associatedType;
+ }
+
+ public void associate(TypeDescriptor associatedType) {
+ this.associatedType = associatedType;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/ExtensionsDescriptor.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/ExtensionsDescriptor.java
new file mode 100644
index 0000000000..7c5f21a676
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/ExtensionsDescriptor.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+public class ExtensionsDescriptor {
+
+ private int first;
+ private int last;
+ private final MessageDescriptor parent;
+
+ public ExtensionsDescriptor(MessageDescriptor parent) {
+ this.parent = parent;
+ }
+
+ public void setFirst(int first) {
+ this.first = first;
+ }
+
+ public void setLast(int last) {
+ this.last = last;
+ }
+
+ public int getFirst() {
+ return first;
+ }
+
+ public int getLast() {
+ return last;
+ }
+
+ public MessageDescriptor getParent() {
+ return parent;
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/FieldDescriptor.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/FieldDescriptor.java
new file mode 100644
index 0000000000..3471c413b9
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/FieldDescriptor.java
@@ -0,0 +1,207 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class FieldDescriptor {
+
+ public static final String STRING_TYPE = "string".intern();
+ public static final String BOOL_TYPE = "bool".intern();
+ public static final String BYTES_TYPE = "bytes".intern();
+ public static final String DOUBLE_TYPE = "double".intern();
+ public static final String FLOAT_TYPE = "float".intern();
+
+ public static final String INT32_TYPE = "int32".intern();
+ public static final String INT64_TYPE = "int64".intern();
+ public static final String UINT32_TYPE = "uint32".intern();
+ public static final String UINT64_TYPE = "uint64".intern();
+ public static final String SINT32_TYPE = "sint32".intern();
+ public static final String SINT64_TYPE = "sint64".intern();
+ public static final String FIXED32_TYPE = "fixed32".intern();
+ public static final String FIXED64_TYPE = "fixed64".intern();
+ public static final String SFIXED32_TYPE = "sfixed32".intern();
+ public static final String SFIXED64_TYPE = "sfixed64".intern();
+
+ public static final String REQUIRED_RULE = "required".intern();
+ public static final String OPTIONAL_RULE= "optional".intern();
+ public static final String REPEATED_RULE = "repeated".intern();
+
+ public static final Set INT32_TYPES = new HashSet();
+ public static final Set INT64_TYPES = new HashSet();
+ public static final Set INTEGER_TYPES = new HashSet();
+ public static final Set NUMBER_TYPES = new HashSet();
+ public static final Set SCALAR_TYPES = new HashSet();
+
+ public static final Set SIGNED_TYPES = new HashSet();
+ public static final Set UNSIGNED_TYPES = new HashSet();
+
+ static {
+ INT32_TYPES.add(INT32_TYPE);
+ INT32_TYPES.add(UINT32_TYPE);
+ INT32_TYPES.add(SINT32_TYPE);
+ INT32_TYPES.add(FIXED32_TYPE);
+ INT32_TYPES.add(SFIXED32_TYPE);
+
+ INT64_TYPES.add(INT64_TYPE);
+ INT64_TYPES.add(UINT64_TYPE);
+ INT64_TYPES.add(SINT64_TYPE);
+ INT64_TYPES.add(FIXED64_TYPE);
+ INT64_TYPES.add(SFIXED64_TYPE);
+
+ INTEGER_TYPES.addAll(INT32_TYPES);
+ INTEGER_TYPES.addAll(INT64_TYPES);
+
+ NUMBER_TYPES.addAll(INTEGER_TYPES);
+ NUMBER_TYPES.add(DOUBLE_TYPE);
+ NUMBER_TYPES.add(FLOAT_TYPE);
+
+ SCALAR_TYPES.addAll(NUMBER_TYPES);
+ SCALAR_TYPES.add(STRING_TYPE);
+ SCALAR_TYPES.add(BOOL_TYPE);
+ SCALAR_TYPES.add(BYTES_TYPE);
+ }
+
+
+ private String name;
+ private String type;
+ private String rule;
+ private int tag;
+ private Map options;
+ private TypeDescriptor typeDescriptor;
+ private final MessageDescriptor parent;
+ private MessageDescriptor group;
+
+ public FieldDescriptor(MessageDescriptor parent) {
+ this.parent = parent;
+ }
+
+ public void validate(List errors) {
+ if( group!=null ) {
+ typeDescriptor=group;
+ }
+ if( !SCALAR_TYPES.contains(type) ) {
+ // Find the type def for that guy..
+ if( typeDescriptor==null ) {
+ typeDescriptor = parent.getType(type);
+ }
+ if( typeDescriptor == null ) {
+ typeDescriptor = parent.getProtoDescriptor().getType(type);
+ }
+ if( typeDescriptor == null ) {
+ errors.add("Field type not found: "+type);
+ }
+ }
+ }
+
+ public boolean isGroup() {
+ return group!=null;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRule() {
+ return rule;
+ }
+ public void setRule(String rule) {
+ this.rule = rule.intern();
+ }
+
+ public boolean isOptional() {
+ return this.rule == OPTIONAL_RULE;
+ }
+ public boolean isRequired() {
+ return this.rule == REQUIRED_RULE;
+ }
+ public boolean isRepeated() {
+ return this.rule == REPEATED_RULE;
+ }
+
+ public int getTag() {
+ return tag;
+ }
+ public void setTag(int tag) {
+ this.tag = tag;
+ }
+
+ public Map getOptions() {
+ return options;
+ }
+ public void setOptions(Map options) {
+ this.options = options;
+ }
+
+ public String getType() {
+ return type;
+ }
+ public void setType(String type) {
+ this.type = type.intern();
+ }
+
+ public boolean isMessageType() {
+ return !SCALAR_TYPES.contains(type);
+ }
+
+ public boolean isScalarType() {
+ return SCALAR_TYPES.contains(type);
+ }
+
+ public boolean isNumberType() {
+ return NUMBER_TYPES.contains(type);
+ }
+
+ public boolean isIntegerType() {
+ return INTEGER_TYPES.contains(type);
+ }
+
+ public boolean isInteger32Type() {
+ return INT32_TYPES.contains(type);
+ }
+
+ public boolean isInteger64Type() {
+ return INT64_TYPES.contains(type);
+ }
+
+ public boolean isStringType() {
+ return type==STRING_TYPE;
+ }
+
+ public TypeDescriptor getTypeDescriptor() {
+ return typeDescriptor;
+ }
+
+ public void setTypeDescriptor(TypeDescriptor typeDescriptor) {
+ this.typeDescriptor = typeDescriptor;
+ }
+
+ public MessageDescriptor getGroup() {
+ return group;
+ }
+ public void setGroup(MessageDescriptor group) {
+ this.group = group;
+ }
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/IntrospectionSupport.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/IntrospectionSupport.java
new file mode 100755
index 0000000000..68382d063c
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/IntrospectionSupport.java
@@ -0,0 +1,324 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.protobuf.compiler;
+
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Map.Entry;
+
+/**
+ * Support class used to do introspection/reflection based setting and getting of properties on a Java Bean.
+ *
+ * @author Hiram Chirino
+ */
+public final class IntrospectionSupport {
+
+ private IntrospectionSupport() {
+ }
+
+ public static boolean getProperties(Object target, Map props, String optionPrefix) {
+
+ boolean rc = false;
+ if (target == null) {
+ throw new IllegalArgumentException("target was null.");
+ }
+ if (props == null) {
+ throw new IllegalArgumentException("props was null.");
+ }
+
+ if (optionPrefix == null) {
+ optionPrefix = "";
+ }
+
+ Class clazz = target.getClass();
+ Method[] methods = clazz.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ String name = method.getName();
+ Class type = method.getReturnType();
+ Class params[] = method.getParameterTypes();
+ if (name.startsWith("get") && params.length == 0 && type != null && isSettableType(type)) {
+
+ try {
+
+ Object value = method.invoke(target, new Object[] {});
+ if (value == null) {
+ continue;
+ }
+
+ String strValue = convertToString(value, type);
+ if (strValue == null) {
+ continue;
+ }
+
+ name = name.substring(3, 4).toLowerCase() + name.substring(4);
+ props.put(optionPrefix + name, strValue);
+ rc = true;
+
+ } catch (Throwable ignore) {
+ }
+
+ }
+ }
+
+ return rc;
+ }
+
+ public static boolean setProperties(Object target, Map props, String optionPrefix) {
+ boolean rc = false;
+ if (target == null) {
+ throw new IllegalArgumentException("target was null.");
+ }
+ if (props == null) {
+ throw new IllegalArgumentException("props was null.");
+ }
+
+ for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
+ String name = iter.next();
+ if (name.startsWith(optionPrefix)) {
+ Object value = props.get(name);
+ name = name.substring(optionPrefix.length());
+ if (setProperty(target, name, value)) {
+ iter.remove();
+ rc = true;
+ }
+ }
+ }
+ return rc;
+ }
+
+ public static Map extractProperties(Map props, String optionPrefix) {
+ if (props == null) {
+ throw new IllegalArgumentException("props was null.");
+ }
+
+ HashMap rc = new HashMap(props.size());
+
+ for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
+ String name = (String)iter.next();
+ if (name.startsWith(optionPrefix)) {
+ Object value = props.get(name);
+ name = name.substring(optionPrefix.length());
+ rc.put(name, value);
+ iter.remove();
+ }
+ }
+
+ return rc;
+ }
+
+ public static boolean setProperties(Object target, Map props) {
+ boolean rc = false;
+
+ if (target == null) {
+ throw new IllegalArgumentException("target was null.");
+ }
+ if (props == null) {
+ throw new IllegalArgumentException("props was null.");
+ }
+
+ for (Iterator iter = props.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry entry = (Entry)iter.next();
+ if (setProperty(target, (String)entry.getKey(), entry.getValue())) {
+ iter.remove();
+ rc = true;
+ }
+ }
+
+ return rc;
+ }
+
+ public static boolean setProperty(Object target, String name, Object value) {
+ try {
+ Class clazz = target.getClass();
+ Method setter = findSetterMethod(clazz, name);
+ if (setter == null) {
+ return false;
+ }
+
+ // If the type is null or it matches the needed type, just use the
+ // value directly
+ if (value == null || value.getClass() == setter.getParameterTypes()[0]) {
+ setter.invoke(target, new Object[] {value});
+ } else {
+ // We need to convert it
+ setter.invoke(target, new Object[] {convert(value, setter.getParameterTypes()[0])});
+ }
+ return true;
+ } catch (Throwable ignore) {
+ return false;
+ }
+ }
+
+ private static Object convert(Object value, Class type) throws URISyntaxException {
+ PropertyEditor editor = PropertyEditorManager.findEditor(type);
+ if (editor != null) {
+ editor.setAsText(value.toString());
+ return editor.getValue();
+ }
+ if (type == URI.class) {
+ return new URI(value.toString());
+ }
+ if (type == File.class) {
+ return new File(value.toString());
+ }
+ if (type == File[].class) {
+ ArrayList files = new ArrayList();
+ StringTokenizer st = new StringTokenizer(value.toString(), ":");
+ while(st.hasMoreTokens()) {
+ String t = st.nextToken();
+ if( t!=null && t.trim().length()>0 ) {
+ files.add(new File(t.trim()));
+ }
+ }
+ File rc[] = new File[files.size()];
+ files.toArray(rc);
+ return rc;
+ }
+ return null;
+ }
+
+ private static String convertToString(Object value, Class type) throws URISyntaxException {
+ PropertyEditor editor = PropertyEditorManager.findEditor(type);
+ if (editor != null) {
+ editor.setValue(value);
+ return editor.getAsText();
+ }
+ if (type == URI.class) {
+ return ((URI)value).toString();
+ }
+ return null;
+ }
+
+ private static Method findSetterMethod(Class clazz, String name) {
+ // Build the method name.
+ name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
+ Method[] methods = clazz.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ Class params[] = method.getParameterTypes();
+ if (method.getName().equals(name) && params.length == 1 && isSettableType(params[0])) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ private static boolean isSettableType(Class clazz) {
+ if (PropertyEditorManager.findEditor(clazz) != null) {
+ return true;
+ }
+ if (clazz == URI.class) {
+ return true;
+ }
+ if (clazz == File.class) {
+ return true;
+ }
+ if (clazz == File[].class) {
+ return true;
+ }
+ if (clazz == Boolean.class) {
+ return true;
+ }
+ return false;
+ }
+
+ public static String toString(Object target) {
+ return toString(target, Object.class);
+ }
+
+ public static String toString(Object target, Class stopClass) {
+ LinkedHashMap map = new LinkedHashMap();
+ addFields(target, target.getClass(), stopClass, map);
+ StringBuffer buffer = new StringBuffer(simpleName(target.getClass()));
+ buffer.append(" {");
+ Set entrySet = map.entrySet();
+ boolean first = true;
+ for (Iterator iter = entrySet.iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry)iter.next();
+ if (first) {
+ first = false;
+ } else {
+ buffer.append(", ");
+ }
+ buffer.append(entry.getKey());
+ buffer.append(" = ");
+ appendToString(buffer, entry.getValue());
+ }
+ buffer.append("}");
+ return buffer.toString();
+ }
+
+ protected static void appendToString(StringBuffer buffer, Object value) {
+ buffer.append(value);
+ }
+
+ public static String simpleName(Class clazz) {
+ String name = clazz.getName();
+ int p = name.lastIndexOf(".");
+ if (p >= 0) {
+ name = name.substring(p + 1);
+ }
+ return name;
+ }
+
+ private static void addFields(Object target, Class startClass, Class