summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/lib/java
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/jaegertracing/thrift/lib/java
parentInitial commit. (diff)
downloadceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz
ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/thrift/lib/java')
-rw-r--r--src/jaegertracing/thrift/lib/java/CMakeLists.txt94
-rw-r--r--src/jaegertracing/thrift/lib/java/Makefile.am72
-rw-r--r--src/jaegertracing/thrift/lib/java/README.md188
-rw-r--r--src/jaegertracing/thrift/lib/java/android/build.gradle50
-rw-r--r--src/jaegertracing/thrift/lib/java/android/settings.gradle1
-rw-r--r--src/jaegertracing/thrift/lib/java/android/src/main/AndroidManifest.xml4
-rw-r--r--src/jaegertracing/thrift/lib/java/build.gradle63
-rw-r--r--src/jaegertracing/thrift/lib/java/code_quality_tools/findbugs-filter.xml51
-rw-r--r--src/jaegertracing/thrift/lib/java/coding_standards.md1
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle.properties34
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/additionalArtifacts.gradle40
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/cloverCoverage.gradle48
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/codeQualityChecks.gradle39
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/environment.gradle75
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/functionalTests.gradle155
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/generateTestThrift.gradle120
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/publishing.gradle119
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/sourceConfiguration.gradle84
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/unitTests.gradle82
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.jarbin0 -> 55616 bytes
-rw-r--r--src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xsrc/jaegertracing/thrift/lib/java/gradlew188
-rw-r--r--src/jaegertracing/thrift/lib/java/gradlew.bat100
-rw-r--r--src/jaegertracing/thrift/lib/java/settings.gradle20
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/AsyncProcessFunction.java55
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/EncodingUtils.java148
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/Option.java125
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/ProcessFunction.java88
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TApplicationException.java150
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TAsyncProcessor.java33
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBase.java67
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java114
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseHelper.java297
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseProcessor.java41
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java61
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TDeserializer.java339
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnum.java24
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnumHelper.java56
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TException.java45
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldIdEnum.java34
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldRequirementType.java30
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java158
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java399
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchStats.java80
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessor.java30
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessorFactory.java43
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializable.java44
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializer.java110
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClient.java91
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClientFactory.java45
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TUnion.java279
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/annotation/Nullable.java33
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java51
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClient.java102
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientFactory.java25
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java201
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java284
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/EnumMetaData.java31
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java70
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldValueMetaData.java72
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/ListMetaData.java29
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/MapMetaData.java31
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/SetMetaData.java29
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/StructMetaData.java31
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/ShortStack.java77
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBase64Utils.java127
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java457
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java904
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TField.java65
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java973
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TList.java38
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMap.java40
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessage.java76
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessageType.java31
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java93
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocol.java162
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolDecorator.java213
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolException.java82
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolFactory.java31
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java221
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSet.java42
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java483
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TStruct.java36
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TTupleProtocol.java98
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TType.java40
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/IScheme.java29
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/SchemeFactory.java25
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/StandardScheme.java25
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/TupleScheme.java25
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java618
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/Invocation.java20
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/ServerContext.java26
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java171
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/THsHaServer.java204
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TNonblockingServer.java247
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServer.java177
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServerEventHandler.java59
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServlet.java119
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TSimpleServer.java115
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java359
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java744
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java50
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java84
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java88
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TByteBuffer.java87
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java200
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileProcessor.java118
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileTransport.java624
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFramedTransport.java190
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/THttpClient.java362
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TIOStreamTransport.java162
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java104
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryInputTransport.java96
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java163
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerTransport.java31
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java210
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingTransport.java47
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java447
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java108
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java230
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslTransport.java575
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSeekableFile.java33
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerSocket.java158
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerTransport.java80
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java216
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSocket.java248
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TStandardFile.java60
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransport.java163
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportException.java81
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportFactory.java41
-rw-r--r--src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TZlibTransport.java148
-rw-r--r--src/jaegertracing/thrift/lib/java/test/.keystorebin0 -> 2429 bytes
-rw-r--r--src/jaegertracing/thrift/lib/java/test/.truststorebin0 -> 1149 bytes
-rw-r--r--src/jaegertracing/thrift/lib/java/test/log4j.properties6
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/Fixtures.java340
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestDeepCopy.java34
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestEnumContainers.java81
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestFullCamel.java59
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java85
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionType.java66
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionals.java88
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestRenderedDoubleConstants.java179
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestReuse.java57
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestStruct.java396
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTBaseHelper.java209
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTDeserializer.java126
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTEnumHelper.java41
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTUnion.java268
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestUnsafeBinaries.java146
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClient.java28
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java378
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/BenchmarkProtocols.java88
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java427
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestShortStack.java42
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTCompactProtocol.java56
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTField.java60
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java48
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java83
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java94
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTTupleProtocol.java27
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/scheme/TestStandardScheme.java40
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/ServerTestBase.java715
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestAsyncServer.java28
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestHsHaServer.java30
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java123
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestThreadedSelectorServer.java30
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/EqualityTest.java663
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/JavaBeansTest.java112
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/ReadStruct.java62
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/SerializationBenchmark.java80
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestClient.java811
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java76
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestServer.java310
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/WriteStruct.java48
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java61
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java37
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java50
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java69
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java36
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java33
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java214
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTMemoryInputTransport.java85
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java92
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java35
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java34
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryStreamedStore.java62
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java471
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java74
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTZlibTransport.java140
-rw-r--r--src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/WriteCountingTransport.java54
190 files changed, 26251 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/java/CMakeLists.txt b/src/jaegertracing/thrift/lib/java/CMakeLists.txt
new file mode 100644
index 000000000..a67845aba
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/CMakeLists.txt
@@ -0,0 +1,94 @@
+#
+# 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.
+#
+
+if(ANDROID)
+
+ set(THRIFT_AAR outputs/aar/thrift-debug.aar outputs/aar/thrift-release.aar)
+ add_custom_command(
+ OUTPUT ${THRIFT_AAR}
+ COMMAND ${GRADLE_EXECUTABLE}
+ -p "${CMAKE_CURRENT_SOURCE_DIR}/android"
+ "-PbuildDir=${CMAKE_CURRENT_BINARY_DIR}/android/build" assemble
+ )
+ add_custom_target(thrift_aar ALL DEPENDS ${THRIFT_AAR})
+
+else()
+
+ if(IS_ABSOLUTE "${LIB_INSTALL_DIR}")
+ set(JAVA_INSTALL_DIR "${LIB_INSTALL_DIR}/java")
+ else()
+ set(JAVA_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/java")
+ endif()
+
+ if(IS_ABSOLUTE "${DOC_INSTALL_DIR}")
+ set(JAVA_DOC_INSTALL_DIR "${DOC_INSTALL_DIR}/java")
+ else()
+ set(JAVA_DOC_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${DOC_INSTALL_DIR}/java")
+ endif()
+
+ set(PRELEASE "true")
+ if (CMAKE_BUILD_TYPE MATCHES DEBUG)
+ set(PRELEASE "false")
+ endif ()
+
+ add_custom_target(ThriftJava ALL
+ COMMENT "Building Java library using Gradle Wrapper"
+ COMMAND ${GRADLEW_EXECUTABLE} ${GRADLE_OPTS} assemble
+ --console=plain --no-daemon
+ -Prelease=${PRELEASE}
+ -Pthrift.version=${thrift_VERSION}
+ "-Pbuild.dir=${CMAKE_CURRENT_BINARY_DIR}/build"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+ # Enable publishing from CMake if the publishing information is provided
+ add_custom_target(MavenPublish
+ COMMENT "Publishing Java Library to Apache Maven staging"
+ COMMAND ${GRADLEW_EXECUTABLE} ${GRADLE_OPTS} clean uploadArchives
+ --console=plain --no-daemon
+ -Prelease=${PRELEASE}
+ -Pthrift.version=${thrift_VERSION}
+ "-Pbuild.dir=${CMAKE_CURRENT_BINARY_DIR}/build"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+ # Hook the CMake install process to the results from make ALL.
+ # This works best when 'make all && sudo make install/fast' is used.
+ # Using slash to end the source location to avoid copying the directory path.
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/libs/
+ DESTINATION ${JAVA_INSTALL_DIR}
+ FILES_MATCHING PATTERN "libthrift-${thrift_VERSION}.jar")
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/deps/
+ DESTINATION ${JAVA_INSTALL_DIR}
+ FILES_MATCHING PATTERN "*.jar")
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/docs/javadoc/
+ DESTINATION ${JAVA_DOC_INSTALL_DIR})
+
+ if(BUILD_TESTING)
+ add_test(NAME JavaTest
+ COMMAND ${GRADLEW_EXECUTABLE} ${GRADLE_OPTS} test
+ --console=plain --no-daemon
+ -Prelease=${PRELEASE}
+ -Pthrift.version=${thrift_VERSION}
+ "-Pbuild.dir=${CMAKE_CURRENT_BINARY_DIR}/build"
+ "-Pthrift.compiler=${THRIFT_COMPILER}"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+ endif()
+
+endif()
diff --git a/src/jaegertracing/thrift/lib/java/Makefile.am b/src/jaegertracing/thrift/lib/java/Makefile.am
new file mode 100644
index 000000000..65981ca68
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/Makefile.am
@@ -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.
+#
+
+export CLASSPATH
+
+all-local:
+ ./gradlew $(GRADLE_OPTS) assemble \
+ -Prelease=true \
+ -Pthrift.version=$(PACKAGE_VERSION) \
+ --console=plain
+
+install-exec-hook:
+ ./gradlew $(GRADLE_OPTS) install \
+ -Prelease=true \
+ -Pinstall.path=$(DESTDIR)$(JAVA_PREFIX) \
+ -Pinstall.javadoc.path=$(DESTDIR)$(docdir)/java \
+ -Pthrift.version=$(PACKAGE_VERSION) \
+ --console=plain
+
+clean-local:
+ ./gradlew $(GRADLE_OPTS) clean --console=plain
+
+precross: $(THRIFT)
+ ./gradlew $(GRADLE_OPTS) shadowJar \
+ -Prelease=true \
+ -Pthrift.version=$(PACKAGE_VERSION) \
+ -Pthrift.compiler=$(THRIFT) \
+ --console=plain
+
+check-local: $(THRIFT)
+ ./gradlew $(GRADLE_OPTS) test \
+ -Prelease=true \
+ -Pthrift.version=$(PACKAGE_VERSION) \
+ -Pthrift.compiler=$(THRIFT) \
+ --console=plain
+
+maven-publish:
+ ./gradlew $(GRADLE_OPTS) uploadArchives \
+ -Prelease=true \
+ -Pthrift.version=$(PACKAGE_VERSION) \
+ --console=plain
+
+EXTRA_DIST = \
+ build.gradle \
+ gradle.properties \
+ settings.gradle \
+ gradle \
+ gradlew \
+ gradlew.bat \
+ CMakeLists.txt \
+ coding_standards.md \
+ android \
+ src \
+ test \
+ code_quality_tools \
+ README.md
diff --git a/src/jaegertracing/thrift/lib/java/README.md b/src/jaegertracing/thrift/lib/java/README.md
new file mode 100644
index 000000000..c8ec1c37c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/README.md
@@ -0,0 +1,188 @@
+Thrift Java Software Library
+
+License
+=======
+
+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.
+
+Building and installing from source
+===================================
+
+When using a CMake build from the source distribution on Linux the
+easiest way to build and install is this simple command line:
+
+ make all && sudo make install/fast
+
+It is important to use the install/fast option to eliminate
+the automatic rebuild by dependency that causes issues because
+the build tooling is designed to work with cached files in the
+user home directory during the build process. Instead this builds
+the code in the expected local build tree and then uses CMake
+install code to copy to the target destination.
+
+Building Thrift with Gradle without CMake/Autoconf
+==================================================
+
+The Thrift Java source is not build using the GNU tools, but rather uses
+the Gradle build system, which tends to be predominant amongst Java
+developers.
+
+To compile the Java Thrift libraries, simply do the following:
+
+ ./gradlew
+
+Yep, that's easy. Look for libthrift-<version>.jar in the build/libs directory.
+
+The default build will run the unit tests which expect a usable
+Thrift compiler to exist on the system. You have two choices for
+that.
+
+* Build the Thrift executable from source at the default
+ location in the source tree. The project is configured
+ to look for it there.
+* Install the published binary distribution to have Thrift
+ executable in a known location and add the path to the
+ ~/.gradle/gradle.properties file using the property name
+ "thrift.compiler". For example this would set the path in
+ a Windows box if Thrift was installed under C:\Thrift
+
+ thrift.compiler=C:/Thrift/thrift.exe
+
+To just build the library without running unit tests you simply do this.
+
+ ./gradlew assemble
+
+To install the library in the local Maven repository location
+where other Maven or Gradle builds can reference it simply do this.
+
+ ./gradlew install
+
+The library will be placed in your home directory under .m2/repository
+
+To include Thrift in your applications simply add libthrift.jar to your
+classpath, or install if in your default system classpath of choice.
+
+
+Build Thrift behind a proxy:
+
+ ./gradlew -Dhttp.proxyHost=myproxyhost -Dhttp.proxyPort=8080 -Dhttp.proxyUser=thriftuser -Dhttp.proxyPassword=topsecret
+
+or via
+
+ ./configure --with-java GRADLE_OPTS='-Dhttp.proxyHost=myproxyhost -Dhttp.proxyPort=8080 -Dhttp.proxyUser=thriftuser -Dhttp.proxyPassword=topsecret'
+
+
+Unit Test HTML Reports
+======================
+
+The build will automatically generate an HTML Unit Test report. This can be found
+under build/reports/tests/test/index.html. It can be viewed with a browser
+directly from that location.
+
+
+Clover Code Coverage for Thrift
+===============================
+
+The build will optionally generate Clover Code coverage if the Gradle property
+`cloverEnabled=true` is set in ~/.gradle/gradle.properties or on the command line
+via `-PcloverEnabled=true`. The generated report can be found under the location
+build/reports/clover/html/index.html. It can be viewed with a browser
+directly from that location. Additionally, a PDF report is generated and is found
+under the location build/reports/clover/clover.pdf.
+
+The following command will build, unit test, and generate Clover reports:
+
+ ./gradlew -PcloverEnabled=true
+
+
+Publishing Maven Artifacts to Maven Central
+===========================================
+
+The Automake build generates a Makefile that provides the correct parameters
+when you run the build provided the configure.ac has been set with the correct
+version number. The Gradle build will receive the correct value for the build.
+The same applies to the CMake build, the value from the configure.ac file will
+be used if you execute these commands:
+
+ make maven-publish -- This is for an Automake Linux build
+ make MavenPublish -- This is for a CMake generated build
+
+The uploadArchives task in Gradle is preconfigured with all necessary details
+to sign and publish the artifacts from the build to the Apache Maven staging
+repository. The task requires the following externally provided properties to
+authenticate to the repository and sign the artifacts. The preferred approach
+is to create or edit the ~/.gradle/gradle.properties file and add the following
+properties to it.
+
+ # Signing key information for artifacts PGP signature (values are examples)
+ signing.keyId=24875D73
+ signing.password=secret
+ signing.secretKeyRingFile=/Users/me/.gnupg/secring.gpg
+
+ # Apache Maven staging repository user credentials
+ mavenUser=meMyselfAndI
+ mavenPassword=MySuperAwesomeSecretPassword
+
+NOTE: If you do not have a secring.gpg file, see the
+[gradle signing docs](https://docs.gradle.org/current/userguide/signing_plugin.html)
+for instructions on how to generate it.
+
+It is also possible to manually publish using the Gradle build directly.
+With the key information and credentials in place the following will generate
+if needed the build artifacts and proceed to publish the results.
+
+ ./gradlew -Prelease=true uploadArchives
+
+It is also possible to override the target repository for the Maven Publication
+by using a Gradle property, for example you can publish signed JAR files to your
+company internal server if you add this to the command line or in the
+~/.gradle/gradle.properties file. The URL below assumes a Nexus Repository.
+
+ maven-repository-url=https://my.company.com/service/local/staging/deploy/maven2
+
+Or the same on the command line:
+
+ ./gradlew -Pmaven-repository-url=https://my.company.com/service/local/staging/deploy/maven2 -Prelease=true -Pthrift.version=0.11.0 uploadArchives
+
+
+Dependencies
+============
+
+Gradle
+http://gradle.org/
+
+# Breaking Changes
+
+## 0.13.0
+
+* The signature of the 'process' method in TAsyncProcessor and TProcessor has
+changed to remove the boolean return type and instead rely on Exceptions.
+
+* Per THRIFT-4805, TSaslTransportException has been removed. The same condition
+is now covered by TTansportException, where `TTransportException.getType() == END_OF_FILE`.
+
+## 0.12.0
+
+The access modifier of the AutoExpandingBuffer class has been changed from
+public to default (package) and will no longer be accessible by third-party
+libraries.
+
+The access modifier of the ShortStack class has been changed from
+public to default (package) and will no longer be accessible by third-party
+libraries.
+
diff --git a/src/jaegertracing/thrift/lib/java/android/build.gradle b/src/jaegertracing/thrift/lib/java/android/build.gradle
new file mode 100644
index 000000000..c9984237b
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/android/build.gradle
@@ -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.
+ */
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.1"
+ useLibrary 'org.apache.http.legacy'
+ sourceSets.main.java {
+ srcDir '../src'
+ exclude 'org/apache/thrift/transport/TSaslClientTransport.java'
+ exclude 'org/apache/thrift/transport/TSaslServerTransport.java'
+ exclude 'org/apache/thrift/transport/TSaslTransport.java'
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.slf4j:slf4j-api:1.7.13'
+ compile 'javax.servlet:servlet-api:2.5'
+ compile 'org.apache.httpcomponents:httpcore:4.4.4'
+}
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.5.0'
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/android/settings.gradle b/src/jaegertracing/thrift/lib/java/android/settings.gradle
new file mode 100644
index 000000000..75e97be41
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name='thrift'
diff --git a/src/jaegertracing/thrift/lib/java/android/src/main/AndroidManifest.xml b/src/jaegertracing/thrift/lib/java/android/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..43abdb758
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/android/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="org.apache.thrift">
+ <application />
+</manifest>
diff --git a/src/jaegertracing/thrift/lib/java/build.gradle b/src/jaegertracing/thrift/lib/java/build.gradle
new file mode 100644
index 000000000..5f0d2782b
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/build.gradle
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+// Using the legacy plugin classpath for Clover so it can be loaded optionally
+buildscript {
+ repositories {
+ mavenCentral()
+ google()
+ jcenter()
+ gradlePluginPortal()
+ }
+
+ dependencies {
+ classpath 'com.bmuschko:gradle-clover-plugin:2.2.1'
+ }
+}
+
+plugins {
+ id 'java'
+ id 'maven'
+ id 'signing'
+ id 'com.github.johnrengelman.shadow' version '4.0.4'
+}
+
+description = 'Apache Thrift Java Library'
+
+defaultTasks 'build'
+
+// Version components for this project
+group = property('thrift.groupid')
+
+if (Boolean.parseBoolean(project.release)) {
+ version = property('thrift.version')
+} else {
+ version = property('thrift.version') + '-SNAPSHOT'
+}
+
+// Keeping the rest of the build logic in functional named scripts for clarity
+apply from: 'gradle/environment.gradle'
+apply from: 'gradle/sourceConfiguration.gradle'
+apply from: 'gradle/additionalArtifacts.gradle'
+apply from: 'gradle/generateTestThrift.gradle'
+apply from: 'gradle/unitTests.gradle'
+apply from: 'gradle/cloverCoverage.gradle'
+apply from: 'gradle/functionalTests.gradle'
+apply from: 'gradle/publishing.gradle'
+apply from: 'gradle/codeQualityChecks.gradle'
diff --git a/src/jaegertracing/thrift/lib/java/code_quality_tools/findbugs-filter.xml b/src/jaegertracing/thrift/lib/java/code_quality_tools/findbugs-filter.xml
new file mode 100644
index 000000000..8a93b0ad0
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/code_quality_tools/findbugs-filter.xml
@@ -0,0 +1,51 @@
+<FindBugsFilter>
+ <!--
+ This file controls filtering some of the more obnoxious findbugs reports.
+ Some may be worthy of examination and resolution, others are too nit-picky.
+ -->
+ <Match>
+ <Or>
+ <!-- Filter the missing serialVersionUID errors -->
+ <Bug code="SnVI" />
+ <!-- Filter Malicious code vulnerability Warnings -->
+ <Bug code="EI,EI2" />
+ <!-- Filter Unchecked/unconfirmed cast -->
+ <Bug code="BC" />
+ <!-- Filter Should return a zero length array rather than null? -->
+ <Bug code="PZLA" />
+ <!-- Filter Redundant nullcheck -->
+ <Bug code="RCN" />
+ <!-- Filter Exception is caught when Exception is not thrown -->
+ <Bug code="REC" />
+ <!-- Filter Switch statement found where default case is missing -->
+ <Bug code="SF" />
+ <!-- Filter Unread public/protected field -->
+ <Bug code="UrF" />
+ <!-- Filter Field not initialized in constructor and dereferenced -->
+ <Bug code="UwF" />
+ </Or>
+ </Match>
+ <Match>
+ <!-- Filter method invokes System.exit(...), which shuts down the entire virtual machine -->
+ <Class name="org.apache.thrift.transport.TFileTransport" />
+ <Method name="printUsage" />
+ <Bug code="Dm" />
+ </Match>
+ <Match>
+ <!-- Filter method might ignore java.lang.Exception -->
+ <Class name="org.apache.thrift.transport.TSimpleFileTransport" />
+ <Method name="close" />
+ <Bug code="DE" />
+ </Match>
+ <Match>
+ <!-- Filter method might ignore java.lang.Exception -->
+ <Class name="org.apache.thrift.TNonblockingMultiFetchClient$MultiFetch" />
+ <Method name="run" />
+ <Bug code="DE" />
+ </Match>
+ <Match>
+ <!-- Filter Class defines non-transient non-serializable instance field -->
+ <Class name="org.apache.thrift.server.TServlet" />
+ <Bug code="Se" />
+ </Match>
+</FindBugsFilter>
diff --git a/src/jaegertracing/thrift/lib/java/coding_standards.md b/src/jaegertracing/thrift/lib/java/coding_standards.md
new file mode 100644
index 000000000..fa0390bb5
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/src/jaegertracing/thrift/lib/java/gradle.properties b/src/jaegertracing/thrift/lib/java/gradle.properties
new file mode 100644
index 000000000..081165910
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle.properties
@@ -0,0 +1,34 @@
+# This file is shared currently between this Gradle build and the
+# Ant builds for fd303 and JavaScript. Keep the dotted notation for
+# the properties to minimize the changes in the dependencies.
+thrift.version=0.13.0
+thrift.groupid=org.apache.thrift
+release=false
+
+# Local Install paths
+install.path=/usr/local/lib
+install.javadoc.path=/usr/local/lib
+
+# Test execution properties
+testPort=9090
+
+# Test with Clover Code coverage (disabled by default)
+cloverEnabled=false
+
+# Maven dependency download locations
+mvn.repo=http://repo1.maven.org/maven2
+apache.repo=https://repository.apache.org/content/repositories/releases
+
+# Apache Maven publish
+license=http://www.apache.org/licenses/LICENSE-2.0.txt
+maven-repository-url=https://repository.apache.org/service/local/staging/deploy/maven2
+maven-repository-id=apache.releases.https
+
+# Dependency versions
+httpclient.version=4.5.6
+httpcore.version=4.4.1
+slf4j.version=1.7.25
+servlet.version=2.5
+junit.version=4.12
+mockito.version=1.9.5
+javax.annotation.version=1.3.2
diff --git a/src/jaegertracing/thrift/lib/java/gradle/additionalArtifacts.gradle b/src/jaegertracing/thrift/lib/java/gradle/additionalArtifacts.gradle
new file mode 100644
index 000000000..201469da1
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/additionalArtifacts.gradle
@@ -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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+task sourcesJar(type: Jar, group: 'Build') {
+ description = 'Assembles a jar archive containing the main Java sources.'
+
+ classifier 'sources'
+ from sourceSets.main.allSource
+}
+
+task javadocJar(type: Jar, dependsOn: javadoc, group: 'Build') {
+ description = 'Assembles a jar archive containing the JavaDoc.'
+
+ classifier 'javadoc'
+ from javadoc.destinationDir
+}
+
+artifacts {
+ archives sourcesJar
+ archives javadocJar
+}
+
diff --git a/src/jaegertracing/thrift/lib/java/gradle/cloverCoverage.gradle b/src/jaegertracing/thrift/lib/java/gradle/cloverCoverage.gradle
new file mode 100644
index 000000000..cef0e79b1
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/cloverCoverage.gradle
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Keep this as an optional feature for now, disabled by default
+if (Boolean.parseBoolean(project.cloverEnabled)) {
+ apply plugin: 'com.bmuschko.clover'
+
+ dependencies {
+ clover 'org.openclover:clover:4.2.+'
+ }
+
+ clover {
+
+ testIncludes = ['**/Test*.java']
+ // Exclude the generated test code from code coverage
+ testExcludes = ['thrift/test/Test*.java']
+
+ compiler {
+ encoding = 'UTF-8'
+ debug = true
+ }
+
+ report {
+ html = true
+ pdf = true
+ }
+ }
+
+ build.dependsOn cloverGenerateReport
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/codeQualityChecks.gradle b/src/jaegertracing/thrift/lib/java/gradle/codeQualityChecks.gradle
new file mode 100644
index 000000000..1ff1c297d
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/codeQualityChecks.gradle
@@ -0,0 +1,39 @@
+
+// =================================================================
+// Configure the Gradle code quality plugins here.
+//
+
+apply plugin: 'findbugs'
+
+findbugs {
+ ignoreFailures = true
+ toolVersion = '3.0.1'
+ sourceSets = [ sourceSets.main ]
+ effort = 'max'
+ reportLevel = 'low'
+ excludeFilter = file('code_quality_tools/findbugs-filter.xml')
+}
+
+tasks.withType(FindBugs) {
+ reports {
+ text.enabled = false
+ html.enabled = true
+ xml.enabled = false
+ }
+}
+
+apply plugin: 'pmd'
+
+pmd {
+ ignoreFailures = true
+ toolVersion = '6.0.0'
+ sourceSets = [ sourceSets.main ]
+ ruleSets = [ 'java-basic' ]
+}
+
+tasks.withType(Pmd) {
+ reports {
+ html.enabled = true
+ xml.enabled = false
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/environment.gradle b/src/jaegertracing/thrift/lib/java/gradle/environment.gradle
new file mode 100644
index 000000000..45fa63a17
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/environment.gradle
@@ -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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Override the build directory if CMake is used (allows for out-of-tree-builds)
+if (hasProperty('build.dir')) {
+ buildDir = file(property('build.dir'))
+}
+
+// In order to remain compatible with other Ant based builds in the system
+// we convert the gradle.properties into DSL friendly camelCased properties
+ext.installPath = property('install.path')
+ext.installJavadocPath = property('install.javadoc.path')
+
+ext.thriftRoot = file('../..')
+
+if (hasProperty('thrift.compiler')) {
+ ext.thriftCompiler = property('thrift.compiler')
+} else {
+ ext.thriftCompiler = "$thriftRoot/compiler/cpp/thrift"
+}
+
+ext.mvnRepo = property('mvn.repo')
+ext.apacheRepo = property('apache.repo')
+ext.mavenRepositoryUrl = property('maven-repository-url')
+
+// Versions used in this project
+ext.httpclientVersion = property('httpclient.version')
+ext.httpcoreVersion = property('httpcore.version')
+ext.servletVersion = property('servlet.version')
+ext.slf4jVersion = property('slf4j.version')
+ext.junitVersion = property('junit.version')
+ext.mockitoVersion = property('mockito.version')
+ext.javaxAnnotationVersion = property('javax.annotation.version')
+
+// In this section you declare where to find the dependencies of your project
+repositories {
+ maven {
+ name 'Maven Central Repository'
+ url mvnRepo
+ }
+ maven {
+ name 'Apache Maven Repository'
+ url apacheRepo
+ }
+}
+
+dependencies {
+ compile "org.slf4j:slf4j-api:${slf4jVersion}"
+ compile "org.apache.httpcomponents:httpclient:${httpclientVersion}"
+ compile "org.apache.httpcomponents:httpcore:${httpcoreVersion}"
+ compile "javax.servlet:servlet-api:${servletVersion}"
+ compile "javax.annotation:javax.annotation-api:${javaxAnnotationVersion}"
+
+ testCompile "junit:junit:${junitVersion}"
+ testCompile "org.mockito:mockito-all:${mockitoVersion}"
+ testRuntime "org.slf4j:slf4j-log4j12:${slf4jVersion}"
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/functionalTests.gradle b/src/jaegertracing/thrift/lib/java/gradle/functionalTests.gradle
new file mode 100644
index 000000000..c420d122c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/functionalTests.gradle
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// ----------------------------------------------------------------------------
+// Functional testing harness creation. This helps run the cross-check tests.
+// The Makefile precross target invokes the shadowJar task and the tests.json
+// code is changed to call runclient or runserver as needed.
+
+// ----------------------------------------------------------------------------
+// Cross Test sources are separated in their own sourceSet
+//
+sourceSets {
+ crossTest {
+ java {
+ srcDir 'test'
+ include '**/test/TestClient.java'
+ include '**/test/TestServer.java'
+ include '**/test/TestNonblockingServer.java'
+ }
+ }
+}
+
+configurations {
+ crossTestCompile { extendsFrom testCompile }
+ crossTestRuntime { extendsFrom crossTestCompile, testRuntime }
+}
+
+dependencies {
+ crossTestCompile sourceSets.main.output
+ crossTestCompile sourceSets.test.output
+}
+
+// I am using shadow plugin to make a self contained functional test Uber JAR that
+// eliminates startup problems with wrapping the cross-check harness in Gradle.
+// This is used by the runner scripts as the single classpath entry which
+// allows the process to be as lightweight as it can.
+shadowJar {
+ description = 'Assemble a test JAR file for cross-check execution'
+ // make sure the runners are created when this runs
+ dependsOn 'generateRunnerScriptForClient', 'generateRunnerScriptForServer', 'generateRunnerScriptForNonblockingServer'
+
+ baseName = 'functionalTest'
+ destinationDir = file("$buildDir/functionalTestJar")
+ classifier = null
+
+ // We do not need a version number for this internal jar
+ version = null
+
+ // Bundle the complete set of unit test classes including generated code
+ // and the runtime dependencies in one JAR to expedite execution.
+ from sourceSets.test.output
+ from sourceSets.crossTest.output
+ configurations = [project.configurations.testRuntime]
+}
+
+// Common script runner configuration elements
+def scriptExt = ''
+def execExt = ''
+def scriptHead = '#!/bin/bash'
+def args = '$*'
+
+// Although this is marked internal it is an available and stable interface
+if (org.gradle.internal.os.OperatingSystem.current().windows) {
+ scriptExt = '.bat'
+ execExt = '.exe'
+ scriptHead = '@echo off'
+ args = '%*'
+}
+
+// The Java executable to use with the runner scripts
+def javaExe = file("${System.getProperty('java.home')}/bin/java${execExt}").canonicalPath
+// The common Uber jar path
+def jarPath = shadowJar.archivePath.canonicalPath
+def trustStore = file('test/.truststore').canonicalPath
+def keyStore = file('test/.keystore').canonicalPath
+
+task generateRunnerScriptForClient(group: 'Build') {
+ description = 'Generate a runner script for cross-check tests with TestClient'
+
+ def clientFile = file("$buildDir/runclient${scriptExt}")
+
+ def runClientText = """\
+${scriptHead}
+
+"${javaExe}" -cp "$jarPath" "-Djavax.net.ssl.trustStore=$trustStore" -Djavax.net.ssl.trustStorePassword=thrift org.apache.thrift.test.TestClient $args
+"""
+ inputs.property 'runClientText', runClientText
+ outputs.file clientFile
+
+ doLast {
+ clientFile.parentFile.mkdirs()
+ clientFile.text = runClientText
+ clientFile.setExecutable(true, false)
+ }
+}
+
+task generateRunnerScriptForServer(group: 'Build') {
+ description = 'Generate a runner script for cross-check tests with TestServer'
+
+ def serverFile = file("$buildDir/runserver${scriptExt}")
+
+ def runServerText = """\
+${scriptHead}
+
+"${javaExe}" -cp "$jarPath" "-Djavax.net.ssl.keyStore=$keyStore" -Djavax.net.ssl.keyStorePassword=thrift org.apache.thrift.test.TestServer $args
+"""
+
+ inputs.property 'runServerText', runServerText
+ outputs.file serverFile
+
+ doLast {
+ serverFile.parentFile.mkdirs()
+ serverFile.text = runServerText
+ serverFile.setExecutable(true, false)
+ }
+}
+
+task generateRunnerScriptForNonblockingServer(group: 'Build') {
+ description = 'Generate a runner script for cross-check tests with TestNonblockingServer'
+
+ def serverFile = file("$buildDir/runnonblockingserver${scriptExt}")
+
+ def runServerText = """\
+${scriptHead}
+
+"${javaExe}" -cp "$jarPath" "-Djavax.net.ssl.keyStore=$keyStore" -Djavax.net.ssl.keyStorePassword=thrift org.apache.thrift.test.TestNonblockingServer $args
+"""
+
+ inputs.property 'runServerText', runServerText
+ outputs.file serverFile
+
+ doLast {
+ serverFile.parentFile.mkdirs()
+ serverFile.text = runServerText
+ serverFile.setExecutable(true, false)
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/generateTestThrift.gradle b/src/jaegertracing/thrift/lib/java/gradle/generateTestThrift.gradle
new file mode 100644
index 000000000..121bf537d
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/generateTestThrift.gradle
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Generated code locations for Unit tests
+ext.genSrc = file("$buildDir/gen-java")
+ext.genBeanSrc = file("$buildDir/gen-javabean")
+ext.genReuseSrc = file("$buildDir/gen-javareuse")
+ext.genFullCamelSrc = file("$buildDir/gen-fullcamel")
+ext.genUnsafeSrc = file("$buildDir/gen-unsafe")
+
+// Add the generated code directories to the test source set
+sourceSets {
+ test.java.srcDirs genSrc, genBeanSrc, genReuseSrc, genFullCamelSrc, genUnsafeSrc
+}
+
+// ----------------------------------------------------------------------------
+// Code generation for Unit Testing
+
+// A callable closure to make this easier
+ext.thriftCompile = { Task task, String thriftFileName, String generator = 'java', File outputDir = genSrc ->
+ def thriftFile = file("$thriftRoot/test/$thriftFileName")
+ assert thriftFile.exists()
+
+ task.inputs.file thriftFile
+ task.outputs.dir outputDir
+
+ task.doLast {
+ outputDir.mkdirs()
+ def result = exec {
+ executable file(thriftCompiler)
+ args '--gen', generator
+ args '-out', outputDir
+ args thriftFile
+ standardOutput = task.outputBuffer
+ errorOutput = task.outputBuffer
+ ignoreExitValue = true
+ }
+ if (result.exitValue != 0) {
+ // Only show the Thrift compiler output on failures, cuts down on noise!
+ println task.outputBuffer.toString()
+ result.rethrowFailure()
+ }
+ }
+}
+
+task generate(group: 'Build') {
+ description = 'Generate all unit test Thrift sources'
+ compileTestJava.dependsOn it
+}
+
+task generateJava(group: 'Build') {
+ description = 'Generate the thrift gen-java source'
+ generate.dependsOn it
+
+ ext.outputBuffer = new ByteArrayOutputStream()
+
+ thriftCompile(it, 'ThriftTest.thrift')
+ thriftCompile(it, 'JavaTypes.thrift')
+ thriftCompile(it, 'DebugProtoTest.thrift')
+ thriftCompile(it, 'DoubleConstantsTest.thrift')
+ thriftCompile(it, 'OptionalRequiredTest.thrift')
+ thriftCompile(it, 'ManyOptionals.thrift')
+ thriftCompile(it, 'JavaDeepCopyTest.thrift')
+ thriftCompile(it, 'EnumContainersTest.thrift')
+ thriftCompile(it, 'JavaBinaryDefault.thrift')
+}
+
+task generateBeanJava(group: 'Build') {
+ description = 'Generate the thrift gen-javabean source'
+ generate.dependsOn it
+
+ ext.outputBuffer = new ByteArrayOutputStream()
+
+ thriftCompile(it, 'JavaBeansTest.thrift', 'java:beans,nocamel', genBeanSrc)
+}
+
+task generateReuseJava(group: 'Build') {
+ description = 'Generate the thrift gen-javareuse source'
+ generate.dependsOn it
+
+ ext.outputBuffer = new ByteArrayOutputStream()
+
+ thriftCompile(it, 'FullCamelTest.thrift', 'java:fullcamel', genFullCamelSrc)
+}
+
+task generateFullCamelJava(group: 'Build') {
+ description = 'Generate the thrift gen-fullcamel source'
+ generate.dependsOn it
+
+ ext.outputBuffer = new ByteArrayOutputStream()
+
+ thriftCompile(it, 'ReuseObjects.thrift', 'java:reuse-objects', genReuseSrc)
+}
+
+task generateUnsafeBinariesJava(group: 'Build') {
+ description = 'Generate the thrift gen-unsafebinaries source'
+ generate.dependsOn it
+
+ ext.outputBuffer = new ByteArrayOutputStream()
+
+ thriftCompile(it, 'UnsafeTypes.thrift', 'java:unsafe_binaries', genUnsafeSrc)
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/publishing.gradle b/src/jaegertracing/thrift/lib/java/gradle/publishing.gradle
new file mode 100644
index 000000000..029bff93d
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/publishing.gradle
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// ----------------------------------------------------------------------------
+// Installation subtasks, not used currently, we use "make install/fast"
+task installDist(type: Copy, group: 'Install') {
+ description = "Copy Thrift JAR and dependencies into $installPath location"
+
+ destinationDir = file(installPath)
+
+ from jar
+ from configurations.compile
+}
+
+task installJavadoc(type: Copy, group: 'Install', dependsOn: javadoc) {
+ description = "Install Thrift JavaDoc into $installJavadocPath location"
+
+ destinationDir = file(installJavadocPath)
+
+ from javadoc.destinationDir
+}
+
+// This is not needed by Gradle builds but the remaining Ant builds seem to
+// need access to the generated test classes for Thrift unit tests so we
+// assist them to use it this way.
+task copyDependencies(type: Copy, group: 'Build') {
+ description = 'Copy runtime dependencies in a common location for other Ant based projects'
+ project.assemble.dependsOn it
+
+ destinationDir = file("$buildDir/deps")
+ from configurations.testRuntime
+ // exclude some very specific unit test dependencies
+ exclude '**/junit*.jar', '**/mockito*.jar', '**/hamcrest*.jar'
+}
+
+// ----------------------------------------------------------------------------
+// Allow this configuration to be shared between install and uploadArchives tasks
+def configurePom(pom) {
+ pom.project {
+ name 'Apache Thrift'
+ description 'Thrift is a software framework for scalable cross-language services development.'
+ packaging 'jar'
+ url 'http://thrift.apache.org'
+
+ scm {
+ url 'https://github.com/apache/thrift'
+ connection 'scm:git:https://github.com/apache/thrift.git'
+ developerConnection 'scm:git:git@github.com:apache/thrift.git'
+ }
+
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url "${project.license}"
+ distribution 'repo'
+ }
+ }
+
+ developers {
+ developer {
+ id 'dev'
+ name 'Apache Thrift Developers'
+ email 'dev@thrift.apache.org'
+ }
+ }
+ }
+
+ pom.whenConfigured {
+ // Fixup the scope for servlet-api to be 'provided' instead of 'compile'
+ dependencies.find { dep -> dep.groupId == 'javax.servlet' && dep.artifactId == 'servlet-api' }.with {
+ // it.optional = true
+ it.scope = 'provided'
+ }
+ }
+}
+
+install {
+ repositories.mavenInstaller {
+ configurePom(pom)
+ }
+}
+
+uploadArchives {
+ dependsOn test // make sure we run unit tests when publishing
+ repositories.mavenDeployer {
+ // signPom will silently do nothing when no signing information is provided
+ beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
+ repository(url: project.mavenRepositoryUrl) {
+ if (project.hasProperty('mavenUser') && project.hasProperty('mavenPassword')) {
+ authentication(userName: mavenUser, password: mavenPassword)
+ }
+ }
+ configurePom(pom)
+ }
+}
+
+// Signing configuration, optional, only when release and uploadArchives is activated
+signing {
+ required { !version.endsWith("SNAPSHOT") && gradle.taskGraph.hasTask("uploadArchives") }
+ sign configurations.archives
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/sourceConfiguration.gradle b/src/jaegertracing/thrift/lib/java/gradle/sourceConfiguration.gradle
new file mode 100644
index 000000000..8dd0331f7
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/sourceConfiguration.gradle
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// ----------------------------------------------------------------------------
+// source sets for main and test sources
+sourceSets {
+ main {
+ java {
+ srcDir 'src'
+ }
+ }
+ test {
+ java {
+ srcDir 'test'
+ // see functionalTests.gradle for these files
+ exclude '**/test/TestClient.java'
+ exclude '**/test/TestServer.java'
+ exclude '**/test/TestNonblockingServer.java'
+ }
+ resources {
+ srcDir 'test'
+ include 'log4j.properties'
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Compiler configuration details
+
+sourceCompatibility = '1.8'
+targetCompatibility = '1.8'
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+ options.debug = true
+ options.deprecation = true
+ // options.compilerArgs.addAll('-Xlint:unchecked')
+}
+
+// ----------------------------------------------------------------------------
+// Jar packaging details
+processResources {
+ into('META-INF') {
+ from "$thriftRoot/LICENSE"
+ from "$thriftRoot/NOTICE"
+ rename('(.+)', '$1.txt')
+ }
+}
+
+jar {
+ project.test.dependsOn it
+ manifest {
+ attributes([
+ "Implementation-Version": "${project.version}",
+ "Bundle-ManifestVersion": "2",
+ "Bundle-SymbolicName": "${project.group}",
+ "Bundle-Name": "Apache Thrift",
+ "Bundle-Version": "${project.version}",
+ "Bundle-Description": "Apache Thrift library",
+ "Bundle-License": "${project.license}",
+ "Bundle-ActivationPolicy": "lazy",
+ "Export-Package": "${project.group}.async;uses:=\"${project.group}.protocol,${project.group}.transport,org.slf4j,${project.group}\";version=\"${version}\",${project.group}.protocol;uses:=\"${project.group}.transport,${project.group},${project.group}.scheme\";version=\"${version}\",${project.group}.server;uses:=\"${project.group}.transport,${project.group}.protocol,${project.group},org.slf4j,javax.servlet,javax.servlet.http\";version=\"${version}\",${project.group}.transport;uses:=\"${project.group}.protocol,${project.group},org.apache.http.client,org.apache.http.params,org.apache.http.entity,org.apache.http.client.methods,org.apache.http,org.slf4j,javax.net.ssl,javax.net,javax.security.sasl,javax.security.auth.callback\";version=\"${version}\",${project.group};uses:=\"${project.group}.protocol,${project.group}.async,${project.group}.server,${project.group}.transport,org.slf4j,org.apache.log4j,${project.group}.scheme\";version=\"${version}\",${project.group}.meta_data;uses:=\"${project.group}\";version=\"${version}\",${project.group}.scheme;uses:=\"${project.group}.protocol,${project.group}\";version=\"${version}\"",
+ "Import-Package": "javax.net,javax.net.ssl,javax.security.auth.callback,javax.security.sasl,javax.servlet;resolution:=optional,javax.servlet.http;resolution:=optional,org.slf4j;resolution:=optional;version=\"[1.4,2)\",org.apache.http.client;resolution:=optional,org.apache.http.params;resolution:=optional,org.apache.http.entity;resolution:=optional,org.apache.http.client.methods;resolution:=optional,org.apache.http;resolution:=optional"
+ ])
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/unitTests.gradle b/src/jaegertracing/thrift/lib/java/gradle/unitTests.gradle
new file mode 100644
index 000000000..61f2fbdeb
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/unitTests.gradle
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Bundle the test classes in a JAR for other Ant based builds
+task testJar(type: Jar, group: 'Build') {
+ description = 'Assembles a jar archive containing the test classes.'
+ project.test.dependsOn it
+
+ classifier 'test'
+ from sourceSets.test.output
+}
+
+// ----------------------------------------------------------------------------
+// Unit test tasks and configurations
+
+// Help the up to date algorithm to make these tests done
+ext.markTaskDone = { task ->
+ def buildFile = file("$buildDir/${task.name}.flag")
+ task.inputs.files task.classpath
+ task.outputs.file buildFile
+ task.doLast {
+ buildFile.text = 'Passed!'
+ }
+}
+
+task deprecatedEqualityTest(type: JavaExec, group: 'Verification') {
+ description = 'Run the non-JUnit test suite '
+ classpath = sourceSets.test.runtimeClasspath
+ main 'org.apache.thrift.test.EqualityTest'
+ markTaskDone(it)
+}
+
+task deprecatedJavaBeansTest(type: JavaExec, group: 'Verification') {
+ description = 'Run the non-JUnit test suite '
+ classpath = sourceSets.test.runtimeClasspath
+ main 'org.apache.thrift.test.JavaBeansTest'
+ markTaskDone(it)
+}
+
+// Main Unit Test task configuration
+test {
+ description="Run the full test suite"
+ dependsOn deprecatedEqualityTest, deprecatedJavaBeansTest
+
+ // Allow repeating tests even after successful execution
+ if (project.hasProperty('rerunTests')) {
+ outputs.upToDateWhen { false }
+ }
+
+ include '**/Test*.class'
+ exclude '**/Test*\$*.class'
+
+ maxHeapSize = '512m'
+ forkEvery = 1
+
+ systemProperties = [
+ 'build.test': "${compileTestJava.destinationDir}",
+ 'test.port': "${testPort}",
+ 'javax.net.ssl.trustStore': "${projectDir}/test/.truststore",
+ 'javax.net.ssl.trustStorePassword': 'thrift',
+ 'javax.net.ssl.keyStore': "${projectDir}/test/.keystore",
+ 'javax.net.ssl.keyStorePassword': 'thrift'
+ ]
+}
diff --git a/src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.jar b/src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..5c2d1cf01
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.properties b/src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..7c4388a92
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/src/jaegertracing/thrift/lib/java/gradlew b/src/jaegertracing/thrift/lib/java/gradlew
new file mode 100755
index 000000000..83f2acfdc
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# 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
+#
+# https://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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/src/jaegertracing/thrift/lib/java/gradlew.bat b/src/jaegertracing/thrift/lib/java/gradlew.bat
new file mode 100644
index 000000000..9618d8d96
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/jaegertracing/thrift/lib/java/settings.gradle b/src/jaegertracing/thrift/lib/java/settings.gradle
new file mode 100644
index 000000000..c9bd8bc0e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/settings.gradle
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+rootProject.name = 'libthrift'
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/AsyncProcessFunction.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/AsyncProcessFunction.java
new file mode 100644
index 000000000..483c8d054
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/AsyncProcessFunction.java
@@ -0,0 +1,55 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.server.AbstractNonblockingServer;
+
+public abstract class AsyncProcessFunction<I, T extends TBase, R> {
+ final String methodName;
+
+ public AsyncProcessFunction(String methodName) {
+ this.methodName = methodName;
+ }
+
+ protected abstract boolean isOneway();
+
+ public abstract void start(I iface, T args, AsyncMethodCallback<R> resultHandler) throws TException;
+
+ public abstract T getEmptyArgsInstance();
+
+ public abstract AsyncMethodCallback<R> getResultHandler(final AbstractNonblockingServer.AsyncFrameBuffer fb, int seqid);
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public void sendResponse(final AbstractNonblockingServer.AsyncFrameBuffer fb, final TSerializable result, final byte type, final int seqid) throws TException {
+ TProtocol oprot = fb.getOutputProtocol();
+
+ oprot.writeMessageBegin(new TMessage(getMethodName(), type, seqid));
+ result.write(oprot);
+ oprot.writeMessageEnd();
+ oprot.getTransport().flush();
+
+ fb.responseReady();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/EncodingUtils.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/EncodingUtils.java
new file mode 100644
index 000000000..bf14ef57e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/EncodingUtils.java
@@ -0,0 +1,148 @@
+/*
+ * 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.thrift;
+
+/**
+ * Utility methods for use when encoding/decoding raw data as byte arrays.
+ */
+public class EncodingUtils {
+
+ /**
+ * Encode <code>integer</code> as a series of 4 bytes into <code>buf</code>
+ * starting at position 0 within that buffer.
+ *
+ * @param integer
+ * The integer to encode.
+ * @param buf
+ * The buffer to write to.
+ */
+ public static final void encodeBigEndian(final int integer, final byte[] buf) {
+ encodeBigEndian(integer, buf, 0);
+ }
+
+ /**
+ * Encode <code>integer</code> as a series of 4 bytes into <code>buf</code>
+ * starting at position <code>offset</code>.
+ *
+ * @param integer
+ * The integer to encode.
+ * @param buf
+ * The buffer to write to.
+ * @param offset
+ * The offset within <code>buf</code> to start the encoding.
+ */
+ public static final void encodeBigEndian(final int integer, final byte[] buf, int offset) {
+ buf[offset] = (byte) (0xff & (integer >> 24));
+ buf[offset + 1] = (byte) (0xff & (integer >> 16));
+ buf[offset + 2] = (byte) (0xff & (integer >> 8));
+ buf[offset + 3] = (byte) (0xff & (integer));
+ }
+
+ /**
+ * Decode a series of 4 bytes from <code>buf</code>, starting at position 0,
+ * and interpret them as an integer.
+ *
+ * @param buf
+ * The buffer to read from.
+ * @return An integer, as read from the buffer.
+ */
+ public static final int decodeBigEndian(final byte[] buf) {
+ return decodeBigEndian(buf, 0);
+ }
+
+ /**
+ * Decode a series of 4 bytes from <code>buf</code>, start at
+ * <code>offset</code>, and interpret them as an integer.
+ *
+ * @param buf
+ * The buffer to read from.
+ * @param offset
+ * The offset with <code>buf</code> to start the decoding.
+ * @return An integer, as read from the buffer.
+ */
+ public static final int decodeBigEndian(final byte[] buf, int offset) {
+ return ((buf[offset] & 0xff) << 24) | ((buf[offset + 1] & 0xff) << 16)
+ | ((buf[offset + 2] & 0xff) << 8) | ((buf[offset + 3] & 0xff));
+ }
+
+ /**
+ * Bitfield utilities.
+ * Returns true if the bit at position is set in v.
+ */
+ public static final boolean testBit(byte v, int position) {
+ return testBit((int)v, position);
+ }
+
+ public static final boolean testBit(short v, int position) {
+ return testBit((int)v, position);
+ }
+
+ public static final boolean testBit(int v, int position) {
+ return (v & (1 << position)) != 0;
+ }
+
+ public static final boolean testBit(long v, int position) {
+ return (v & (1L << position)) != 0L;
+ }
+
+ /**
+ * Returns v, with the bit at position set to zero.
+ */
+ public static final byte clearBit(byte v, int position) {
+ return (byte)clearBit((int)v, position);
+ }
+
+ public static final short clearBit(short v, int position) {
+ return (short)clearBit((int)v, position);
+ }
+
+ public static final int clearBit(int v, int position) {
+ return v & ~(1 << position);
+ }
+
+ public static final long clearBit(long v, int position) {
+ return v & ~(1L << position);
+ }
+
+ /**
+ * Returns v, with the bit at position set to 1 or 0 depending on value.
+ */
+ public static final byte setBit(byte v, int position, boolean value) {
+ return (byte)setBit((int)v, position, value);
+ }
+
+ public static final short setBit(short v, int position, boolean value) {
+ return (short)setBit((int)v, position, value);
+ }
+
+ public static final int setBit(int v, int position, boolean value) {
+ if(value)
+ return v | (1 << position);
+ else
+ return clearBit(v, position);
+ }
+
+ public static final long setBit(long v, int position, boolean value) {
+ if(value)
+ return v | (1L << position);
+ else
+ return clearBit(v, position);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/Option.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/Option.java
new file mode 100644
index 000000000..d5cd309e8
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/Option.java
@@ -0,0 +1,125 @@
+/*
+ * 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.thrift;
+
+/**
+ * Implementation of the Option type pattern
+ */
+public abstract class Option<T> {
+
+ @SuppressWarnings("rawtypes")
+ private static final Option NONE = new None();
+
+ /**
+ * Whether the Option is defined or not
+ * @return
+ * true if the Option is defined (of type Some)
+ * false if the Option is not defined (of type None)
+ */
+ public abstract boolean isDefined();
+
+ /**
+ * Get the value of the Option (if it is defined)
+ * @return the value
+ * @throws IllegalStateException if called on a None
+ */
+ public abstract T get();
+
+ /**
+ * Get the contained value (if defined) or else return a default value
+ * @param other what to return if the value is not defined (a None)
+ * @return either the value, or other if the value is not defined
+ */
+ public T or(T other) {
+ if (isDefined()) {
+ return get();
+ } else {
+ return other;
+ }
+ }
+ /**
+ * The None type, representing an absent value (instead of "null")
+ */
+ public static class None<T> extends Option<T> {
+ public boolean isDefined() {
+ return false;
+ }
+
+ public T get() {
+ throw new IllegalStateException("Cannot call get() on None");
+ }
+
+ public String toString() {
+ return "None";
+ }
+ }
+
+ /**
+ * The Some type, representing an existence of some value
+ * @param <T> The type of value
+ */
+ public static class Some<T> extends Option<T> {
+ private final T value;
+ public Some(T value) {
+ this.value = value;
+ }
+
+ public boolean isDefined() {
+ return true;
+ }
+
+ public T get() {
+ return value;
+ }
+
+ public String toString() {
+ return "Some(" + value + ")";
+ }
+ }
+
+ /**
+ * Wraps value in an Option type, depending on whether or not value is null
+ * @param value
+ * @param <T> type of value
+ * @return Some(value) if value is not null, None if value is null
+ */
+ public static <T> Option<T> fromNullable(T value) {
+ if (value != null) {
+ return some(value);
+ } else {
+ return none();
+ }
+ }
+
+ /**
+ * Wrap value in a Some type (NB! value must not be null!)
+ * @param value
+ * @param <T> type of value
+ * @return a new Some(value)
+ */
+ public static <T> Some<T> some(T value) {
+ return new Some<T>(value);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> None<T> none() {
+ return (None<T>) NONE;
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/ProcessFunction.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/ProcessFunction.java
new file mode 100644
index 000000000..e6213dfa1
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/ProcessFunction.java
@@ -0,0 +1,88 @@
+package org.apache.thrift;
+
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TMessageType;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolException;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class ProcessFunction<I, T extends TBase> {
+ private final String methodName;
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ProcessFunction.class.getName());
+
+ public ProcessFunction(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public final void process(int seqid, TProtocol iprot, TProtocol oprot, I iface) throws TException {
+ T args = getEmptyArgsInstance();
+ try {
+ args.read(iprot);
+ } catch (TProtocolException e) {
+ iprot.readMessageEnd();
+ TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());
+ oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
+ x.write(oprot);
+ oprot.writeMessageEnd();
+ oprot.getTransport().flush();
+ return;
+ }
+ iprot.readMessageEnd();
+ TSerializable result = null;
+ byte msgType = TMessageType.REPLY;
+
+ try {
+ result = getResult(iface, args);
+ } catch (TTransportException ex) {
+ LOGGER.error("Transport error while processing " + getMethodName(), ex);
+ throw ex;
+ } catch (TApplicationException ex) {
+ LOGGER.error("Internal application error processing " + getMethodName(), ex);
+ result = ex;
+ msgType = TMessageType.EXCEPTION;
+ } catch (Exception ex) {
+ LOGGER.error("Internal error processing " + getMethodName(), ex);
+ if(rethrowUnhandledExceptions()) throw new RuntimeException(ex.getMessage(), ex);
+ if(!isOneway()) {
+ result = new TApplicationException(TApplicationException.INTERNAL_ERROR,
+ "Internal error processing " + getMethodName());
+ msgType = TMessageType.EXCEPTION;
+ }
+ }
+
+ if(!isOneway()) {
+ oprot.writeMessageBegin(new TMessage(getMethodName(), msgType, seqid));
+ result.write(oprot);
+ oprot.writeMessageEnd();
+ oprot.getTransport().flush();
+ }
+ }
+
+ private void handleException(int seqid, TProtocol oprot) throws TException {
+ if (!isOneway()) {
+ TApplicationException x = new TApplicationException(TApplicationException.INTERNAL_ERROR,
+ "Internal error processing " + getMethodName());
+ oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
+ x.write(oprot);
+ oprot.writeMessageEnd();
+ oprot.getTransport().flush();
+ }
+ }
+
+ protected boolean rethrowUnhandledExceptions(){
+ return false;
+ }
+
+ protected abstract boolean isOneway();
+
+ public abstract TBase getResult(I iface, T args) throws TException;
+
+ public abstract T getEmptyArgsInstance();
+
+ public String getMethodName() {
+ return methodName;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TApplicationException.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TApplicationException.java
new file mode 100644
index 000000000..4d693d9ce
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TApplicationException.java
@@ -0,0 +1,150 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolUtil;
+import org.apache.thrift.protocol.TStruct;
+import org.apache.thrift.protocol.TType;
+
+/**
+ * Application level exception
+ *
+ */
+public class TApplicationException extends TException implements TSerializable {
+
+ private static final TStruct TAPPLICATION_EXCEPTION_STRUCT = new TStruct("TApplicationException");
+ private static final TField MESSAGE_FIELD = new TField("message", TType.STRING, (short)1);
+ private static final TField TYPE_FIELD = new TField("type", TType.I32, (short)2);
+
+ private static final long serialVersionUID = 1L;
+
+ public static final int UNKNOWN = 0;
+ public static final int UNKNOWN_METHOD = 1;
+ public static final int INVALID_MESSAGE_TYPE = 2;
+ public static final int WRONG_METHOD_NAME = 3;
+ public static final int BAD_SEQUENCE_ID = 4;
+ public static final int MISSING_RESULT = 5;
+ public static final int INTERNAL_ERROR = 6;
+ public static final int PROTOCOL_ERROR = 7;
+ public static final int INVALID_TRANSFORM = 8;
+ public static final int INVALID_PROTOCOL = 9;
+ public static final int UNSUPPORTED_CLIENT_TYPE = 10;
+
+ protected int type_ = UNKNOWN;
+ private String message_ = null;
+
+ public TApplicationException() {
+ super();
+ }
+
+ public TApplicationException(int type) {
+ super();
+ type_ = type;
+ }
+
+ public TApplicationException(int type, String message) {
+ super(message);
+ type_ = type;
+ }
+
+ public TApplicationException(String message) {
+ super(message);
+ }
+
+ public int getType() {
+ return type_;
+ }
+
+ @Override
+ public String getMessage() {
+ if (message_ == null) {
+ return super.getMessage();
+ }
+ else {
+ return message_;
+ }
+ }
+
+ public void read(TProtocol iprot) throws TException
+ {
+ TField field;
+ iprot.readStructBegin();
+
+ String message = null;
+ int type = UNKNOWN;
+
+ while (true) {
+ field = iprot.readFieldBegin();
+ if (field.type == TType.STOP) {
+ break;
+ }
+ switch (field.id) {
+ case 1:
+ if (field.type == TType.STRING) {
+ message = iprot.readString();
+ } else {
+ TProtocolUtil.skip(iprot, field.type);
+ }
+ break;
+ case 2:
+ if (field.type == TType.I32) {
+ type = iprot.readI32();
+ } else {
+ TProtocolUtil.skip(iprot, field.type);
+ }
+ break;
+ default:
+ TProtocolUtil.skip(iprot, field.type);
+ break;
+ }
+ iprot.readFieldEnd();
+ }
+ iprot.readStructEnd();
+ type_ = type;
+ message_ = message;
+ }
+
+ /**
+ * Convenience factory method for constructing a TApplicationException given a TProtocol input
+ */
+ public static TApplicationException readFrom(TProtocol iprot) throws TException
+ {
+ TApplicationException result = new TApplicationException();
+ result.read(iprot);
+ return result;
+ }
+
+ public void write(TProtocol oprot) throws TException
+ {
+ oprot.writeStructBegin(TAPPLICATION_EXCEPTION_STRUCT);
+ if (getMessage() != null) {
+ oprot.writeFieldBegin(MESSAGE_FIELD);
+ oprot.writeString(getMessage());
+ oprot.writeFieldEnd();
+ }
+ oprot.writeFieldBegin(TYPE_FIELD);
+ oprot.writeI32(type_);
+ oprot.writeFieldEnd();
+ oprot.writeFieldStop();
+ oprot.writeStructEnd();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TAsyncProcessor.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TAsyncProcessor.java
new file mode 100644
index 000000000..66f768896
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TAsyncProcessor.java
@@ -0,0 +1,33 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer;
+
+public interface TAsyncProcessor {
+ /**
+ * Process a single frame.
+
+ * <b>Note:</b> Implementations must call fb.responseReady() once processing
+ * is complete
+ *
+ * @throws TException if the frame cannot be processed
+ */
+ public void process(final AsyncFrameBuffer fb) throws TException;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBase.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBase.java
new file mode 100644
index 000000000..e1489d530
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBase.java
@@ -0,0 +1,67 @@
+/*
+ * 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.thrift;
+
+import java.io.Serializable;
+
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * Generic base interface for generated Thrift objects.
+ *
+ */
+public interface TBase<T extends TBase<T,F>, F extends TFieldIdEnum> extends Comparable<T>, TSerializable, Serializable {
+
+ /**
+ * Get the F instance that corresponds to fieldId.
+ */
+ public F fieldForId(int fieldId);
+
+ /**
+ * Check if a field is currently set or unset.
+ *
+ * @param field
+ */
+ public boolean isSet(F field);
+
+ /**
+ * Get a field's value by field variable. Primitive types will be wrapped in
+ * the appropriate "boxed" types.
+ *
+ * @param field
+ */
+ public Object getFieldValue(F field);
+
+ /**
+ * Set a field's value by field variable. Primitive types must be "boxed" in
+ * the appropriate object wrapper type.
+ *
+ * @param field
+ */
+ public void setFieldValue(F field, Object value);
+
+ public T deepCopy();
+
+ /**
+ * Return to the state of having just been initialized, as though you had just
+ * called the default constructor.
+ */
+ public void clear();
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java
new file mode 100644
index 000000000..f13f068ef
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java
@@ -0,0 +1,114 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.async.AsyncMethodCallback;
+
+import org.apache.thrift.server.AbstractNonblockingServer.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class TBaseAsyncProcessor<I> implements TAsyncProcessor, TProcessor {
+ protected final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
+
+ final I iface;
+ final Map<String,AsyncProcessFunction<I, ? extends TBase,?>> processMap;
+
+ public TBaseAsyncProcessor(I iface, Map<String, AsyncProcessFunction<I, ? extends TBase,?>> processMap) {
+ this.iface = iface;
+ this.processMap = processMap;
+ }
+
+ public Map<String,AsyncProcessFunction<I, ? extends TBase,?>> getProcessMapView() {
+ return Collections.unmodifiableMap(processMap);
+ }
+
+ public void process(final AsyncFrameBuffer fb) throws TException {
+
+ final TProtocol in = fb.getInputProtocol();
+ final TProtocol out = fb.getOutputProtocol();
+
+ //Find processing function
+ final TMessage msg = in.readMessageBegin();
+ AsyncProcessFunction fn = processMap.get(msg.name);
+ if (fn == null) {
+ TProtocolUtil.skip(in, TType.STRUCT);
+ in.readMessageEnd();
+
+ TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD,
+ "Invalid method name: '" + msg.name + "'");
+ LOGGER.debug("Invalid method name", x);
+
+ // this means it is a two-way request, so we can send a reply
+ if (msg.type == TMessageType.CALL) {
+ out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
+ x.write(out);
+ out.writeMessageEnd();
+ out.getTransport().flush();
+ }
+ fb.responseReady();
+ return;
+ }
+
+ //Get Args
+ TBase args = fn.getEmptyArgsInstance();
+
+ try {
+ args.read(in);
+ } catch (TProtocolException e) {
+ in.readMessageEnd();
+
+ TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR,
+ e.getMessage());
+ LOGGER.debug("Could not retrieve function arguments", x);
+
+ if (!fn.isOneway()) {
+ out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
+ x.write(out);
+ out.writeMessageEnd();
+ out.getTransport().flush();
+ }
+ fb.responseReady();
+ return;
+ }
+ in.readMessageEnd();
+
+ if (fn.isOneway()) {
+ fb.responseReady();
+ }
+
+ //start off processing function
+ AsyncMethodCallback resultHandler = fn.getResultHandler(fb, msg.seqid);
+ try {
+ fn.start(iface, args, resultHandler);
+ } catch (Exception e) {
+ LOGGER.debug("Exception handling function", e);
+ resultHandler.onError(e);
+ }
+ return;
+ }
+
+ @Override
+ public void process(TProtocol in, TProtocol out) throws TException {
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseHelper.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseHelper.java
new file mode 100644
index 000000000..6f6c6ebf5
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseHelper.java
@@ -0,0 +1,297 @@
+/**
+ * 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.thrift;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+public final class TBaseHelper {
+
+ private TBaseHelper(){}
+
+ private static final Comparator comparator = new NestedStructureComparator();
+
+ public static int compareTo(Object o1, Object o2) {
+ if (o1 instanceof Comparable) {
+ return compareTo((Comparable)o1, (Comparable)o2);
+ } else if (o1 instanceof List) {
+ return compareTo((List)o1, (List)o2);
+ } else if (o1 instanceof Set) {
+ return compareTo((Set)o1, (Set)o2);
+ } else if (o1 instanceof Map) {
+ return compareTo((Map)o1, (Map)o2);
+ } else if (o1 instanceof byte[]) {
+ return compareTo((byte[])o1, (byte[])o2);
+ } else {
+ throw new IllegalArgumentException("Cannot compare objects of type " + o1.getClass());
+ }
+ }
+
+ public static int compareTo(boolean a, boolean b) {
+ return Boolean.compare(a, b);
+ }
+
+ public static int compareTo(byte a, byte b) {
+ return Byte.compare(a, b);
+ }
+
+ public static int compareTo(short a, short b) {
+ return Short.compare(a,b);
+ }
+
+ public static int compareTo(int a, int b) {
+ return Integer.compare(a, b);
+ }
+
+ public static int compareTo(long a, long b) {
+ return Long.compare(a, b);
+ }
+
+ public static int compareTo(double a, double b) {
+ return Double.compare(a, b);
+ }
+
+ public static int compareTo(String a, String b) {
+ return a.compareTo(b);
+ }
+
+ public static int compareTo(byte[] a, byte[] b) {
+ int compare = compareTo(a.length, b.length);
+ if (compare == 0) {
+ for (int i = 0; i < a.length; i++) {
+ compare = compareTo(a[i], b[i]);
+ if (compare != 0) {
+ break;
+ }
+ }
+ }
+ return compare;
+ }
+
+ public static int compareTo(Comparable a, Comparable b) {
+ return a.compareTo(b);
+ }
+
+ public static int compareTo(List a, List b) {
+ int compare = compareTo(a.size(), b.size());
+ if (compare == 0) {
+ for (int i = 0; i < a.size(); i++) {
+ compare = comparator.compare(a.get(i), b.get(i));
+ if (compare != 0) {
+ break;
+ }
+ }
+ }
+ return compare;
+ }
+
+ public static int compareTo(Set a, Set b) {
+ int compare = compareTo(a.size(), b.size());
+ if (compare == 0) {
+ ArrayList sortedA = new ArrayList(a);
+ ArrayList sortedB = new ArrayList(b);
+
+ Collections.sort(sortedA, comparator);
+ Collections.sort(sortedB, comparator);
+
+ Iterator iterA = sortedA.iterator();
+ Iterator iterB = sortedB.iterator();
+
+ // Compare each item.
+ while (iterA.hasNext() && iterB.hasNext()) {
+ compare = comparator.compare(iterA.next(), iterB.next());
+ if (compare != 0) {
+ break;
+ }
+ }
+ }
+ return compare;
+ }
+
+ public static int compareTo(Map a, Map b) {
+ int lastComparison = compareTo(a.size(), b.size());
+ if (lastComparison != 0) {
+ return lastComparison;
+ }
+
+ // Sort a and b so we can compare them.
+ SortedMap sortedA = new TreeMap(comparator);
+ sortedA.putAll(a);
+ Iterator<Map.Entry> iterA = sortedA.entrySet().iterator();
+ SortedMap sortedB = new TreeMap(comparator);
+ sortedB.putAll(b);
+ Iterator<Map.Entry> iterB = sortedB.entrySet().iterator();
+
+ // Compare each item.
+ while (iterA.hasNext() && iterB.hasNext()) {
+ Map.Entry entryA = iterA.next();
+ Map.Entry entryB = iterB.next();
+ lastComparison = comparator.compare(entryA.getKey(), entryB.getKey());
+ if (lastComparison != 0) {
+ return lastComparison;
+ }
+ lastComparison = comparator.compare(entryA.getValue(), entryB.getValue());
+ if (lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Comparator to compare items inside a structure (e.g. a list, set, or map).
+ */
+ private static class NestedStructureComparator implements Comparator, Serializable {
+ public int compare(Object oA, Object oB) {
+ if (oA == null && oB == null) {
+ return 0;
+ } else if (oA == null) {
+ return -1;
+ } else if (oB == null) {
+ return 1;
+ } else if (oA instanceof List) {
+ return compareTo((List)oA, (List)oB);
+ } else if (oA instanceof Set) {
+ return compareTo((Set)oA, (Set)oB);
+ } else if (oA instanceof Map) {
+ return compareTo((Map)oA, (Map)oB);
+ } else if (oA instanceof byte[]) {
+ return compareTo((byte[])oA, (byte[])oB);
+ } else {
+ return compareTo((Comparable)oA, (Comparable)oB);
+ }
+ }
+ }
+
+ public static void toString(Collection<ByteBuffer> bbs, StringBuilder sb) {
+ Iterator<ByteBuffer> it = bbs.iterator();
+ if (!it.hasNext()) {
+ sb.append("[]");
+ } else {
+ sb.append("[");
+ while (true) {
+ ByteBuffer bb = it.next();
+ org.apache.thrift.TBaseHelper.toString(bb, sb);
+ if (!it.hasNext()) {
+ sb.append("]");
+ return;
+ } else {
+ sb.append(", ");
+ }
+ }
+ }
+ }
+
+ public static void toString(ByteBuffer bb, StringBuilder sb) {
+ byte[] buf = bb.array();
+
+ int arrayOffset = bb.arrayOffset();
+ int offset = arrayOffset + bb.position();
+ int origLimit = arrayOffset + bb.limit();
+ int limit = (origLimit - offset > 128) ? offset + 128 : origLimit;
+
+ for (int i = offset; i < limit; i++) {
+ if (i > offset) {
+ sb.append(" ");
+ }
+ sb.append(paddedByteString(buf[i]));
+ }
+ if (origLimit != limit) {
+ sb.append("...");
+ }
+ }
+
+ public static String paddedByteString(byte b) {
+ int extended = (b | 0x100) & 0x1ff;
+ return Integer.toHexString(extended).toUpperCase().substring(1);
+ }
+
+ public static byte[] byteBufferToByteArray(ByteBuffer byteBuffer) {
+ if (wrapsFullArray(byteBuffer)) {
+ return byteBuffer.array();
+ }
+ byte[] target = new byte[byteBuffer.remaining()];
+ byteBufferToByteArray(byteBuffer, target, 0);
+ return target;
+ }
+
+ public static boolean wrapsFullArray(ByteBuffer byteBuffer) {
+ return byteBuffer.hasArray()
+ && byteBuffer.position() == 0
+ && byteBuffer.arrayOffset() == 0
+ && byteBuffer.remaining() == byteBuffer.capacity();
+ }
+
+ public static int byteBufferToByteArray(ByteBuffer byteBuffer, byte[] target, int offset) {
+ int remaining = byteBuffer.remaining();
+ System.arraycopy(byteBuffer.array(),
+ byteBuffer.arrayOffset() + byteBuffer.position(),
+ target,
+ offset,
+ remaining);
+ return remaining;
+ }
+
+ public static ByteBuffer rightSize(ByteBuffer in) {
+ if (in == null) {
+ return null;
+ }
+ if (wrapsFullArray(in)) {
+ return in;
+ }
+ return ByteBuffer.wrap(byteBufferToByteArray(in));
+ }
+
+ public static ByteBuffer copyBinary(final ByteBuffer orig) {
+ if (orig == null) {
+ return null;
+ }
+ ByteBuffer copy = ByteBuffer.wrap(new byte[orig.remaining()]);
+ if (orig.hasArray()) {
+ System.arraycopy(orig.array(), orig.arrayOffset() + orig.position(), copy.array(), 0, orig.remaining());
+ } else {
+ orig.slice().get(copy.array());
+ }
+
+ return copy;
+ }
+
+ public static byte[] copyBinary(final byte[] orig) {
+ return (orig == null) ? null : Arrays.copyOf(orig, orig.length);
+ }
+
+ public static int hashCode(long value) {
+ return Long.hashCode(value);
+ }
+
+ public static int hashCode(double value) {
+ return Double.hashCode(value);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseProcessor.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseProcessor.java
new file mode 100644
index 000000000..55a0f15d3
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TBaseProcessor.java
@@ -0,0 +1,41 @@
+package org.apache.thrift;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TMessageType;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolUtil;
+import org.apache.thrift.protocol.TType;
+
+public abstract class TBaseProcessor<I> implements TProcessor {
+ private final I iface;
+ private final Map<String,ProcessFunction<I, ? extends TBase>> processMap;
+
+ protected TBaseProcessor(I iface, Map<String, ProcessFunction<I, ? extends TBase>> processFunctionMap) {
+ this.iface = iface;
+ this.processMap = processFunctionMap;
+ }
+
+ public Map<String,ProcessFunction<I, ? extends TBase>> getProcessMapView() {
+ return Collections.unmodifiableMap(processMap);
+ }
+
+ @Override
+ public void process(TProtocol in, TProtocol out) throws TException {
+ TMessage msg = in.readMessageBegin();
+ ProcessFunction fn = processMap.get(msg.name);
+ if (fn == null) {
+ TProtocolUtil.skip(in, TType.STRUCT);
+ in.readMessageEnd();
+ TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, "Invalid method name: '"+msg.name+"'");
+ out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
+ x.write(out);
+ out.writeMessageEnd();
+ out.getTransport().flush();
+ } else {
+ fn.process(msg.seqid, in, out, iface);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java
new file mode 100644
index 000000000..3a2d56c88
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java
@@ -0,0 +1,61 @@
+/*
+ * 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.thrift;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
+
+/**
+ * Class that allows access to the underlying buf without doing deep
+ * copies on it.
+ *
+ */
+public class TByteArrayOutputStream extends ByteArrayOutputStream {
+
+ private final int initialSize;
+
+ public TByteArrayOutputStream(int size) {
+ super(size);
+ this.initialSize = size;
+ }
+
+ public TByteArrayOutputStream() {
+ this(32);
+ }
+
+ public byte[] get() {
+ return buf;
+ }
+
+ public void reset() {
+ super.reset();
+ if (buf.length > initialSize) {
+ buf = new byte[initialSize];
+ }
+ }
+
+ public int len() {
+ return count;
+ }
+
+ public String toString(Charset charset) {
+ return new String(buf, 0, count, charset);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TDeserializer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TDeserializer.java
new file mode 100644
index 000000000..d1d396609
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TDeserializer.java
@@ -0,0 +1,339 @@
+/*
+ * 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.thrift;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.protocol.TProtocolUtil;
+import org.apache.thrift.protocol.TType;
+import org.apache.thrift.transport.TMemoryInputTransport;
+
+/**
+ * Generic utility for easily deserializing objects from a byte array or Java
+ * String.
+ *
+ */
+public class TDeserializer {
+ private final TProtocol protocol_;
+ private final TMemoryInputTransport trans_;
+
+ /**
+ * Create a new TDeserializer that uses the TBinaryProtocol by default.
+ */
+ public TDeserializer() {
+ this(new TBinaryProtocol.Factory());
+ }
+
+ /**
+ * Create a new TDeserializer. It will use the TProtocol specified by the
+ * factory that is passed in.
+ *
+ * @param protocolFactory Factory to create a protocol
+ */
+ public TDeserializer(TProtocolFactory protocolFactory) {
+ trans_ = new TMemoryInputTransport();
+ protocol_ = protocolFactory.getProtocol(trans_);
+ }
+
+ /**
+ * Deserialize the Thrift object from a byte array.
+ *
+ * @param base The object to read into
+ * @param bytes The array to read from
+ */
+ public void deserialize(TBase base, byte[] bytes) throws TException {
+ deserialize(base, bytes, 0, bytes.length);
+ }
+
+ /**
+ * Deserialize the Thrift object from a byte array.
+ *
+ * @param base The object to read into
+ * @param bytes The array to read from
+ * @param offset The offset into {@code bytes}
+ * @param length The length to read from {@code bytes}
+ */
+ public void deserialize(TBase base, byte[] bytes, int offset, int length) throws TException {
+ try {
+ trans_.reset(bytes, offset, length);
+ base.read(protocol_);
+ } finally {
+ trans_.clear();
+ protocol_.reset();
+ }
+ }
+
+ /**
+ * Deserialize the Thrift object from a Java string, using a specified
+ * character set for decoding.
+ *
+ * @param base The object to read into
+ * @param data The string to read from
+ * @param charset Valid JVM charset
+ */
+ public void deserialize(TBase base, String data, String charset) throws TException {
+ try {
+ deserialize(base, data.getBytes(charset));
+ } catch (UnsupportedEncodingException uex) {
+ throw new TException("JVM DOES NOT SUPPORT ENCODING: " + charset);
+ } finally {
+ protocol_.reset();
+ }
+ }
+
+ /**
+ * Deserialize only a single Thrift object (addressed by recursively using field id)
+ * from a byte record.
+ * @param tb The object to read into
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path tb
+ * @param fieldIdPathRest The rest FieldId's that define a path tb
+ * @throws TException
+ */
+ public void partialDeserialize(TBase tb, byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ try {
+ if (locateField(bytes, fieldIdPathFirst, fieldIdPathRest) != null) {
+ // if this line is reached, iprot will be positioned at the start of tb.
+ tb.read(protocol_);
+ }
+ } catch (Exception e) {
+ throw new TException(e);
+ } finally {
+ trans_.clear();
+ protocol_.reset();
+ }
+ }
+
+ /**
+ * Deserialize only a boolean field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to a boolean field
+ * @param fieldIdPathRest The rest FieldId's that define a path to a boolean field
+ * @throws TException
+ */
+ public Boolean partialDeserializeBool(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ return (Boolean) partialDeserializeField(TType.BOOL, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only a byte field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to a byte field
+ * @param fieldIdPathRest The rest FieldId's that define a path to a byte field
+ * @throws TException
+ */
+ public Byte partialDeserializeByte(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ return (Byte) partialDeserializeField(TType.BYTE, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only a double field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to a double field
+ * @param fieldIdPathRest The rest FieldId's that define a path to a double field
+ * @throws TException
+ */
+ public Double partialDeserializeDouble(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ return (Double) partialDeserializeField(TType.DOUBLE, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only an i16 field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to an i16 field
+ * @param fieldIdPathRest The rest FieldId's that define a path to an i16 field
+ * @throws TException
+ */
+ public Short partialDeserializeI16(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ return (Short) partialDeserializeField(TType.I16, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only an i32 field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to an i32 field
+ * @param fieldIdPathRest The rest FieldId's that define a path to an i32 field
+ * @throws TException
+ */
+ public Integer partialDeserializeI32(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ return (Integer) partialDeserializeField(TType.I32, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only an i64 field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to an i64 field
+ * @param fieldIdPathRest The rest FieldId's that define a path to an i64 field
+ * @throws TException
+ */
+ public Long partialDeserializeI64(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ return (Long) partialDeserializeField(TType.I64, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only a string field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to a string field
+ * @param fieldIdPathRest The rest FieldId's that define a path to a string field
+ * @throws TException
+ */
+ public String partialDeserializeString(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ return (String) partialDeserializeField(TType.STRING, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only a binary field (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to a binary field
+ * @param fieldIdPathRest The rest FieldId's that define a path to a binary field
+ * @throws TException
+ */
+ public ByteBuffer partialDeserializeByteArray(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ // TType does not have binary, so we use the arbitrary num 100
+ return (ByteBuffer) partialDeserializeField((byte)100, bytes, fieldIdPathFirst, fieldIdPathRest);
+ }
+
+ /**
+ * Deserialize only the id of the field set in a TUnion (addressed by recursively using field id)
+ * from a byte record.
+ * @param bytes The serialized object to read from
+ * @param fieldIdPathFirst First of the FieldId's that define a path to a TUnion
+ * @param fieldIdPathRest The rest FieldId's that define a path to a TUnion
+ * @throws TException
+ */
+ public Short partialDeserializeSetFieldIdInUnion(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ try {
+ TField field = locateField(bytes, fieldIdPathFirst, fieldIdPathRest);
+ if (field != null){
+ protocol_.readStructBegin(); // The Union
+ return protocol_.readFieldBegin().id; // The field set in the union
+ }
+ return null;
+ } catch (Exception e) {
+ throw new TException(e);
+ } finally {
+ trans_.clear();
+ protocol_.reset();
+ }
+ }
+
+ private Object partialDeserializeField(byte ttype, byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ try {
+ TField field = locateField(bytes, fieldIdPathFirst, fieldIdPathRest);
+ if (field != null) {
+ if (ttype == field.type) {
+ // if this point is reached, iprot will be positioned at the start of
+ // the field
+ switch (ttype) {
+ case TType.BOOL:
+ return protocol_.readBool();
+ case TType.BYTE:
+ return protocol_.readByte();
+ case TType.DOUBLE:
+ return protocol_.readDouble();
+ case TType.I16:
+ return protocol_.readI16();
+ case TType.I32:
+ return protocol_.readI32();
+ case TType.I64:
+ return protocol_.readI64();
+ case TType.STRING:
+ return protocol_.readString();
+ default:
+ return null;
+ }
+ }
+ // hack to differentiate between string and binary
+ if (ttype == 100 && field.type == TType.STRING) {
+ return protocol_.readBinary();
+ }
+ }
+ return null;
+ } catch (Exception e) {
+ throw new TException(e);
+ } finally {
+ trans_.clear();
+ protocol_.reset();
+ }
+ }
+
+ private TField locateField(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ trans_.reset(bytes);
+
+ TFieldIdEnum[] fieldIdPath = new TFieldIdEnum[fieldIdPathRest.length + 1];
+ fieldIdPath[0] = fieldIdPathFirst;
+ System.arraycopy(fieldIdPathRest, 0, fieldIdPath, 1, fieldIdPathRest.length);
+
+ // index into field ID path being currently searched for
+ int curPathIndex = 0;
+
+ // this will be the located field, or null if it is not located
+ TField field = null;
+
+ protocol_.readStructBegin();
+
+ while (curPathIndex < fieldIdPath.length) {
+ field = protocol_.readFieldBegin();
+ // we can stop searching if we either see a stop or we go past the field
+ // id we're looking for (since fields should now be serialized in asc
+ // order).
+ if (field.type == TType.STOP || field.id > fieldIdPath[curPathIndex].getThriftFieldId()) {
+ return null;
+ }
+
+ if (field.id != fieldIdPath[curPathIndex].getThriftFieldId()) {
+ // Not the field we're looking for. Skip field.
+ TProtocolUtil.skip(protocol_, field.type);
+ protocol_.readFieldEnd();
+ } else {
+ // This field is the next step in the path. Step into field.
+ curPathIndex++;
+ if (curPathIndex < fieldIdPath.length) {
+ protocol_.readStructBegin();
+ }
+ }
+ }
+ return field;
+ }
+
+ /**
+ * Deserialize the Thrift object from a Java string, using the default JVM
+ * charset encoding.
+ *
+ * @param base The object to read into
+ * @param data The string to read from
+ */
+ public void fromString(TBase base, String data) throws TException {
+ deserialize(base, data.getBytes());
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnum.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnum.java
new file mode 100644
index 000000000..325fdece7
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnum.java
@@ -0,0 +1,24 @@
+/*
+ * 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.thrift;
+
+public interface TEnum {
+ public int getValue();
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnumHelper.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnumHelper.java
new file mode 100644
index 000000000..fbc778751
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TEnumHelper.java
@@ -0,0 +1,56 @@
+/*
+ * 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.thrift;
+
+import java.lang.NoSuchMethodException;
+import java.lang.IllegalAccessException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Utility class with static methods for interacting with TEnum
+ */
+public class TEnumHelper {
+
+ /**
+ * Given a TEnum class and integer value, this method will return
+ * the associated constant from the given TEnum class.
+ * This method MUST be modified should the name of the 'findByValue' method
+ * change.
+ *
+ * @param enumClass TEnum from which to return a matching constant.
+ * @param value Value for which to return the constant.
+ *
+ * @return The constant in 'enumClass' whose value is 'value' or null if
+ * something went wrong.
+ */
+ public static TEnum getByValue(Class<? extends TEnum> enumClass, int value) {
+ try {
+ Method method = enumClass.getMethod("findByValue", int.class);
+ return (TEnum) method.invoke(null, value);
+ } catch (NoSuchMethodException nsme) {
+ return null;
+ } catch (IllegalAccessException iae) {
+ return null;
+ } catch (InvocationTargetException ite) {
+ return null;
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TException.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TException.java
new file mode 100644
index 000000000..f84f4812e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TException.java
@@ -0,0 +1,45 @@
+/*
+ * 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.thrift;
+
+/**
+ * Generic exception class for Thrift.
+ *
+ */
+public class TException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public TException() {
+ super();
+ }
+
+ public TException(String message) {
+ super(message);
+ }
+
+ public TException(Throwable cause) {
+ super(cause);
+ }
+
+ public TException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldIdEnum.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldIdEnum.java
new file mode 100644
index 000000000..2956fba0b
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldIdEnum.java
@@ -0,0 +1,34 @@
+/*
+ * 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.thrift;
+
+/**
+ * Interface for all generated struct Fields objects.
+ */
+public interface TFieldIdEnum {
+ /**
+ * Get the Thrift field id for the named field.
+ */
+ public short getThriftFieldId();
+
+ /**
+ * Get the field's name, exactly as in the IDL.
+ */
+ public String getFieldName();
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldRequirementType.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldRequirementType.java
new file mode 100644
index 000000000..74bac4eff
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TFieldRequirementType.java
@@ -0,0 +1,30 @@
+/*
+ * 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.thrift;
+
+/**
+ * Requirement type constants.
+ *
+ */
+public final class TFieldRequirementType {
+ public static final byte REQUIRED = 1;
+ public static final byte OPTIONAL = 2;
+ public static final byte DEFAULT = 3;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java
new file mode 100644
index 000000000..c49486217
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java
@@ -0,0 +1,158 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.protocol.*;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * <code>TMultiplexedProcessor</code> is a <code>TProcessor</code> allowing
+ * a single <code>TServer</code> to provide multiple services.
+ *
+ * <p>To do so, you instantiate the processor and then register additional
+ * processors with it, as shown in the following example:</p>
+ *
+ * <blockquote><code>
+ * TMultiplexedProcessor processor = new TMultiplexedProcessor();
+ *
+ * processor.registerProcessor(
+ * "Calculator",
+ * new Calculator.Processor(new CalculatorHandler()));
+ *
+ * processor.registerProcessor(
+ * "WeatherReport",
+ * new WeatherReport.Processor(new WeatherReportHandler()));
+ *
+ * TServerTransport t = new TServerSocket(9090);
+ * TSimpleServer server = new TSimpleServer(processor, t);
+ *
+ * server.serve();
+ * </code></blockquote>
+ */
+public class TMultiplexedProcessor implements TProcessor {
+
+ private final Map<String,TProcessor> SERVICE_PROCESSOR_MAP
+ = new HashMap<String,TProcessor>();
+ private TProcessor defaultProcessor;
+
+ /**
+ * 'Register' a service with this <code>TMultiplexedProcessor</code>. This
+ * allows us to broker requests to individual services by using the service
+ * name to select them at request time.
+ *
+ * @param serviceName Name of a service, has to be identical to the name
+ * declared in the Thrift IDL, e.g. "WeatherReport".
+ * @param processor Implementation of a service, usually referred to
+ * as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface.
+ */
+ public void registerProcessor(String serviceName, TProcessor processor) {
+ SERVICE_PROCESSOR_MAP.put(serviceName, processor);
+ }
+
+ /**
+ * Register a service to be called to process queries without service name
+ * @param processor
+ */
+ public void registerDefault(TProcessor processor) {
+ defaultProcessor = processor;
+ }
+
+ /**
+ * This implementation of <code>process</code> performs the following steps:
+ *
+ * <ol>
+ * <li>Read the beginning of the message.</li>
+ * <li>Extract the service name from the message.</li>
+ * <li>Using the service name to locate the appropriate processor.</li>
+ * <li>Dispatch to the processor, with a decorated instance of TProtocol
+ * that allows readMessageBegin() to return the original TMessage.</li>
+ * </ol>
+ *
+ * @throws TProtocolException If the message type is not CALL or ONEWAY, if
+ * the service name was not found in the message, or if the service
+ * name was not found in the service map. You called {@link #registerProcessor(String, TProcessor) registerProcessor}
+ * during initialization, right? :)
+ */
+ public void process(TProtocol iprot, TProtocol oprot) throws TException {
+ /*
+ Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
+ message header. This pulls the message "off the wire", which we'll
+ deal with at the end of this method.
+ */
+ TMessage message = iprot.readMessageBegin();
+
+ if (message.type != TMessageType.CALL && message.type != TMessageType.ONEWAY) {
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+ "This should not have happened!?");
+ }
+
+ // Extract the service name
+ int index = message.name.indexOf(TMultiplexedProtocol.SEPARATOR);
+ if (index < 0) {
+ if (defaultProcessor != null) {
+ // Dispatch processing to the stored processor
+ defaultProcessor.process(new StoredMessageProtocol(iprot, message), oprot);
+ return;
+ }
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+ "Service name not found in message name: " + message.name + ". Did you " +
+ "forget to use a TMultiplexProtocol in your client?");
+ }
+
+ // Create a new TMessage, something that can be consumed by any TProtocol
+ String serviceName = message.name.substring(0, index);
+ TProcessor actualProcessor = SERVICE_PROCESSOR_MAP.get(serviceName);
+ if (actualProcessor == null) {
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+ "Service name not found: " + serviceName + ". Did you forget " +
+ "to call registerProcessor()?");
+ }
+
+ // Create a new TMessage, removing the service name
+ TMessage standardMessage = new TMessage(
+ message.name.substring(serviceName.length()+TMultiplexedProtocol.SEPARATOR.length()),
+ message.type,
+ message.seqid
+ );
+
+ // Dispatch processing to the stored processor
+ actualProcessor.process(new StoredMessageProtocol(iprot, standardMessage), oprot);
+ }
+
+ /**
+ * Our goal was to work with any protocol. In order to do that, we needed
+ * to allow them to call readMessageBegin() and get a TMessage in exactly
+ * the standard format, without the service name prepended to TMessage.name.
+ */
+ private static class StoredMessageProtocol extends TProtocolDecorator {
+ TMessage messageBegin;
+ public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin) {
+ super(protocol);
+ this.messageBegin = messageBegin;
+ }
+ @Override
+ public TMessage readMessageBegin() throws TException {
+ return messageBegin;
+ }
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java
new file mode 100644
index 000000000..382d978db
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java
@@ -0,0 +1,399 @@
+/**
+ * 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.thrift;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+
+/**
+ * This class uses a single thread to set up non-blocking sockets to a set
+ * of remote servers (hostname and port pairs), and sends a same request to
+ * all these servers. It then fetches responses from servers.
+ *
+ * Parameters:
+ * int maxRecvBufBytesPerServer - an upper limit for receive buffer size
+ * per server (in byte). If a response from a server exceeds this limit, the
+ * client will not allocate memory or read response data for it.
+ *
+ * int fetchTimeoutSeconds - time limit for fetching responses from all
+ * servers (in second). After the timeout, the fetch job is stopped and
+ * available responses are returned.
+ *
+ * ByteBuffer requestBuf - request message that is sent to all servers.
+ *
+ * Output:
+ * Responses are stored in an array of ByteBuffers. Index of elements in
+ * this array corresponds to index of servers in the server list. Content in
+ * a ByteBuffer may be in one of the following forms:
+ * 1. First 4 bytes form an integer indicating length of following data,
+ * then followed by the data.
+ * 2. First 4 bytes form an integer indicating length of following data,
+ * then followed by nothing - this happens when the response data size
+ * exceeds maxRecvBufBytesPerServer, and the client will not read any
+ * response data.
+ * 3. No data in the ByteBuffer - this happens when the server does not
+ * return any response within fetchTimeoutSeconds.
+ *
+ * In some special cases (no servers are given, fetchTimeoutSeconds less
+ * than or equal to 0, requestBuf is null), the return is null.
+ *
+ * Note:
+ * It assumes all remote servers are TNonblockingServers and use
+ * TFramedTransport.
+ *
+ */
+public class TNonblockingMultiFetchClient {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(
+ TNonblockingMultiFetchClient.class.getName()
+ );
+
+ // if the size of the response msg exceeds this limit (in byte), we will
+ // not read the msg
+ private int maxRecvBufBytesPerServer;
+
+ // time limit for fetching data from all servers (in second)
+ private int fetchTimeoutSeconds;
+
+ // store request that will be sent to servers
+ private ByteBuffer requestBuf;
+ private ByteBuffer requestBufDuplication;
+
+ // a list of remote servers
+ private List<InetSocketAddress> servers;
+
+ // store fetch results
+ private TNonblockingMultiFetchStats stats;
+ private ByteBuffer[] recvBuf;
+
+ public TNonblockingMultiFetchClient(int maxRecvBufBytesPerServer,
+ int fetchTimeoutSeconds, ByteBuffer requestBuf,
+ List<InetSocketAddress> servers) {
+ this.maxRecvBufBytesPerServer = maxRecvBufBytesPerServer;
+ this.fetchTimeoutSeconds = fetchTimeoutSeconds;
+ this.requestBuf = requestBuf;
+ this.servers = servers;
+
+ stats = new TNonblockingMultiFetchStats();
+ recvBuf = null;
+ }
+
+ public synchronized int getMaxRecvBufBytesPerServer() {
+ return maxRecvBufBytesPerServer;
+ }
+
+ public synchronized int getFetchTimeoutSeconds() {
+ return fetchTimeoutSeconds;
+ }
+
+ /**
+ * return a duplication of requestBuf, so that requestBuf will not
+ * be modified by others.
+ */
+ public synchronized ByteBuffer getRequestBuf() {
+ if (requestBuf == null) {
+ return null;
+ } else {
+ if (requestBufDuplication == null) {
+ requestBufDuplication = requestBuf.duplicate();
+ }
+ return requestBufDuplication;
+ }
+ }
+
+ public synchronized List<InetSocketAddress> getServerList() {
+ if (servers == null) {
+ return null;
+ }
+ return Collections.unmodifiableList(servers);
+ }
+
+ public synchronized TNonblockingMultiFetchStats getFetchStats() {
+ return stats;
+ }
+
+ /**
+ * main entry function for fetching from servers
+ */
+ public synchronized ByteBuffer[] fetch() {
+ // clear previous results
+ recvBuf = null;
+ stats.clear();
+
+ if (servers == null || servers.size() == 0 ||
+ requestBuf == null || fetchTimeoutSeconds <= 0) {
+ return recvBuf;
+ }
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ MultiFetch multiFetch = new MultiFetch();
+ FutureTask<?> task = new FutureTask(multiFetch, null);
+ executor.execute(task);
+ try {
+ task.get(fetchTimeoutSeconds, TimeUnit.SECONDS);
+ } catch(InterruptedException ie) {
+ // attempt to cancel execution of the task.
+ task.cancel(true);
+ LOGGER.error("interrupted during fetch: "+ie.toString());
+ } catch(ExecutionException ee) {
+ // attempt to cancel execution of the task.
+ task.cancel(true);
+ LOGGER.error("exception during fetch: "+ee.toString());
+ } catch(TimeoutException te) {
+ // attempt to cancel execution of the task.
+ task.cancel(true);
+ LOGGER.error("timeout for fetch: "+te.toString());
+ }
+
+ executor.shutdownNow();
+ multiFetch.close();
+ return recvBuf;
+ }
+
+ /**
+ * Private class that does real fetch job.
+ * Users are not allowed to directly use this class, as its run()
+ * function may run forever.
+ */
+ private class MultiFetch implements Runnable {
+ private Selector selector;
+
+ /**
+ * main entry function for fetching.
+ *
+ * Server responses are stored in TNonblocingMultiFetchClient.recvBuf,
+ * and fetch statistics is in TNonblockingMultiFetchClient.stats.
+ *
+ * Sanity check for parameters has been done in
+ * TNonblockingMultiFetchClient before calling this function.
+ */
+ public void run() {
+ long t1 = System.currentTimeMillis();
+
+ int numTotalServers = servers.size();
+ stats.setNumTotalServers(numTotalServers);
+
+ // buffer for receiving response from servers
+ recvBuf = new ByteBuffer[numTotalServers];
+ // buffer for sending request
+ ByteBuffer sendBuf[] = new ByteBuffer[numTotalServers];
+ long numBytesRead[] = new long[numTotalServers];
+ int frameSize[] = new int[numTotalServers];
+ boolean hasReadFrameSize[] = new boolean[numTotalServers];
+
+ try {
+ selector = Selector.open();
+ } catch (IOException e) {
+ LOGGER.error("selector opens error: "+e.toString());
+ return;
+ }
+
+ for (int i = 0; i < numTotalServers; i++) {
+ // create buffer to send request to server.
+ sendBuf[i] = requestBuf.duplicate();
+ // create buffer to read response's frame size from server
+ recvBuf[i] = ByteBuffer.allocate(4);
+ stats.incTotalRecvBufBytes(4);
+
+ InetSocketAddress server = servers.get(i);
+ SocketChannel s = null;
+ SelectionKey key = null;
+ try {
+ s = SocketChannel.open();
+ s.configureBlocking(false);
+ // now this method is non-blocking
+ s.connect(server);
+ key = s.register(selector, s.validOps());
+ // attach index of the key
+ key.attach(i);
+ } catch (Exception e) {
+ stats.incNumConnectErrorServers();
+ String err = String.format("set up socket to server %s error: %s",
+ server.toString(), e.toString());
+ LOGGER.error(err);
+ // free resource
+ if (s != null) {
+ try {s.close();} catch (Exception ex) {}
+ }
+ if (key != null) {
+ key.cancel();
+ }
+ }
+ }
+
+ // wait for events
+ while (stats.getNumReadCompletedServers() +
+ stats.getNumConnectErrorServers() < stats.getNumTotalServers()) {
+ // if the thread is interrupted (e.g., task is cancelled)
+ if (Thread.currentThread().isInterrupted()) {
+ return;
+ }
+
+ try{
+ selector.select();
+ } catch (Exception e) {
+ LOGGER.error("selector selects error: "+e.toString());
+ continue;
+ }
+
+ Iterator<SelectionKey> it = selector.selectedKeys().iterator();
+ while (it.hasNext()) {
+ SelectionKey selKey = it.next();
+ it.remove();
+
+ // get previously attached index
+ int index = (Integer)selKey.attachment();
+
+ if (selKey.isValid() && selKey.isConnectable()) {
+ // if this socket throws an exception (e.g., connection refused),
+ // print error msg and skip it.
+ try {
+ SocketChannel sChannel = (SocketChannel)selKey.channel();
+ sChannel.finishConnect();
+ } catch (Exception e) {
+ stats.incNumConnectErrorServers();
+ String err = String.format("socket %d connects to server %s " +
+ "error: %s",
+ index, servers.get(index).toString(), e.toString());
+ LOGGER.error(err);
+ }
+ }
+
+ if (selKey.isValid() && selKey.isWritable()) {
+ if (sendBuf[index].hasRemaining()) {
+ // if this socket throws an exception, print error msg and
+ // skip it.
+ try {
+ SocketChannel sChannel = (SocketChannel)selKey.channel();
+ sChannel.write(sendBuf[index]);
+ } catch (Exception e) {
+ String err = String.format("socket %d writes to server %s " +
+ "error: %s",
+ index, servers.get(index).toString(), e.toString());
+ LOGGER.error(err);
+ }
+ }
+ }
+
+ if (selKey.isValid() && selKey.isReadable()) {
+ // if this socket throws an exception, print error msg and
+ // skip it.
+ try {
+ SocketChannel sChannel = (SocketChannel)selKey.channel();
+ int bytesRead = sChannel.read(recvBuf[index]);
+
+ if (bytesRead > 0) {
+ numBytesRead[index] += bytesRead;
+
+ if (!hasReadFrameSize[index] &&
+ recvBuf[index].remaining()==0) {
+ // if the frame size has been read completely, then prepare
+ // to read the actual frame.
+ frameSize[index] = recvBuf[index].getInt(0);
+
+ if (frameSize[index] <= 0) {
+ stats.incNumInvalidFrameSize();
+ String err = String.format("Read an invalid frame size %d"
+ + " from %s. Does the server use TFramedTransport? ",
+ frameSize[index], servers.get(index).toString());
+ LOGGER.error(err);
+ sChannel.close();
+ continue;
+ }
+
+ if (frameSize[index] + 4 > stats.getMaxResponseBytes()) {
+ stats.setMaxResponseBytes(frameSize[index]+4);
+ }
+
+ if (frameSize[index] + 4 > maxRecvBufBytesPerServer) {
+ stats.incNumOverflowedRecvBuf();
+ String err = String.format("Read frame size %d from %s,"
+ + " total buffer size would exceed limit %d",
+ frameSize[index], servers.get(index).toString(),
+ maxRecvBufBytesPerServer);
+ LOGGER.error(err);
+ sChannel.close();
+ continue;
+ }
+
+ // reallocate buffer for actual frame data
+ recvBuf[index] = ByteBuffer.allocate(frameSize[index] + 4);
+ recvBuf[index].putInt(frameSize[index]);
+
+ stats.incTotalRecvBufBytes(frameSize[index]);
+ hasReadFrameSize[index] = true;
+ }
+
+ if (hasReadFrameSize[index] &&
+ numBytesRead[index] >= frameSize[index]+4) {
+ // has read all data
+ sChannel.close();
+ stats.incNumReadCompletedServers();
+ long t2 = System.currentTimeMillis();
+ stats.setReadTime(t2-t1);
+ }
+ }
+ } catch (Exception e) {
+ String err = String.format("socket %d reads from server %s " +
+ "error: %s",
+ index, servers.get(index).toString(), e.toString());
+ LOGGER.error(err);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * dispose any resource allocated
+ */
+ public void close() {
+ try {
+ if (selector.isOpen()) {
+ Iterator<SelectionKey> it = selector.keys().iterator();
+ while (it.hasNext()) {
+ SelectionKey selKey = it.next();
+ SocketChannel sChannel = (SocketChannel)selKey.channel();
+ sChannel.close();
+ }
+
+ selector.close();
+ }
+ } catch (IOException e) {
+ LOGGER.error("free resource error: "+e.toString());
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchStats.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchStats.java
new file mode 100644
index 000000000..90b86208b
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TNonblockingMultiFetchStats.java
@@ -0,0 +1,80 @@
+/**
+ * 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.thrift;
+
+/**
+ * This class keeps track of statistics for TNonblockinMultiFetchClient.
+ */
+public class TNonblockingMultiFetchStats {
+ private int numTotalServers;
+ private int numReadCompletedServers;
+ private int numConnectErrorServers;
+ private int totalRecvBufBytes;
+ private int maxResponseBytes;
+ private int numOverflowedRecvBuf;
+ private int numInvalidFrameSize;
+ // time from the beginning of fetch() function to the reading finish
+ // time of the last socket (in milli-second)
+ private long readTime;
+
+ public TNonblockingMultiFetchStats() {
+ clear();
+ }
+
+ public void clear() {
+ numTotalServers = 0;
+ numReadCompletedServers = 0;
+ numConnectErrorServers = 0;
+ totalRecvBufBytes = 0;
+ maxResponseBytes = 0;
+ numOverflowedRecvBuf = 0;
+ numInvalidFrameSize = 0;
+ readTime = 0;
+ }
+
+ public String toString() {
+ String stats = String.format("numTotalServers=%d, " +
+ "numReadCompletedServers=%d, numConnectErrorServers=%d, " +
+ "numUnresponsiveServers=%d, totalRecvBufBytes=%fM, " +
+ "maxResponseBytes=%d, numOverflowedRecvBuf=%d, " +
+ "numInvalidFrameSize=%d, readTime=%dms",
+ numTotalServers, numReadCompletedServers, numConnectErrorServers,
+ (numTotalServers-numReadCompletedServers-numConnectErrorServers),
+ totalRecvBufBytes/1024.0/1024, maxResponseBytes, numOverflowedRecvBuf,
+ numInvalidFrameSize, readTime);
+ return stats;
+ }
+
+ public void setNumTotalServers(int val) { numTotalServers = val; }
+ public void setMaxResponseBytes(int val) { maxResponseBytes = val; }
+ public void setReadTime(long val) { readTime = val; }
+ public void incNumReadCompletedServers() { numReadCompletedServers++; }
+ public void incNumConnectErrorServers() { numConnectErrorServers++; }
+ public void incNumOverflowedRecvBuf() { numOverflowedRecvBuf++; }
+ public void incTotalRecvBufBytes(int val) { totalRecvBufBytes += val; }
+ public void incNumInvalidFrameSize() { numInvalidFrameSize++; }
+
+ public int getMaxResponseBytes() { return maxResponseBytes; }
+ public int getNumReadCompletedServers() { return numReadCompletedServers; }
+ public int getNumConnectErrorServers() { return numConnectErrorServers; }
+ public int getNumTotalServers() { return numTotalServers; }
+ public int getNumOverflowedRecvBuf() { return numOverflowedRecvBuf;}
+ public int getTotalRecvBufBytes() { return totalRecvBufBytes;}
+ public int getNumInvalidFrameSize() { return numInvalidFrameSize; }
+ public long getReadTime() { return readTime; }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessor.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessor.java
new file mode 100644
index 000000000..15ba9c0fe
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessor.java
@@ -0,0 +1,30 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * A processor is a generic object which operates upon an input stream and
+ * writes to some output stream.
+ */
+public interface TProcessor {
+ public void process(TProtocol in, TProtocol out) throws TException;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessorFactory.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessorFactory.java
new file mode 100644
index 000000000..81933a211
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TProcessorFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * The default processor factory just returns a singleton
+ * instance.
+ */
+public class TProcessorFactory {
+
+ private final TProcessor processor_;
+
+ public TProcessorFactory(TProcessor processor) {
+ processor_ = processor;
+ }
+
+ public TProcessor getProcessor(TTransport trans) {
+ return processor_;
+ }
+
+ public boolean isAsyncProcessor() {
+ return processor_ instanceof TAsyncProcessor;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializable.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializable.java
new file mode 100644
index 000000000..80002c761
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializable.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.thrift;
+
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * Generic base interface for generated Thrift objects.
+ *
+ */
+public interface TSerializable {
+
+ /**
+ * Reads the TObject from the given input protocol.
+ *
+ * @param iprot Input protocol
+ */
+ public void read(TProtocol iprot) throws TException;
+
+ /**
+ * Writes the objects out to the protocol
+ *
+ * @param oprot Output protocol
+ */
+ public void write(TProtocol oprot) throws TException;
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializer.java
new file mode 100644
index 000000000..4e1ce6129
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TSerializer.java
@@ -0,0 +1,110 @@
+/*
+ * 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.thrift;
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TIOStreamTransport;
+
+/**
+ * Generic utility for easily serializing objects into a byte array or Java
+ * String.
+ *
+ */
+public class TSerializer {
+
+ /**
+ * This is the byte array that data is actually serialized into
+ */
+ private final ByteArrayOutputStream baos_ = new ByteArrayOutputStream();
+
+ /**
+ * This transport wraps that byte array
+ */
+ private final TIOStreamTransport transport_ = new TIOStreamTransport(baos_);
+
+ /**
+ * Internal protocol used for serializing objects.
+ */
+ private TProtocol protocol_;
+
+ /**
+ * Create a new TSerializer that uses the TBinaryProtocol by default.
+ */
+ public TSerializer() {
+ this(new TBinaryProtocol.Factory());
+ }
+
+ /**
+ * Create a new TSerializer. It will use the TProtocol specified by the
+ * factory that is passed in.
+ *
+ * @param protocolFactory Factory to create a protocol
+ */
+ public TSerializer(TProtocolFactory protocolFactory) {
+ protocol_ = protocolFactory.getProtocol(transport_);
+ }
+
+ /**
+ * Serialize the Thrift object into a byte array. The process is simple,
+ * just clear the byte array output, write the object into it, and grab the
+ * raw bytes.
+ *
+ * @param base The object to serialize
+ * @return Serialized object in byte[] format
+ */
+ public byte[] serialize(TBase base) throws TException {
+ baos_.reset();
+ base.write(protocol_);
+ return baos_.toByteArray();
+ }
+
+ /**
+ * Serialize the Thrift object into a Java string, using a specified
+ * character set for encoding.
+ *
+ * @param base The object to serialize
+ * @param charset Valid JVM charset
+ * @return Serialized object as a String
+ */
+ public String toString(TBase base, String charset) throws TException {
+ try {
+ return new String(serialize(base), charset);
+ } catch (UnsupportedEncodingException uex) {
+ throw new TException("JVM DOES NOT SUPPORT ENCODING: " + charset);
+ }
+ }
+
+ /**
+ * Serialize the Thrift object into a Java string, using the default JVM
+ * charset encoding.
+ *
+ * @param base The object to serialize
+ * @return Serialized object as a String
+ */
+ public String toString(TBase base) throws TException {
+ return new String(serialize(base));
+ }
+}
+
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClient.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClient.java
new file mode 100644
index 000000000..00a36ee7f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClient.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.thrift;
+
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TMessageType;
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * A TServiceClient is used to communicate with a TService implementation
+ * across protocols and transports.
+ */
+public abstract class TServiceClient {
+ public TServiceClient(TProtocol prot) {
+ this(prot, prot);
+ }
+
+ public TServiceClient(TProtocol iprot, TProtocol oprot) {
+ iprot_ = iprot;
+ oprot_ = oprot;
+ }
+
+ protected TProtocol iprot_;
+ protected TProtocol oprot_;
+
+ protected int seqid_;
+
+ /**
+ * Get the TProtocol being used as the input (read) protocol.
+ * @return the TProtocol being used as the input (read) protocol.
+ */
+ public TProtocol getInputProtocol() {
+ return this.iprot_;
+ }
+
+ /**
+ * Get the TProtocol being used as the output (write) protocol.
+ * @return the TProtocol being used as the output (write) protocol.
+ */
+ public TProtocol getOutputProtocol() {
+ return this.oprot_;
+ }
+
+ protected void sendBase(String methodName, TBase<?,?> args) throws TException {
+ sendBase(methodName, args, TMessageType.CALL);
+ }
+
+ protected void sendBaseOneway(String methodName, TBase<?,?> args) throws TException {
+ sendBase(methodName, args, TMessageType.ONEWAY);
+ }
+
+ private void sendBase(String methodName, TBase<?,?> args, byte type) throws TException {
+ oprot_.writeMessageBegin(new TMessage(methodName, type, ++seqid_));
+ args.write(oprot_);
+ oprot_.writeMessageEnd();
+ oprot_.getTransport().flush();
+ }
+
+ protected void receiveBase(TBase<?,?> result, String methodName) throws TException {
+ TMessage msg = iprot_.readMessageBegin();
+ if (msg.type == TMessageType.EXCEPTION) {
+ TApplicationException x = new TApplicationException();
+ x.read(iprot_);
+ iprot_.readMessageEnd();
+ throw x;
+ }
+ if (msg.seqid != seqid_) {
+ throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID,
+ String.format("%s failed: out of sequence response: expected %d but got %d", methodName, seqid_, msg.seqid));
+ }
+ result.read(iprot_);
+ iprot_.readMessageEnd();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClientFactory.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClientFactory.java
new file mode 100644
index 000000000..988e65591
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TServiceClientFactory.java
@@ -0,0 +1,45 @@
+/*
+ * 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.thrift;
+
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * A TServiceClientFactory provides a general way to get a TServiceClient
+ * connected to a remote TService via a protocol.
+ * @param <T>
+ */
+public interface TServiceClientFactory<T extends TServiceClient> {
+ /**
+ * Get a brand-new T using <i>prot</i> as both the input and output protocol.
+ * @param prot
+ * @return A brand-new T using <i>prot</i> as both the input and output protocol.
+ */
+ public T getClient(TProtocol prot);
+
+ /**
+ * Get a brand new T using the specified input and output protocols. The
+ * input and output protocols may be the same instance.
+ * @param iprot
+ * @param oprot
+ * @return a brand new T using the specified input and output protocols
+ */
+ public T getClient(TProtocol iprot, TProtocol oprot);
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TUnion.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TUnion.java
new file mode 100644
index 000000000..1ef11df49
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/TUnion.java
@@ -0,0 +1,279 @@
+/**
+ * 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.thrift;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolException;
+import org.apache.thrift.protocol.TStruct;
+import org.apache.thrift.scheme.IScheme;
+import org.apache.thrift.scheme.SchemeFactory;
+import org.apache.thrift.scheme.StandardScheme;
+import org.apache.thrift.scheme.TupleScheme;
+
+public abstract class TUnion<T extends TUnion<T,F>, F extends TFieldIdEnum> implements TBase<T, F> {
+
+ protected Object value_;
+ protected F setField_;
+
+ protected TUnion() {
+ setField_ = null;
+ value_ = null;
+ }
+
+ private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
+ static {
+ schemes.put(StandardScheme.class, new TUnionStandardSchemeFactory());
+ schemes.put(TupleScheme.class, new TUnionTupleSchemeFactory());
+ }
+
+ protected TUnion(F setField, Object value) {
+ setFieldValue(setField, value);
+ }
+
+ protected TUnion(TUnion<T, F> other) {
+ if (!other.getClass().equals(this.getClass())) {
+ throw new ClassCastException();
+ }
+ setField_ = other.setField_;
+ value_ = deepCopyObject(other.value_);
+ }
+
+ private static Object deepCopyObject(Object o) {
+ if (o instanceof TBase) {
+ return ((TBase)o).deepCopy();
+ } else if (o instanceof ByteBuffer) {
+ return TBaseHelper.copyBinary((ByteBuffer)o);
+ } else if (o instanceof List) {
+ return deepCopyList((List)o);
+ } else if (o instanceof Set) {
+ return deepCopySet((Set)o);
+ } else if (o instanceof Map) {
+ return deepCopyMap((Map)o);
+ } else {
+ return o;
+ }
+ }
+
+ private static Map deepCopyMap(Map<Object, Object> map) {
+ Map copy = new HashMap(map.size());
+ for (Map.Entry<Object, Object> entry : map.entrySet()) {
+ copy.put(deepCopyObject(entry.getKey()), deepCopyObject(entry.getValue()));
+ }
+ return copy;
+ }
+
+ private static Set deepCopySet(Set set) {
+ Set copy = new HashSet(set.size());
+ for (Object o : set) {
+ copy.add(deepCopyObject(o));
+ }
+ return copy;
+ }
+
+ private static List deepCopyList(List list) {
+ List copy = new ArrayList(list.size());
+ for (Object o : list) {
+ copy.add(deepCopyObject(o));
+ }
+ return copy;
+ }
+
+ public F getSetField() {
+ return setField_;
+ }
+
+ public Object getFieldValue() {
+ return value_;
+ }
+
+ public Object getFieldValue(F fieldId) {
+ if (fieldId != setField_) {
+ throw new IllegalArgumentException("Cannot get the value of field " + fieldId + " because union's set field is " + setField_);
+ }
+
+ return getFieldValue();
+ }
+
+ public Object getFieldValue(int fieldId) {
+ return getFieldValue(enumForId((short)fieldId));
+ }
+
+ public boolean isSet() {
+ return setField_ != null;
+ }
+
+ public boolean isSet(F fieldId) {
+ return setField_ == fieldId;
+ }
+
+ public boolean isSet(int fieldId) {
+ return isSet(enumForId((short)fieldId));
+ }
+
+ public void read(TProtocol iprot) throws TException {
+ schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
+ }
+
+ public void setFieldValue(F fieldId, Object value) {
+ checkType(fieldId, value);
+ setField_ = fieldId;
+ value_ = value;
+ }
+
+ public void setFieldValue(int fieldId, Object value) {
+ setFieldValue(enumForId((short)fieldId), value);
+ }
+
+ public void write(TProtocol oprot) throws TException {
+ schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
+ }
+
+ /**
+ * Implementation should be generated so that we can efficiently type check
+ * various values.
+ * @param setField
+ * @param value
+ */
+ protected abstract void checkType(F setField, Object value) throws ClassCastException;
+
+ /**
+ * Implementation should be generated to read the right stuff from the wire
+ * based on the field header.
+ * @param field
+ * @return read Object based on the field header, as specified by the argument.
+ */
+ protected abstract Object standardSchemeReadValue(TProtocol iprot, TField field) throws TException;
+ protected abstract void standardSchemeWriteValue(TProtocol oprot) throws TException;
+
+ protected abstract Object tupleSchemeReadValue(TProtocol iprot, short fieldID) throws TException;
+ protected abstract void tupleSchemeWriteValue(TProtocol oprot) throws TException;
+
+ protected abstract TStruct getStructDesc();
+
+ protected abstract TField getFieldDesc(F setField);
+
+ protected abstract F enumForId(short id);
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<");
+ sb.append(this.getClass().getSimpleName());
+ sb.append(" ");
+
+ if (getSetField() != null) {
+ Object v = getFieldValue();
+ sb.append(getFieldDesc(getSetField()).name);
+ sb.append(":");
+ if(v instanceof ByteBuffer) {
+ TBaseHelper.toString((ByteBuffer)v, sb);
+ } else {
+ sb.append(v.toString());
+ }
+ }
+ sb.append(">");
+ return sb.toString();
+ }
+
+ public final void clear() {
+ this.setField_ = null;
+ this.value_ = null;
+ }
+
+ private static class TUnionStandardSchemeFactory implements SchemeFactory {
+ public TUnionStandardScheme getScheme() {
+ return new TUnionStandardScheme();
+ }
+ }
+
+ private static class TUnionStandardScheme extends StandardScheme<TUnion> {
+
+ @Override
+ public void read(TProtocol iprot, TUnion struct) throws TException {
+ struct.setField_ = null;
+ struct.value_ = null;
+
+ iprot.readStructBegin();
+
+ TField field = iprot.readFieldBegin();
+
+ struct.value_ = struct.standardSchemeReadValue(iprot, field);
+ if (struct.value_ != null) {
+ struct.setField_ = struct.enumForId(field.id);
+ }
+
+ iprot.readFieldEnd();
+ // this is so that we will eat the stop byte. we could put a check here to
+ // make sure that it actually *is* the stop byte, but it's faster to do it
+ // this way.
+ iprot.readFieldBegin();
+ iprot.readStructEnd();
+ }
+
+ @Override
+ public void write(TProtocol oprot, TUnion struct) throws TException {
+ if (struct.getSetField() == null || struct.getFieldValue() == null) {
+ throw new TProtocolException("Cannot write a TUnion with no set value!");
+ }
+ oprot.writeStructBegin(struct.getStructDesc());
+ oprot.writeFieldBegin(struct.getFieldDesc(struct.setField_));
+ struct.standardSchemeWriteValue(oprot);
+ oprot.writeFieldEnd();
+ oprot.writeFieldStop();
+ oprot.writeStructEnd();
+ }
+ }
+
+ private static class TUnionTupleSchemeFactory implements SchemeFactory {
+ public TUnionTupleScheme getScheme() {
+ return new TUnionTupleScheme();
+ }
+ }
+
+ private static class TUnionTupleScheme extends TupleScheme<TUnion> {
+
+ @Override
+ public void read(TProtocol iprot, TUnion struct) throws TException {
+ struct.setField_ = null;
+ struct.value_ = null;
+ short fieldID = iprot.readI16();
+ struct.value_ = struct.tupleSchemeReadValue(iprot, fieldID);
+ if (struct.value_ != null) {
+ struct.setField_ = struct.enumForId(fieldID);
+ }
+ }
+
+ @Override
+ public void write(TProtocol oprot, TUnion struct) throws TException {
+ if (struct.getSetField() == null || struct.getFieldValue() == null) {
+ throw new TProtocolException("Cannot write a TUnion with no set value!");
+ }
+ oprot.writeI16(struct.setField_.getThriftFieldId());
+ struct.tupleSchemeWriteValue(oprot);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/annotation/Nullable.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/annotation/Nullable.java
new file mode 100644
index 000000000..a34b01ebb
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/annotation/Nullable.java
@@ -0,0 +1,33 @@
+/*
+ * 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.thrift.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation indicating a field, method return, or method parameter may be {@code null}.
+ * We package our own annotation to avoid a mandatory third-party dependency.
+ */
+@Retention(RetentionPolicy.CLASS)
+public @interface Nullable {
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java
new file mode 100644
index 000000000..4ebde0741
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java
@@ -0,0 +1,51 @@
+/*
+ * 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.thrift.async;
+
+/**
+ * A handler interface asynchronous clients can implement to receive future
+ * notice of the results of an asynchronous method call.
+ *
+ * @param <T> The return type of the asynchronously invoked method.
+ */
+public interface AsyncMethodCallback<T> {
+ /**
+ * This method will be called when the remote side has completed invoking
+ * your method call and the result is fully read. For {@code oneway} method
+ * calls, this method will be called as soon as we have completed writing out
+ * the request.
+ *
+ * @param response The return value of the asynchronously invoked method;
+ * {@code null} for void methods which includes
+ * {@code oneway} methods.
+ */
+ void onComplete(T response);
+
+ /**
+ * This method will be called when there is either an unexpected client-side
+ * exception like an IOException or else when the remote method raises an
+ * exception, either declared in the IDL or due to an unexpected server-side
+ * error.
+ *
+ * @param exception The exception encountered processing the the asynchronous
+ * method call, may be a local exception or an unmarshalled
+ * remote exception.
+ */
+ void onError(Exception exception);
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClient.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClient.java
new file mode 100644
index 000000000..005018a83
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClient.java
@@ -0,0 +1,102 @@
+/*
+ * 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.thrift.async;
+
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TNonblockingTransport;
+
+public abstract class TAsyncClient {
+ protected final TProtocolFactory ___protocolFactory;
+ protected final TNonblockingTransport ___transport;
+ protected final TAsyncClientManager ___manager;
+ protected TAsyncMethodCall ___currentMethod;
+ private Exception ___error;
+ private long ___timeout;
+
+ public TAsyncClient(TProtocolFactory protocolFactory, TAsyncClientManager manager, TNonblockingTransport transport) {
+ this(protocolFactory, manager, transport, 0);
+ }
+
+ public TAsyncClient(TProtocolFactory protocolFactory, TAsyncClientManager manager, TNonblockingTransport transport, long timeout) {
+ this.___protocolFactory = protocolFactory;
+ this.___manager = manager;
+ this.___transport = transport;
+ this.___timeout = timeout;
+ }
+
+ public TProtocolFactory getProtocolFactory() {
+ return ___protocolFactory;
+ }
+
+ public long getTimeout() {
+ return ___timeout;
+ }
+
+ public boolean hasTimeout() {
+ return ___timeout > 0;
+ }
+
+ public void setTimeout(long timeout) {
+ this.___timeout = timeout;
+ }
+
+ /**
+ * Is the client in an error state?
+ * @return If client in an error state?
+ */
+ public boolean hasError() {
+ return ___error != null;
+ }
+
+ /**
+ * Get the client's error - returns null if no error
+ * @return Get the client's error. <p> returns null if no error
+ */
+ public Exception getError() {
+ return ___error;
+ }
+
+ protected void checkReady() {
+ // Ensure we are not currently executing a method
+ if (___currentMethod != null) {
+ throw new IllegalStateException("Client is currently executing another method: " + ___currentMethod.getClass().getName());
+ }
+
+ // Ensure we're not in an error state
+ if (___error != null) {
+ throw new IllegalStateException("Client has an error!", ___error);
+ }
+ }
+
+ /**
+ * Called by delegate method when finished
+ */
+ protected void onComplete() {
+ ___currentMethod = null;
+ }
+
+ /**
+ * Called by delegate method on error
+ */
+ protected void onError(Exception exception) {
+ ___transport.close();
+ ___currentMethod = null;
+ ___error = exception;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientFactory.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientFactory.java
new file mode 100644
index 000000000..28feb73d1
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientFactory.java
@@ -0,0 +1,25 @@
+/*
+ * 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.thrift.async;
+
+import org.apache.thrift.transport.TNonblockingTransport;
+
+public interface TAsyncClientFactory<T extends TAsyncClient> {
+ public T getAsyncClient(TNonblockingTransport transport);
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java
new file mode 100644
index 000000000..c07ccd540
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java
@@ -0,0 +1,201 @@
+/*
+ * 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.thrift.async;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.thrift.TException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Contains selector thread which transitions method call objects
+ */
+public class TAsyncClientManager {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TAsyncClientManager.class.getName());
+
+ private final SelectThread selectThread;
+ private final ConcurrentLinkedQueue<TAsyncMethodCall> pendingCalls = new ConcurrentLinkedQueue<TAsyncMethodCall>();
+
+ public TAsyncClientManager() throws IOException {
+ this.selectThread = new SelectThread();
+ selectThread.start();
+ }
+
+ public void call(TAsyncMethodCall method) throws TException {
+ if (!isRunning()) {
+ throw new TException("SelectThread is not running");
+ }
+ method.prepareMethodCall();
+ pendingCalls.add(method);
+ selectThread.getSelector().wakeup();
+ }
+
+ public void stop() {
+ selectThread.finish();
+ }
+
+ public boolean isRunning() {
+ return selectThread.isAlive();
+ }
+
+ private class SelectThread extends Thread {
+ private final Selector selector;
+ private volatile boolean running;
+ private final TreeSet<TAsyncMethodCall> timeoutWatchSet = new TreeSet<TAsyncMethodCall>(new TAsyncMethodCallTimeoutComparator());
+
+ public SelectThread() throws IOException {
+ this.selector = SelectorProvider.provider().openSelector();
+ this.running = true;
+ this.setName("TAsyncClientManager#SelectorThread " + this.getId());
+
+ // We don't want to hold up the JVM when shutting down
+ setDaemon(true);
+ }
+
+ public Selector getSelector() {
+ return selector;
+ }
+
+ public void finish() {
+ running = false;
+ selector.wakeup();
+ }
+
+ public void run() {
+ while (running) {
+ try {
+ try {
+ if (timeoutWatchSet.size() == 0) {
+ // No timeouts, so select indefinitely
+ selector.select();
+ } else {
+ // We have a timeout pending, so calculate the time until then and select appropriately
+ long nextTimeout = timeoutWatchSet.first().getTimeoutTimestamp();
+ long selectTime = nextTimeout - System.currentTimeMillis();
+ if (selectTime > 0) {
+ // Next timeout is in the future, select and wake up then
+ selector.select(selectTime);
+ } else {
+ // Next timeout is now or in past, select immediately so we can time out
+ selector.selectNow();
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.error("Caught IOException in TAsyncClientManager!", e);
+ }
+ transitionMethods();
+ timeoutMethods();
+ startPendingMethods();
+ } catch (Exception exception) {
+ LOGGER.error("Ignoring uncaught exception in SelectThread", exception);
+ }
+ }
+
+ try {
+ selector.close();
+ } catch (IOException ex) {
+ LOGGER.warn("Could not close selector. This may result in leaked resources!", ex);
+ }
+ }
+
+ // Transition methods for ready keys
+ private void transitionMethods() {
+ try {
+ Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
+ while (keys.hasNext()) {
+ SelectionKey key = keys.next();
+ keys.remove();
+ if (!key.isValid()) {
+ // this can happen if the method call experienced an error and the
+ // key was cancelled. can also happen if we timeout a method, which
+ // results in a channel close.
+ // just skip
+ continue;
+ }
+ TAsyncMethodCall methodCall = (TAsyncMethodCall)key.attachment();
+ methodCall.transition(key);
+
+ // If done or error occurred, remove from timeout watch set
+ if (methodCall.isFinished() || methodCall.getClient().hasError()) {
+ timeoutWatchSet.remove(methodCall);
+ }
+ }
+ } catch (ClosedSelectorException e) {
+ LOGGER.error("Caught ClosedSelectorException in TAsyncClientManager!", e);
+ }
+ }
+
+ // Timeout any existing method calls
+ private void timeoutMethods() {
+ Iterator<TAsyncMethodCall> iterator = timeoutWatchSet.iterator();
+ long currentTime = System.currentTimeMillis();
+ while (iterator.hasNext()) {
+ TAsyncMethodCall methodCall = iterator.next();
+ if (currentTime >= methodCall.getTimeoutTimestamp()) {
+ iterator.remove();
+ methodCall.onError(new TimeoutException("Operation " + methodCall.getClass() + " timed out after " + (currentTime - methodCall.getStartTime()) + " ms."));
+ } else {
+ break;
+ }
+ }
+ }
+
+ // Start any new calls
+ private void startPendingMethods() {
+ TAsyncMethodCall methodCall;
+ while ((methodCall = pendingCalls.poll()) != null) {
+ // Catch registration errors. method will catch transition errors and cleanup.
+ try {
+ methodCall.start(selector);
+
+ // If timeout specified and first transition went smoothly, add to timeout watch set
+ TAsyncClient client = methodCall.getClient();
+ if (client.hasTimeout() && !client.hasError()) {
+ timeoutWatchSet.add(methodCall);
+ }
+ } catch (Exception exception) {
+ LOGGER.warn("Caught exception in TAsyncClientManager!", exception);
+ methodCall.onError(exception);
+ }
+ }
+ }
+ }
+
+ /** Comparator used in TreeSet */
+ private static class TAsyncMethodCallTimeoutComparator implements Comparator<TAsyncMethodCall>, Serializable {
+ public int compare(TAsyncMethodCall left, TAsyncMethodCall right) {
+ if (left.getTimeoutTimestamp() == right.getTimeoutTimestamp()) {
+ return (int)(left.getSequenceId() - right.getSequenceId());
+ } else {
+ return (int)(left.getTimeoutTimestamp() - right.getTimeoutTimestamp());
+ }
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java
new file mode 100644
index 000000000..3bf1747f4
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java
@@ -0,0 +1,284 @@
+/*
+ * 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.thrift.async;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TMemoryBuffer;
+import org.apache.thrift.transport.TNonblockingTransport;
+import org.apache.thrift.transport.TTransportException;
+
+/**
+ * Encapsulates an async method call.
+ * <p>
+ * Need to generate:
+ * <ul>
+ * <li>protected abstract void write_args(TProtocol protocol)</li>
+ * <li>protected abstract T getResult() throws &lt;Exception_1&gt;, &lt;Exception_2&gt;, ...</li>
+ * </ul>
+ *
+ * @param <T> The return type of the encapsulated method call.
+ */
+public abstract class TAsyncMethodCall<T> {
+
+ private static final int INITIAL_MEMORY_BUFFER_SIZE = 128;
+ private static AtomicLong sequenceIdCounter = new AtomicLong(0);
+
+ public static enum State {
+ CONNECTING,
+ WRITING_REQUEST_SIZE,
+ WRITING_REQUEST_BODY,
+ READING_RESPONSE_SIZE,
+ READING_RESPONSE_BODY,
+ RESPONSE_READ,
+ ERROR;
+ }
+
+ /**
+ * Next step in the call, initialized by start()
+ */
+ private State state = null;
+
+ protected final TNonblockingTransport transport;
+ private final TProtocolFactory protocolFactory;
+ protected final TAsyncClient client;
+ private final AsyncMethodCallback<T> callback;
+ private final boolean isOneway;
+ private long sequenceId;
+ private final long timeout;
+
+ private ByteBuffer sizeBuffer;
+ private final byte[] sizeBufferArray = new byte[4];
+ private ByteBuffer frameBuffer;
+
+ private long startTime = System.currentTimeMillis();
+
+ protected TAsyncMethodCall(TAsyncClient client, TProtocolFactory protocolFactory, TNonblockingTransport transport, AsyncMethodCallback<T> callback, boolean isOneway) {
+ this.transport = transport;
+ this.callback = callback;
+ this.protocolFactory = protocolFactory;
+ this.client = client;
+ this.isOneway = isOneway;
+ this.sequenceId = TAsyncMethodCall.sequenceIdCounter.getAndIncrement();
+ this.timeout = client.getTimeout();
+ }
+
+ protected State getState() {
+ return state;
+ }
+
+ protected boolean isFinished() {
+ return state == State.RESPONSE_READ;
+ }
+
+ protected long getStartTime() {
+ return startTime;
+ }
+
+ protected long getSequenceId() {
+ return sequenceId;
+ }
+
+ public TAsyncClient getClient() {
+ return client;
+ }
+
+ public boolean hasTimeout() {
+ return timeout > 0;
+ }
+
+ public long getTimeoutTimestamp() {
+ return timeout + startTime;
+ }
+
+ protected abstract void write_args(TProtocol protocol) throws TException;
+
+ protected abstract T getResult() throws Exception;
+
+ /**
+ * Initialize buffers.
+ * @throws TException if buffer initialization fails
+ */
+ protected void prepareMethodCall() throws TException {
+ TMemoryBuffer memoryBuffer = new TMemoryBuffer(INITIAL_MEMORY_BUFFER_SIZE);
+ TProtocol protocol = protocolFactory.getProtocol(memoryBuffer);
+ write_args(protocol);
+
+ int length = memoryBuffer.length();
+ frameBuffer = ByteBuffer.wrap(memoryBuffer.getArray(), 0, length);
+
+ TFramedTransport.encodeFrameSize(length, sizeBufferArray);
+ sizeBuffer = ByteBuffer.wrap(sizeBufferArray);
+ }
+
+ /**
+ * Register with selector and start first state, which could be either connecting or writing.
+ * @throws IOException if register or starting fails
+ */
+ void start(Selector sel) throws IOException {
+ SelectionKey key;
+ if (transport.isOpen()) {
+ state = State.WRITING_REQUEST_SIZE;
+ key = transport.registerSelector(sel, SelectionKey.OP_WRITE);
+ } else {
+ state = State.CONNECTING;
+ key = transport.registerSelector(sel, SelectionKey.OP_CONNECT);
+
+ // non-blocking connect can complete immediately,
+ // in which case we should not expect the OP_CONNECT
+ if (transport.startConnect()) {
+ registerForFirstWrite(key);
+ }
+ }
+
+ key.attach(this);
+ }
+
+ void registerForFirstWrite(SelectionKey key) throws IOException {
+ state = State.WRITING_REQUEST_SIZE;
+ key.interestOps(SelectionKey.OP_WRITE);
+ }
+
+ protected ByteBuffer getFrameBuffer() {
+ return frameBuffer;
+ }
+
+ /**
+ * Transition to next state, doing whatever work is required. Since this
+ * method is only called by the selector thread, we can make changes to our
+ * select interests without worrying about concurrency.
+ * @param key
+ */
+ void transition(SelectionKey key) {
+ // Ensure key is valid
+ if (!key.isValid()) {
+ key.cancel();
+ Exception e = new TTransportException("Selection key not valid!");
+ onError(e);
+ return;
+ }
+
+ // Transition function
+ try {
+ switch (state) {
+ case CONNECTING:
+ doConnecting(key);
+ break;
+ case WRITING_REQUEST_SIZE:
+ doWritingRequestSize();
+ break;
+ case WRITING_REQUEST_BODY:
+ doWritingRequestBody(key);
+ break;
+ case READING_RESPONSE_SIZE:
+ doReadingResponseSize();
+ break;
+ case READING_RESPONSE_BODY:
+ doReadingResponseBody(key);
+ break;
+ default: // RESPONSE_READ, ERROR, or bug
+ throw new IllegalStateException("Method call in state " + state
+ + " but selector called transition method. Seems like a bug...");
+ }
+ } catch (Exception e) {
+ key.cancel();
+ key.attach(null);
+ onError(e);
+ }
+ }
+
+ protected void onError(Exception e) {
+ client.onError(e);
+ callback.onError(e);
+ state = State.ERROR;
+ }
+
+ private void doReadingResponseBody(SelectionKey key) throws IOException {
+ if (transport.read(frameBuffer) < 0) {
+ throw new IOException("Read call frame failed");
+ }
+ if (frameBuffer.remaining() == 0) {
+ cleanUpAndFireCallback(key);
+ }
+ }
+
+ private void cleanUpAndFireCallback(SelectionKey key) {
+ state = State.RESPONSE_READ;
+ key.interestOps(0);
+ // this ensures that the TAsyncMethod instance doesn't hang around
+ key.attach(null);
+ try {
+ T result = this.getResult();
+ client.onComplete();
+ callback.onComplete(result);
+ } catch (Exception e) {
+ key.cancel();
+ onError(e);
+ }
+ }
+
+ private void doReadingResponseSize() throws IOException {
+ if (transport.read(sizeBuffer) < 0) {
+ throw new IOException("Read call frame size failed");
+ }
+ if (sizeBuffer.remaining() == 0) {
+ state = State.READING_RESPONSE_BODY;
+ frameBuffer = ByteBuffer.allocate(TFramedTransport.decodeFrameSize(sizeBufferArray));
+ }
+ }
+
+ private void doWritingRequestBody(SelectionKey key) throws IOException {
+ if (transport.write(frameBuffer) < 0) {
+ throw new IOException("Write call frame failed");
+ }
+ if (frameBuffer.remaining() == 0) {
+ if (isOneway) {
+ cleanUpAndFireCallback(key);
+ } else {
+ state = State.READING_RESPONSE_SIZE;
+ sizeBuffer.rewind(); // Prepare to read incoming frame size
+ key.interestOps(SelectionKey.OP_READ);
+ }
+ }
+ }
+
+ private void doWritingRequestSize() throws IOException {
+ if (transport.write(sizeBuffer) < 0) {
+ throw new IOException("Write call frame size failed");
+ }
+ if (sizeBuffer.remaining() == 0) {
+ state = State.WRITING_REQUEST_BODY;
+ }
+ }
+
+ private void doConnecting(SelectionKey key) throws IOException {
+ if (!key.isConnectable() || !transport.finishConnect()) {
+ throw new IOException("not connectable or finishConnect returned false after we got an OP_CONNECT");
+ }
+ registerForFirstWrite(key);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/EnumMetaData.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/EnumMetaData.java
new file mode 100644
index 000000000..be49cb949
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/EnumMetaData.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.thrift.meta_data;
+
+import org.apache.thrift.TEnum;
+
+public class EnumMetaData extends FieldValueMetaData {
+ public final Class<? extends TEnum> enumClass;
+
+ public EnumMetaData(byte type, Class<? extends TEnum> sClass){
+ super(type);
+ this.enumClass = sClass;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java
new file mode 100644
index 000000000..445f7e474
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java
@@ -0,0 +1,70 @@
+/*
+ * 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.thrift.meta_data;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.thrift.TBase;
+import org.apache.thrift.TFieldIdEnum;
+
+/**
+ * This class is used to store meta data about thrift fields. Every field in a
+ * a struct should have a corresponding instance of this class describing it.
+ *
+ */
+public class FieldMetaData implements java.io.Serializable {
+ public final String fieldName;
+ public final byte requirementType;
+ public final FieldValueMetaData valueMetaData;
+ private static Map<Class<? extends TBase>, Map<? extends TFieldIdEnum, FieldMetaData>> structMap;
+
+ static {
+ structMap = new HashMap<Class<? extends TBase>, Map<? extends TFieldIdEnum, FieldMetaData>>();
+ }
+
+ public FieldMetaData(String name, byte req, FieldValueMetaData vMetaData){
+ this.fieldName = name;
+ this.requirementType = req;
+ this.valueMetaData = vMetaData;
+ }
+
+ public static synchronized void addStructMetaDataMap(Class<? extends TBase> sClass, Map<? extends TFieldIdEnum, FieldMetaData> map){
+ structMap.put(sClass, map);
+ }
+
+ /**
+ * Returns a map with metadata (i.e. instances of FieldMetaData) that
+ * describe the fields of the given class.
+ *
+ * @param sClass The TBase class for which the metadata map is requested
+ */
+ public static synchronized Map<? extends TFieldIdEnum, FieldMetaData> getStructMetaDataMap(Class<? extends TBase> sClass){
+ if (!structMap.containsKey(sClass)){ // Load class if it hasn't been loaded
+ try{
+ sClass.newInstance();
+ } catch (InstantiationException e){
+ throw new RuntimeException("InstantiationException for TBase class: " + sClass.getName() + ", message: " + e.getMessage());
+ } catch (IllegalAccessException e){
+ throw new RuntimeException("IllegalAccessException for TBase class: " + sClass.getName() + ", message: " + e.getMessage());
+ }
+ }
+ return structMap.get(sClass);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldValueMetaData.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldValueMetaData.java
new file mode 100644
index 000000000..2180b089b
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/FieldValueMetaData.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.thrift.meta_data;
+
+import org.apache.thrift.protocol.TType;
+
+/**
+ * FieldValueMetaData and collection of subclasses to store metadata about
+ * the value(s) of a field
+ */
+public class FieldValueMetaData implements java.io.Serializable {
+ public final byte type;
+
+ private final boolean isTypedefType;
+ private final String typedefName;
+ private final boolean isBinary;
+
+ public FieldValueMetaData(byte type, boolean binary) {
+ this.type = type;
+ this.isTypedefType = false;
+ this.typedefName = null;
+ this.isBinary = binary;
+ }
+
+ public FieldValueMetaData(byte type) {
+ this(type, false);
+ }
+
+ public FieldValueMetaData(byte type, String typedefName) {
+ this.type = type;
+ this.isTypedefType = true;
+ this.typedefName = typedefName;
+ this.isBinary = false;
+ }
+
+ public boolean isTypedef() {
+ return isTypedefType;
+ }
+
+ public String getTypedefName() {
+ return typedefName;
+ }
+
+ public boolean isStruct() {
+ return type == TType.STRUCT;
+ }
+
+ public boolean isContainer() {
+ return type == TType.LIST || type == TType.MAP || type == TType.SET;
+ }
+
+ public boolean isBinary() {
+ return isBinary;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/ListMetaData.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/ListMetaData.java
new file mode 100644
index 000000000..8e7073bf5
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/ListMetaData.java
@@ -0,0 +1,29 @@
+/*
+ * 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.thrift.meta_data;
+
+public class ListMetaData extends FieldValueMetaData {
+ public final FieldValueMetaData elemMetaData;
+
+ public ListMetaData(byte type, FieldValueMetaData eMetaData){
+ super(type);
+ this.elemMetaData = eMetaData;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/MapMetaData.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/MapMetaData.java
new file mode 100644
index 000000000..e7c408c78
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/MapMetaData.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.thrift.meta_data;
+
+public class MapMetaData extends FieldValueMetaData {
+ public final FieldValueMetaData keyMetaData;
+ public final FieldValueMetaData valueMetaData;
+
+ public MapMetaData(byte type, FieldValueMetaData kMetaData, FieldValueMetaData vMetaData){
+ super(type);
+ this.keyMetaData = kMetaData;
+ this.valueMetaData = vMetaData;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/SetMetaData.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/SetMetaData.java
new file mode 100644
index 000000000..cf4b96aab
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/SetMetaData.java
@@ -0,0 +1,29 @@
+/*
+ * 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.thrift.meta_data;
+
+public class SetMetaData extends FieldValueMetaData {
+ public final FieldValueMetaData elemMetaData;
+
+ public SetMetaData(byte type, FieldValueMetaData eMetaData){
+ super(type);
+ this.elemMetaData = eMetaData;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/StructMetaData.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/StructMetaData.java
new file mode 100644
index 000000000..b37d21dab
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/meta_data/StructMetaData.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.thrift.meta_data;
+
+import org.apache.thrift.TBase;
+
+public class StructMetaData extends FieldValueMetaData {
+ public final Class<? extends TBase> structClass;
+
+ public StructMetaData(byte type, Class<? extends TBase> sClass){
+ super(type);
+ this.structClass = sClass;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/ShortStack.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/ShortStack.java
new file mode 100644
index 000000000..9e6593074
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/ShortStack.java
@@ -0,0 +1,77 @@
+/*
+ * 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.thrift.protocol;
+
+import java.util.Arrays;
+
+/**
+ * ShortStack is a short-specific Stack implementation written for the express
+ * purpose of very fast operations on TCompactProtocol's field id stack. This
+ * implementation performs at least 10x faster than java.util.Stack.
+ */
+class ShortStack {
+
+ private short[] vector;
+
+ /** Always points to the next location */
+ private int top = 0;
+
+ public ShortStack(int initialCapacity) {
+ vector = new short[initialCapacity];
+ }
+
+ public short pop() {
+ return vector[--top];
+ }
+
+ public void push(short pushed) {
+ if (vector.length == top) {
+ grow();
+ }
+ vector[top++] = pushed;
+ }
+
+ private void grow() {
+ vector = Arrays.copyOf(vector, vector.length << 1);
+ }
+
+ public void clear() {
+ top = 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<ShortStack vector:[");
+ for (int i = 0; i < vector.length; i++) {
+ boolean isTop = (i == (top - 1));
+ short value = vector[i];
+ if (i != 0) {
+ sb.append(' ');
+ }
+ if (isTop) {
+ sb.append(">>").append(value).append("<<");
+ } else {
+ sb.append(value);
+ }
+ }
+ sb.append("]>");
+ return sb.toString();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBase64Utils.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBase64Utils.java
new file mode 100644
index 000000000..abfc965b7
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBase64Utils.java
@@ -0,0 +1,127 @@
+/*
+ * 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.thrift.protocol;
+
+/**
+ * Class for encoding and decoding Base64 data.
+ *
+ * This class is kept at package level because the interface does no input
+ * validation and is therefore too low-level for generalized reuse.
+ *
+ * Note also that the encoding does not pad with equal signs , as discussed in
+ * section 2.2 of the RFC (http://www.faqs.org/rfcs/rfc3548.html). Furthermore,
+ * bad data encountered when decoding is neither rejected or ignored but simply
+ * results in bad decoded data -- this is not in compliance with the RFC but is
+ * done in the interest of performance.
+ *
+ */
+class TBase64Utils {
+
+ private static final String ENCODE_TABLE =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ /**
+ * Encode len bytes of data in src at offset srcOff, storing the result into
+ * dst at offset dstOff. len must be 1, 2, or 3. dst must have at least len+1
+ * bytes of space at dstOff. src and dst should not be the same object. This
+ * method does no validation of the input values in the interest of
+ * performance.
+ *
+ * @param src the source of bytes to encode
+ * @param srcOff the offset into the source to read the unencoded bytes
+ * @param len the number of bytes to encode (must be 1, 2, or 3).
+ * @param dst the destination for the encoding
+ * @param dstOff the offset into the destination to place the encoded bytes
+ */
+ static final void encode(byte[] src, int srcOff, int len, byte[] dst,
+ int dstOff) {
+ dst[dstOff] = (byte)ENCODE_TABLE.charAt((src[srcOff] >> 2) & 0x3F);
+ if (len == 3) {
+ dst[dstOff + 1] =
+ (byte)ENCODE_TABLE.charAt(
+ ((src[srcOff] << 4) & 0x30) | ((src[srcOff+1] >> 4) & 0x0F));
+ dst[dstOff + 2] =
+ (byte)ENCODE_TABLE.charAt(
+ ((src[srcOff+1] << 2) & 0x3C) | ((src[srcOff+2] >> 6) & 0x03));
+ dst[dstOff + 3] =
+ (byte)ENCODE_TABLE.charAt(src[srcOff+2] & 0x3F);
+ }
+ else if (len == 2) {
+ dst[dstOff+1] =
+ (byte)ENCODE_TABLE.charAt(
+ ((src[srcOff] << 4) & 0x30) | ((src[srcOff+1] >> 4) & 0x0F));
+ dst[dstOff + 2] =
+ (byte)ENCODE_TABLE.charAt((src[srcOff+1] << 2) & 0x3C);
+ }
+ else { // len == 1) {
+ dst[dstOff + 1] =
+ (byte)ENCODE_TABLE.charAt((src[srcOff] << 4) & 0x30);
+ }
+ }
+
+ private static final byte[] DECODE_TABLE = {
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
+ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
+ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
+ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ };
+
+ /**
+ * Decode len bytes of data in src at offset srcOff, storing the result into
+ * dst at offset dstOff. len must be 2, 3, or 4. dst must have at least len-1
+ * bytes of space at dstOff. src and dst may be the same object as long as
+ * dstoff <= srcOff. This method does no validation of the input values in
+ * the interest of performance.
+ *
+ * @param src the source of bytes to decode
+ * @param srcOff the offset into the source to read the encoded bytes
+ * @param len the number of bytes to decode (must be 2, 3, or 4)
+ * @param dst the destination for the decoding
+ * @param dstOff the offset into the destination to place the decoded bytes
+ */
+ static final void decode(byte[] src, int srcOff, int len, byte[] dst,
+ int dstOff) {
+ dst[dstOff] = (byte)
+ ((DECODE_TABLE[src[srcOff] & 0x0FF] << 2) |
+ (DECODE_TABLE[src[srcOff+1] & 0x0FF] >> 4));
+ if (len > 2) {
+ dst[dstOff+1] = (byte)
+ (((DECODE_TABLE[src[srcOff+1] & 0x0FF] << 4) & 0xF0) |
+ (DECODE_TABLE[src[srcOff+2] & 0x0FF] >> 2));
+ if (len > 3) {
+ dst[dstOff+2] = (byte)
+ (((DECODE_TABLE[src[srcOff+2] & 0x0FF] << 6) & 0xC0) |
+ DECODE_TABLE[src[srcOff+3] & 0x0FF]);
+ }
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java
new file mode 100644
index 000000000..7924e2fe6
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java
@@ -0,0 +1,457 @@
+/*
+ * 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.thrift.protocol;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * Binary protocol implementation for thrift.
+ *
+ */
+public class TBinaryProtocol extends TProtocol {
+ private static final TStruct ANONYMOUS_STRUCT = new TStruct();
+ private static final long NO_LENGTH_LIMIT = -1;
+
+ protected static final int VERSION_MASK = 0xffff0000;
+ protected static final int VERSION_1 = 0x80010000;
+
+ /**
+ * The maximum number of bytes to read from the transport for
+ * variable-length fields (such as strings or binary) or {@link #NO_LENGTH_LIMIT} for
+ * unlimited.
+ */
+ private final long stringLengthLimit_;
+
+ /**
+ * The maximum number of elements to read from the network for
+ * containers (maps, sets, lists), or {@link #NO_LENGTH_LIMIT} for unlimited.
+ */
+ private final long containerLengthLimit_;
+
+ protected boolean strictRead_;
+ protected boolean strictWrite_;
+
+ private final byte[] inoutTemp = new byte[8];
+
+ /**
+ * Factory
+ */
+ public static class Factory implements TProtocolFactory {
+ protected long stringLengthLimit_;
+ protected long containerLengthLimit_;
+ protected boolean strictRead_;
+ protected boolean strictWrite_;
+
+ public Factory() {
+ this(false, true);
+ }
+
+ public Factory(boolean strictRead, boolean strictWrite) {
+ this(strictRead, strictWrite, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
+ }
+
+ public Factory(long stringLengthLimit, long containerLengthLimit) {
+ this(false, true, stringLengthLimit, containerLengthLimit);
+ }
+
+ public Factory(boolean strictRead, boolean strictWrite, long stringLengthLimit, long containerLengthLimit) {
+ stringLengthLimit_ = stringLengthLimit;
+ containerLengthLimit_ = containerLengthLimit;
+ strictRead_ = strictRead;
+ strictWrite_ = strictWrite;
+ }
+
+ public TProtocol getProtocol(TTransport trans) {
+ return new TBinaryProtocol(trans, stringLengthLimit_, containerLengthLimit_, strictRead_, strictWrite_);
+ }
+ }
+
+ /**
+ * Constructor
+ */
+ public TBinaryProtocol(TTransport trans) {
+ this(trans, false, true);
+ }
+
+ public TBinaryProtocol(TTransport trans, boolean strictRead, boolean strictWrite) {
+ this(trans, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT, strictRead, strictWrite);
+ }
+
+ public TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit) {
+ this(trans, stringLengthLimit, containerLengthLimit, false, true);
+ }
+
+ public TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit, boolean strictRead, boolean strictWrite) {
+ super(trans);
+ stringLengthLimit_ = stringLengthLimit;
+ containerLengthLimit_ = containerLengthLimit;
+ strictRead_ = strictRead;
+ strictWrite_ = strictWrite;
+ }
+
+ @Override
+ public void writeMessageBegin(TMessage message) throws TException {
+ if (strictWrite_) {
+ int version = VERSION_1 | message.type;
+ writeI32(version);
+ writeString(message.name);
+ writeI32(message.seqid);
+ } else {
+ writeString(message.name);
+ writeByte(message.type);
+ writeI32(message.seqid);
+ }
+ }
+
+ @Override
+ public void writeMessageEnd() throws TException {}
+
+ @Override
+ public void writeStructBegin(TStruct struct) throws TException {}
+
+ @Override
+ public void writeStructEnd() throws TException {}
+
+ @Override
+ public void writeFieldBegin(TField field) throws TException {
+ writeByte(field.type);
+ writeI16(field.id);
+ }
+
+ @Override
+ public void writeFieldEnd() throws TException {}
+
+ @Override
+ public void writeFieldStop() throws TException {
+ writeByte(TType.STOP);
+ }
+
+ @Override
+ public void writeMapBegin(TMap map) throws TException {
+ writeByte(map.keyType);
+ writeByte(map.valueType);
+ writeI32(map.size);
+ }
+
+ @Override
+ public void writeMapEnd() throws TException {}
+
+ @Override
+ public void writeListBegin(TList list) throws TException {
+ writeByte(list.elemType);
+ writeI32(list.size);
+ }
+
+ @Override
+ public void writeListEnd() throws TException {}
+
+ @Override
+ public void writeSetBegin(TSet set) throws TException {
+ writeByte(set.elemType);
+ writeI32(set.size);
+ }
+
+ @Override
+ public void writeSetEnd() throws TException {}
+
+ @Override
+ public void writeBool(boolean b) throws TException {
+ writeByte(b ? (byte)1 : (byte)0);
+ }
+
+ @Override
+ public void writeByte(byte b) throws TException {
+ inoutTemp[0] = b;
+ trans_.write(inoutTemp, 0, 1);
+ }
+
+ @Override
+ public void writeI16(short i16) throws TException {
+ inoutTemp[0] = (byte)(0xff & (i16 >> 8));
+ inoutTemp[1] = (byte)(0xff & (i16));
+ trans_.write(inoutTemp, 0, 2);
+ }
+
+ @Override
+ public void writeI32(int i32) throws TException {
+ inoutTemp[0] = (byte)(0xff & (i32 >> 24));
+ inoutTemp[1] = (byte)(0xff & (i32 >> 16));
+ inoutTemp[2] = (byte)(0xff & (i32 >> 8));
+ inoutTemp[3] = (byte)(0xff & (i32));
+ trans_.write(inoutTemp, 0, 4);
+ }
+
+ @Override
+ public void writeI64(long i64) throws TException {
+ inoutTemp[0] = (byte)(0xff & (i64 >> 56));
+ inoutTemp[1] = (byte)(0xff & (i64 >> 48));
+ inoutTemp[2] = (byte)(0xff & (i64 >> 40));
+ inoutTemp[3] = (byte)(0xff & (i64 >> 32));
+ inoutTemp[4] = (byte)(0xff & (i64 >> 24));
+ inoutTemp[5] = (byte)(0xff & (i64 >> 16));
+ inoutTemp[6] = (byte)(0xff & (i64 >> 8));
+ inoutTemp[7] = (byte)(0xff & (i64));
+ trans_.write(inoutTemp, 0, 8);
+ }
+
+ @Override
+ public void writeDouble(double dub) throws TException {
+ writeI64(Double.doubleToLongBits(dub));
+ }
+
+ @Override
+ public void writeString(String str) throws TException {
+ byte[] dat = str.getBytes(StandardCharsets.UTF_8);
+ writeI32(dat.length);
+ trans_.write(dat, 0, dat.length);
+ }
+
+ @Override
+ public void writeBinary(ByteBuffer bin) throws TException {
+ int length = bin.limit() - bin.position();
+ writeI32(length);
+ trans_.write(bin.array(), bin.position() + bin.arrayOffset(), length);
+ }
+
+ /**
+ * Reading methods.
+ */
+
+ @Override
+ public TMessage readMessageBegin() throws TException {
+ int size = readI32();
+ if (size < 0) {
+ int version = size & VERSION_MASK;
+ if (version != VERSION_1) {
+ throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in readMessageBegin");
+ }
+ return new TMessage(readString(), (byte)(size & 0x000000ff), readI32());
+ } else {
+ if (strictRead_) {
+ throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
+ }
+ return new TMessage(readStringBody(size), readByte(), readI32());
+ }
+ }
+
+ @Override
+ public void readMessageEnd() throws TException {}
+
+ @Override
+ public TStruct readStructBegin() throws TException {
+ return ANONYMOUS_STRUCT;
+ }
+
+ @Override
+ public void readStructEnd() throws TException {}
+
+ @Override
+ public TField readFieldBegin() throws TException {
+ byte type = readByte();
+ short id = type == TType.STOP ? 0 : readI16();
+ return new TField("", type, id);
+ }
+
+ @Override
+ public void readFieldEnd() throws TException {}
+
+ @Override
+ public TMap readMapBegin() throws TException {
+ TMap map = new TMap(readByte(), readByte(), readI32());
+ checkContainerReadLength(map.size);
+ return map;
+ }
+
+ @Override
+ public void readMapEnd() throws TException {}
+
+ @Override
+ public TList readListBegin() throws TException {
+ TList list = new TList(readByte(), readI32());
+ checkContainerReadLength(list.size);
+ return list;
+ }
+
+ @Override
+ public void readListEnd() throws TException {}
+
+ @Override
+ public TSet readSetBegin() throws TException {
+ TSet set = new TSet(readByte(), readI32());
+ checkContainerReadLength(set.size);
+ return set;
+ }
+
+ @Override
+ public void readSetEnd() throws TException {}
+
+ @Override
+ public boolean readBool() throws TException {
+ return (readByte() == 1);
+ }
+
+ @Override
+ public byte readByte() throws TException {
+ if (trans_.getBytesRemainingInBuffer() >= 1) {
+ byte b = trans_.getBuffer()[trans_.getBufferPosition()];
+ trans_.consumeBuffer(1);
+ return b;
+ }
+ readAll(inoutTemp, 0, 1);
+ return inoutTemp[0];
+ }
+
+ @Override
+ public short readI16() throws TException {
+ byte[] buf = inoutTemp;
+ int off = 0;
+
+ if (trans_.getBytesRemainingInBuffer() >= 2) {
+ buf = trans_.getBuffer();
+ off = trans_.getBufferPosition();
+ trans_.consumeBuffer(2);
+ } else {
+ readAll(inoutTemp, 0, 2);
+ }
+
+ return
+ (short)
+ (((buf[off] & 0xff) << 8) |
+ ((buf[off+1] & 0xff)));
+ }
+
+ @Override
+ public int readI32() throws TException {
+ byte[] buf = inoutTemp;
+ int off = 0;
+
+ if (trans_.getBytesRemainingInBuffer() >= 4) {
+ buf = trans_.getBuffer();
+ off = trans_.getBufferPosition();
+ trans_.consumeBuffer(4);
+ } else {
+ readAll(inoutTemp, 0, 4);
+ }
+ return
+ ((buf[off] & 0xff) << 24) |
+ ((buf[off+1] & 0xff) << 16) |
+ ((buf[off+2] & 0xff) << 8) |
+ ((buf[off+3] & 0xff));
+ }
+
+ @Override
+ public long readI64() throws TException {
+ byte[] buf = inoutTemp;
+ int off = 0;
+
+ if (trans_.getBytesRemainingInBuffer() >= 8) {
+ buf = trans_.getBuffer();
+ off = trans_.getBufferPosition();
+ trans_.consumeBuffer(8);
+ } else {
+ readAll(inoutTemp, 0, 8);
+ }
+
+ return
+ ((long)(buf[off] & 0xff) << 56) |
+ ((long)(buf[off+1] & 0xff) << 48) |
+ ((long)(buf[off+2] & 0xff) << 40) |
+ ((long)(buf[off+3] & 0xff) << 32) |
+ ((long)(buf[off+4] & 0xff) << 24) |
+ ((long)(buf[off+5] & 0xff) << 16) |
+ ((long)(buf[off+6] & 0xff) << 8) |
+ ((long)(buf[off+7] & 0xff));
+ }
+
+ @Override
+ public double readDouble() throws TException {
+ return Double.longBitsToDouble(readI64());
+ }
+
+ @Override
+ public String readString() throws TException {
+ int size = readI32();
+
+ checkStringReadLength(size);
+
+ if (trans_.getBytesRemainingInBuffer() >= size) {
+ String s = new String(trans_.getBuffer(), trans_.getBufferPosition(),
+ size, StandardCharsets.UTF_8);
+ trans_.consumeBuffer(size);
+ return s;
+ }
+
+ return readStringBody(size);
+ }
+
+ public String readStringBody(int size) throws TException {
+ checkStringReadLength(size);
+ byte[] buf = new byte[size];
+ trans_.readAll(buf, 0, size);
+ return new String(buf, StandardCharsets.UTF_8);
+ }
+
+ @Override
+ public ByteBuffer readBinary() throws TException {
+ int size = readI32();
+
+ checkStringReadLength(size);
+
+ if (trans_.getBytesRemainingInBuffer() >= size) {
+ ByteBuffer bb = ByteBuffer.wrap(trans_.getBuffer(), trans_.getBufferPosition(), size);
+ trans_.consumeBuffer(size);
+ return bb;
+ }
+
+ byte[] buf = new byte[size];
+ trans_.readAll(buf, 0, size);
+ return ByteBuffer.wrap(buf);
+ }
+
+ private void checkStringReadLength(int length) throws TProtocolException {
+ if (length < 0) {
+ throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+ "Negative length: " + length);
+ }
+ if (stringLengthLimit_ != NO_LENGTH_LIMIT && length > stringLengthLimit_) {
+ throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+ "Length exceeded max allowed: " + length);
+ }
+ }
+
+ private void checkContainerReadLength(int length) throws TProtocolException {
+ if (length < 0) {
+ throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+ "Negative length: " + length);
+ }
+ if (containerLengthLimit_ != NO_LENGTH_LIMIT && length > containerLengthLimit_) {
+ throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+ "Length exceeded max allowed: " + length);
+ }
+ }
+
+ private int readAll(byte[] buf, int off, int len) throws TException {
+ return trans_.readAll(buf, off, len);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
new file mode 100644
index 000000000..ee0586945
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
@@ -0,0 +1,904 @@
+/*
+ * 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.thrift.protocol;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * TCompactProtocol2 is the Java implementation of the compact protocol specified
+ * in THRIFT-110. The fundamental approach to reducing the overhead of
+ * structures is a) use variable-length integers all over the place and b) make
+ * use of unused bits wherever possible. Your savings will obviously vary
+ * based on the specific makeup of your structs, but in general, the more
+ * fields, nested structures, short strings and collections, and low-value i32
+ * and i64 fields you have, the more benefit you'll see.
+ */
+public class TCompactProtocol extends TProtocol {
+ private final static byte[] EMPTY_BYTES = new byte[0];
+ private final static ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(EMPTY_BYTES);
+
+ private final static long NO_LENGTH_LIMIT = -1;
+
+ private final static TStruct ANONYMOUS_STRUCT = new TStruct("");
+ private final static TField TSTOP = new TField("", TType.STOP, (short)0);
+
+ private final static byte[] ttypeToCompactType = new byte[16];
+
+ static {
+ ttypeToCompactType[TType.STOP] = TType.STOP;
+ ttypeToCompactType[TType.BOOL] = Types.BOOLEAN_TRUE;
+ ttypeToCompactType[TType.BYTE] = Types.BYTE;
+ ttypeToCompactType[TType.I16] = Types.I16;
+ ttypeToCompactType[TType.I32] = Types.I32;
+ ttypeToCompactType[TType.I64] = Types.I64;
+ ttypeToCompactType[TType.DOUBLE] = Types.DOUBLE;
+ ttypeToCompactType[TType.STRING] = Types.BINARY;
+ ttypeToCompactType[TType.LIST] = Types.LIST;
+ ttypeToCompactType[TType.SET] = Types.SET;
+ ttypeToCompactType[TType.MAP] = Types.MAP;
+ ttypeToCompactType[TType.STRUCT] = Types.STRUCT;
+ }
+
+ /**
+ * TProtocolFactory that produces TCompactProtocols.
+ */
+ public static class Factory implements TProtocolFactory {
+ private final long stringLengthLimit_;
+ private final long containerLengthLimit_;
+
+ public Factory() {
+ this(NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
+ }
+
+ public Factory(long stringLengthLimit) {
+ this(stringLengthLimit, NO_LENGTH_LIMIT);
+ }
+
+ public Factory(long stringLengthLimit, long containerLengthLimit) {
+ this.containerLengthLimit_ = containerLengthLimit;
+ this.stringLengthLimit_ = stringLengthLimit;
+ }
+
+ public TProtocol getProtocol(TTransport trans) {
+ return new TCompactProtocol(trans, stringLengthLimit_, containerLengthLimit_);
+ }
+ }
+
+ private static final byte PROTOCOL_ID = (byte)0x82;
+ private static final byte VERSION = 1;
+ private static final byte VERSION_MASK = 0x1f; // 0001 1111
+ private static final byte TYPE_MASK = (byte)0xE0; // 1110 0000
+ private static final byte TYPE_BITS = 0x07; // 0000 0111
+ private static final int TYPE_SHIFT_AMOUNT = 5;
+
+ /**
+ * All of the on-wire type codes.
+ */
+ private static class Types {
+ public static final byte BOOLEAN_TRUE = 0x01;
+ public static final byte BOOLEAN_FALSE = 0x02;
+ public static final byte BYTE = 0x03;
+ public static final byte I16 = 0x04;
+ public static final byte I32 = 0x05;
+ public static final byte I64 = 0x06;
+ public static final byte DOUBLE = 0x07;
+ public static final byte BINARY = 0x08;
+ public static final byte LIST = 0x09;
+ public static final byte SET = 0x0A;
+ public static final byte MAP = 0x0B;
+ public static final byte STRUCT = 0x0C;
+ }
+
+ /**
+ * Used to keep track of the last field for the current and previous structs,
+ * so we can do the delta stuff.
+ */
+ private ShortStack lastField_ = new ShortStack(15);
+
+ private short lastFieldId_ = 0;
+
+ /**
+ * If we encounter a boolean field begin, save the TField here so it can
+ * have the value incorporated.
+ */
+ private TField booleanField_ = null;
+
+ /**
+ * If we read a field header, and it's a boolean field, save the boolean
+ * value here so that readBool can use it.
+ */
+ private Boolean boolValue_ = null;
+
+ /**
+ * The maximum number of bytes to read from the transport for
+ * variable-length fields (such as strings or binary) or {@link #NO_LENGTH_LIMIT} for
+ * unlimited.
+ */
+ private final long stringLengthLimit_;
+
+ /**
+ * The maximum number of elements to read from the network for
+ * containers (maps, sets, lists), or {@link #NO_LENGTH_LIMIT} for unlimited.
+ */
+ private final long containerLengthLimit_;
+
+ /**
+ * Temporary buffer used for various operations that would otherwise require a
+ * small allocation.
+ */
+ private final byte[] temp = new byte[10];
+
+ /**
+ * Create a TCompactProtocol.
+ *
+ * @param transport the TTransport object to read from or write to.
+ * @param stringLengthLimit the maximum number of bytes to read for
+ * variable-length fields.
+ * @param containerLengthLimit the maximum number of elements to read
+ * for containers.
+ */
+ public TCompactProtocol(TTransport transport, long stringLengthLimit, long containerLengthLimit) {
+ super(transport);
+ this.stringLengthLimit_ = stringLengthLimit;
+ this.containerLengthLimit_ = containerLengthLimit;
+ }
+
+ /**
+ * Create a TCompactProtocol.
+ *
+ * @param transport the TTransport object to read from or write to.
+ * @param stringLengthLimit the maximum number of bytes to read for
+ * variable-length fields.
+ * @deprecated Use constructor specifying both string limit and container limit instead
+ */
+ @Deprecated
+ public TCompactProtocol(TTransport transport, long stringLengthLimit) {
+ this(transport, stringLengthLimit, NO_LENGTH_LIMIT);
+ }
+
+ /**
+ * Create a TCompactProtocol.
+ *
+ * @param transport the TTransport object to read from or write to.
+ */
+ public TCompactProtocol(TTransport transport) {
+ this(transport, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
+ }
+
+ @Override
+ public void reset() {
+ lastField_.clear();
+ lastFieldId_ = 0;
+ }
+
+ //
+ // Public Writing methods.
+ //
+
+ /**
+ * Write a message header to the wire. Compact Protocol messages contain the
+ * protocol version so we can migrate forwards in the future if need be.
+ */
+ @Override
+ public void writeMessageBegin(TMessage message) throws TException {
+ writeByteDirect(PROTOCOL_ID);
+ writeByteDirect((VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
+ writeVarint32(message.seqid);
+ writeString(message.name);
+ }
+
+ /**
+ * Write a struct begin. This doesn't actually put anything on the wire. We
+ * use it as an opportunity to put special placeholder markers on the field
+ * stack so we can get the field id deltas correct.
+ */
+ @Override
+ public void writeStructBegin(TStruct struct) throws TException {
+ lastField_.push(lastFieldId_);
+ lastFieldId_ = 0;
+ }
+
+ /**
+ * Write a struct end. This doesn't actually put anything on the wire. We use
+ * this as an opportunity to pop the last field from the current struct off
+ * of the field stack.
+ */
+ public void writeStructEnd() throws TException {
+ lastFieldId_ = lastField_.pop();
+ }
+
+ /**
+ * Write a field header containing the field id and field type. If the
+ * difference between the current field id and the last one is small (&lt; 15),
+ * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
+ * field id will follow the type header as a zigzag varint.
+ */
+ public void writeFieldBegin(TField field) throws TException {
+ if (field.type == TType.BOOL) {
+ // we want to possibly include the value, so we'll wait.
+ booleanField_ = field;
+ } else {
+ writeFieldBeginInternal(field, (byte)-1);
+ }
+ }
+
+ /**
+ * The workhorse of writeFieldBegin. It has the option of doing a
+ * 'type override' of the type header. This is used specifically in the
+ * boolean field case.
+ */
+ private void writeFieldBeginInternal(TField field, byte typeOverride) throws TException {
+ // short lastField = lastField_.pop();
+
+ // if there's a type override, use that.
+ byte typeToWrite = typeOverride == -1 ? getCompactType(field.type) : typeOverride;
+
+ // check if we can use delta encoding for the field id
+ if (field.id > lastFieldId_ && field.id - lastFieldId_ <= 15) {
+ // write them together
+ writeByteDirect((field.id - lastFieldId_) << 4 | typeToWrite);
+ } else {
+ // write them separate
+ writeByteDirect(typeToWrite);
+ writeI16(field.id);
+ }
+
+ lastFieldId_ = field.id;
+ // lastField_.push(field.id);
+ }
+
+ /**
+ * Write the STOP symbol so we know there are no more fields in this struct.
+ */
+ public void writeFieldStop() throws TException {
+ writeByteDirect(TType.STOP);
+ }
+
+ /**
+ * Write a map header. If the map is empty, omit the key and value type
+ * headers, as we don't need any additional information to skip it.
+ */
+ public void writeMapBegin(TMap map) throws TException {
+ if (map.size == 0) {
+ writeByteDirect(0);
+ } else {
+ writeVarint32(map.size);
+ writeByteDirect(getCompactType(map.keyType) << 4 | getCompactType(map.valueType));
+ }
+ }
+
+ /**
+ * Write a list header.
+ */
+ public void writeListBegin(TList list) throws TException {
+ writeCollectionBegin(list.elemType, list.size);
+ }
+
+ /**
+ * Write a set header.
+ */
+ public void writeSetBegin(TSet set) throws TException {
+ writeCollectionBegin(set.elemType, set.size);
+ }
+
+ /**
+ * Write a boolean value. Potentially, this could be a boolean field, in
+ * which case the field header info isn't written yet. If so, decide what the
+ * right type header is for the value and then write the field header.
+ * Otherwise, write a single byte.
+ */
+ public void writeBool(boolean b) throws TException {
+ if (booleanField_ != null) {
+ // we haven't written the field header yet
+ writeFieldBeginInternal(booleanField_, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
+ booleanField_ = null;
+ } else {
+ // we're not part of a field, so just write the value.
+ writeByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
+ }
+ }
+
+ /**
+ * Write a byte. Nothing to see here!
+ */
+ public void writeByte(byte b) throws TException {
+ writeByteDirect(b);
+ }
+
+ /**
+ * Write an I16 as a zigzag varint.
+ */
+ public void writeI16(short i16) throws TException {
+ writeVarint32(intToZigZag(i16));
+ }
+
+ /**
+ * Write an i32 as a zigzag varint.
+ */
+ public void writeI32(int i32) throws TException {
+ writeVarint32(intToZigZag(i32));
+ }
+
+ /**
+ * Write an i64 as a zigzag varint.
+ */
+ public void writeI64(long i64) throws TException {
+ writeVarint64(longToZigzag(i64));
+ }
+
+ /**
+ * Write a double to the wire as 8 bytes.
+ */
+ public void writeDouble(double dub) throws TException {
+ fixedLongToBytes(Double.doubleToLongBits(dub), temp, 0);
+ trans_.write(temp, 0, 8);
+ }
+
+ /**
+ * Write a string to the wire with a varint size preceding.
+ */
+ public void writeString(String str) throws TException {
+ byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+ writeBinary(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Write a byte array, using a varint for the size.
+ */
+ public void writeBinary(ByteBuffer bin) throws TException {
+ int length = bin.limit() - bin.position();
+ writeBinary(bin.array(), bin.position() + bin.arrayOffset(), length);
+ }
+
+ private void writeBinary(byte[] buf, int offset, int length) throws TException {
+ writeVarint32(length);
+ trans_.write(buf, offset, length);
+ }
+
+ //
+ // These methods are called by structs, but don't actually have any wire
+ // output or purpose.
+ //
+
+ public void writeMessageEnd() throws TException {}
+ public void writeMapEnd() throws TException {}
+ public void writeListEnd() throws TException {}
+ public void writeSetEnd() throws TException {}
+ public void writeFieldEnd() throws TException {}
+
+ //
+ // Internal writing methods
+ //
+
+ /**
+ * Abstract method for writing the start of lists and sets. List and sets on
+ * the wire differ only by the type indicator.
+ */
+ protected void writeCollectionBegin(byte elemType, int size) throws TException {
+ if (size <= 14) {
+ writeByteDirect(size << 4 | getCompactType(elemType));
+ } else {
+ writeByteDirect(0xf0 | getCompactType(elemType));
+ writeVarint32(size);
+ }
+ }
+
+ /**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ * TODO: make a permanent buffer like writeVarint64?
+ */
+ private void writeVarint32(int n) throws TException {
+ int idx = 0;
+ while (true) {
+ if ((n & ~0x7F) == 0) {
+ temp[idx++] = (byte)n;
+ // writeByteDirect((byte)n);
+ break;
+ // return;
+ } else {
+ temp[idx++] = (byte)((n & 0x7F) | 0x80);
+ // writeByteDirect((byte)((n & 0x7F) | 0x80));
+ n >>>= 7;
+ }
+ }
+ trans_.write(temp, 0, idx);
+ }
+
+ /**
+ * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ */
+ private void writeVarint64(long n) throws TException {
+ int idx = 0;
+ while (true) {
+ if ((n & ~0x7FL) == 0) {
+ temp[idx++] = (byte)n;
+ break;
+ } else {
+ temp[idx++] = ((byte)((n & 0x7F) | 0x80));
+ n >>>= 7;
+ }
+ }
+ trans_.write(temp, 0, idx);
+ }
+
+ /**
+ * Convert l into a zigzag long. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+ private long longToZigzag(long l) {
+ return (l << 1) ^ (l >> 63);
+ }
+
+ /**
+ * Convert n into a zigzag int. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+ private int intToZigZag(int n) {
+ return (n << 1) ^ (n >> 31);
+ }
+
+ /**
+ * Convert a long into little-endian bytes in buf starting at off and going
+ * until off+7.
+ */
+ private void fixedLongToBytes(long n, byte[] buf, int off) {
+ buf[off+0] = (byte)( n & 0xff);
+ buf[off+1] = (byte)((n >> 8 ) & 0xff);
+ buf[off+2] = (byte)((n >> 16) & 0xff);
+ buf[off+3] = (byte)((n >> 24) & 0xff);
+ buf[off+4] = (byte)((n >> 32) & 0xff);
+ buf[off+5] = (byte)((n >> 40) & 0xff);
+ buf[off+6] = (byte)((n >> 48) & 0xff);
+ buf[off+7] = (byte)((n >> 56) & 0xff);
+ }
+
+ /**
+ * Writes a byte without any possibility of all that field header nonsense.
+ * Used internally by other writing methods that know they need to write a byte.
+ */
+ private void writeByteDirect(byte b) throws TException {
+ temp[0] = b;
+ trans_.write(temp, 0, 1);
+ }
+
+ /**
+ * Writes a byte without any possibility of all that field header nonsense.
+ */
+ private void writeByteDirect(int n) throws TException {
+ writeByteDirect((byte)n);
+ }
+
+
+ //
+ // Reading methods.
+ //
+
+ /**
+ * Read a message header.
+ */
+ public TMessage readMessageBegin() throws TException {
+ byte protocolId = readByte();
+ if (protocolId != PROTOCOL_ID) {
+ throw new TProtocolException("Expected protocol id " + Integer.toHexString(PROTOCOL_ID) + " but got " + Integer.toHexString(protocolId));
+ }
+ byte versionAndType = readByte();
+ byte version = (byte)(versionAndType & VERSION_MASK);
+ if (version != VERSION) {
+ throw new TProtocolException("Expected version " + VERSION + " but got " + version);
+ }
+ byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+ int seqid = readVarint32();
+ String messageName = readString();
+ return new TMessage(messageName, type, seqid);
+ }
+
+ /**
+ * Read a struct begin. There's nothing on the wire for this, but it is our
+ * opportunity to push a new struct begin marker onto the field stack.
+ */
+ public TStruct readStructBegin() throws TException {
+ lastField_.push(lastFieldId_);
+ lastFieldId_ = 0;
+ return ANONYMOUS_STRUCT;
+ }
+
+ /**
+ * Doesn't actually consume any wire data, just removes the last field for
+ * this struct from the field stack.
+ */
+ public void readStructEnd() throws TException {
+ // consume the last field we read off the wire.
+ lastFieldId_ = lastField_.pop();
+ }
+
+ /**
+ * Read a field header off the wire.
+ */
+ public TField readFieldBegin() throws TException {
+ byte type = readByte();
+
+ // if it's a stop, then we can return immediately, as the struct is over.
+ if (type == TType.STOP) {
+ return TSTOP;
+ }
+
+ short fieldId;
+
+ // mask off the 4 MSB of the type header. it could contain a field id delta.
+ short modifier = (short)((type & 0xf0) >> 4);
+ if (modifier == 0) {
+ // not a delta. look ahead for the zigzag varint field id.
+ fieldId = readI16();
+ } else {
+ // has a delta. add the delta to the last read field id.
+ fieldId = (short)(lastFieldId_ + modifier);
+ }
+
+ TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);
+
+ // if this happens to be a boolean field, the value is encoded in the type
+ if (isBoolType(type)) {
+ // save the boolean value in a special instance variable.
+ boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ // push the new field onto the field stack so we can keep the deltas going.
+ lastFieldId_ = field.id;
+ return field;
+ }
+
+ /**
+ * Read a map header off the wire. If the size is zero, skip reading the key
+ * and value type. This means that 0-length maps will yield TMaps without the
+ * "correct" types.
+ */
+ public TMap readMapBegin() throws TException {
+ int size = readVarint32();
+ checkContainerReadLength(size);
+ byte keyAndValueType = size == 0 ? 0 : readByte();
+ return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);
+ }
+
+ /**
+ * Read a list header off the wire. If the list size is 0-14, the size will
+ * be packed into the element type header. If it's a longer list, the 4 MSB
+ * of the element type header will be 0xF, and a varint will follow with the
+ * true size.
+ */
+ public TList readListBegin() throws TException {
+ byte size_and_type = readByte();
+ int size = (size_and_type >> 4) & 0x0f;
+ if (size == 15) {
+ size = readVarint32();
+ }
+ checkContainerReadLength(size);
+ byte type = getTType(size_and_type);
+ return new TList(type, size);
+ }
+
+ /**
+ * Read a set header off the wire. If the set size is 0-14, the size will
+ * be packed into the element type header. If it's a longer set, the 4 MSB
+ * of the element type header will be 0xF, and a varint will follow with the
+ * true size.
+ */
+ public TSet readSetBegin() throws TException {
+ return new TSet(readListBegin());
+ }
+
+ /**
+ * Read a boolean off the wire. If this is a boolean field, the value should
+ * already have been read during readFieldBegin, so we'll just consume the
+ * pre-stored value. Otherwise, read a byte.
+ */
+ public boolean readBool() throws TException {
+ if (boolValue_ != null) {
+ boolean result = boolValue_.booleanValue();
+ boolValue_ = null;
+ return result;
+ }
+ return readByte() == Types.BOOLEAN_TRUE;
+ }
+
+ /**
+ * Read a single byte off the wire. Nothing interesting here.
+ */
+ public byte readByte() throws TException {
+ byte b;
+ if (trans_.getBytesRemainingInBuffer() > 0) {
+ b = trans_.getBuffer()[trans_.getBufferPosition()];
+ trans_.consumeBuffer(1);
+ } else {
+ trans_.readAll(temp, 0, 1);
+ b = temp[0];
+ }
+ return b;
+ }
+
+ /**
+ * Read an i16 from the wire as a zigzag varint.
+ */
+ public short readI16() throws TException {
+ return (short)zigzagToInt(readVarint32());
+ }
+
+ /**
+ * Read an i32 from the wire as a zigzag varint.
+ */
+ public int readI32() throws TException {
+ return zigzagToInt(readVarint32());
+ }
+
+ /**
+ * Read an i64 from the wire as a zigzag varint.
+ */
+ public long readI64() throws TException {
+ return zigzagToLong(readVarint64());
+ }
+
+ /**
+ * No magic here - just read a double off the wire.
+ */
+ public double readDouble() throws TException {
+ trans_.readAll(temp, 0, 8);
+ return Double.longBitsToDouble(bytesToLong(temp));
+ }
+
+ /**
+ * Reads a byte[] (via readBinary), and then UTF-8 decodes it.
+ */
+ public String readString() throws TException {
+ int length = readVarint32();
+ checkStringReadLength(length);
+
+ if (length == 0) {
+ return "";
+ }
+
+ final String str;
+ if (trans_.getBytesRemainingInBuffer() >= length) {
+ str = new String(trans_.getBuffer(), trans_.getBufferPosition(),
+ length, StandardCharsets.UTF_8);
+ trans_.consumeBuffer(length);
+ } else {
+ str = new String(readBinary(length), StandardCharsets.UTF_8);
+ }
+ return str;
+ }
+
+ /**
+ * Read a byte[] from the wire.
+ */
+ public ByteBuffer readBinary() throws TException {
+ int length = readVarint32();
+ checkStringReadLength(length);
+ if (length == 0) return EMPTY_BUFFER;
+
+ if (trans_.getBytesRemainingInBuffer() >= length) {
+ ByteBuffer bb = ByteBuffer.wrap(trans_.getBuffer(), trans_.getBufferPosition(), length);
+ trans_.consumeBuffer(length);
+ return bb;
+ }
+
+ byte[] buf = new byte[length];
+ trans_.readAll(buf, 0, length);
+ return ByteBuffer.wrap(buf);
+ }
+
+ /**
+ * Read a byte[] of a known length from the wire.
+ */
+ private byte[] readBinary(int length) throws TException {
+ if (length == 0) return EMPTY_BYTES;
+
+ byte[] buf = new byte[length];
+ trans_.readAll(buf, 0, length);
+ return buf;
+ }
+
+ private void checkStringReadLength(int length) throws TProtocolException {
+ if (length < 0) {
+ throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+ "Negative length: " + length);
+ }
+ if (stringLengthLimit_ != NO_LENGTH_LIMIT && length > stringLengthLimit_) {
+ throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+ "Length exceeded max allowed: " + length);
+ }
+ }
+
+ private void checkContainerReadLength(int length) throws TProtocolException {
+ if (length < 0) {
+ throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+ "Negative length: " + length);
+ }
+ if (containerLengthLimit_ != NO_LENGTH_LIMIT && length > containerLengthLimit_) {
+ throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+ "Length exceeded max allowed: " + length);
+ }
+ }
+
+ //
+ // These methods are here for the struct to call, but don't have any wire
+ // encoding.
+ //
+ public void readMessageEnd() throws TException {}
+ public void readFieldEnd() throws TException {}
+ public void readMapEnd() throws TException {}
+ public void readListEnd() throws TException {}
+ public void readSetEnd() throws TException {}
+
+ //
+ // Internal reading methods
+ //
+
+ /**
+ * Read an i32 from the wire as a varint. The MSB of each byte is set
+ * if there is another byte to follow. This can read up to 5 bytes.
+ */
+ private int readVarint32() throws TException {
+ int result = 0;
+ int shift = 0;
+ if (trans_.getBytesRemainingInBuffer() >= 5) {
+ byte[] buf = trans_.getBuffer();
+ int pos = trans_.getBufferPosition();
+ int off = 0;
+ while (true) {
+ byte b = buf[pos+off];
+ result |= (int) (b & 0x7f) << shift;
+ if ((b & 0x80) != 0x80) break;
+ shift += 7;
+ off++;
+ }
+ trans_.consumeBuffer(off+1);
+ } else {
+ while (true) {
+ byte b = readByte();
+ result |= (int) (b & 0x7f) << shift;
+ if ((b & 0x80) != 0x80) break;
+ shift += 7;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Read an i64 from the wire as a proper varint. The MSB of each byte is set
+ * if there is another byte to follow. This can read up to 10 bytes.
+ */
+ private long readVarint64() throws TException {
+ int shift = 0;
+ long result = 0;
+ if (trans_.getBytesRemainingInBuffer() >= 10) {
+ byte[] buf = trans_.getBuffer();
+ int pos = trans_.getBufferPosition();
+ int off = 0;
+ while (true) {
+ byte b = buf[pos+off];
+ result |= (long) (b & 0x7f) << shift;
+ if ((b & 0x80) != 0x80) break;
+ shift += 7;
+ off++;
+ }
+ trans_.consumeBuffer(off+1);
+ } else {
+ while (true) {
+ byte b = readByte();
+ result |= (long) (b & 0x7f) << shift;
+ if ((b & 0x80) != 0x80) break;
+ shift +=7;
+ }
+ }
+ return result;
+ }
+
+ //
+ // encoding helpers
+ //
+
+ /**
+ * Convert from zigzag int to int.
+ */
+ private int zigzagToInt(int n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ /**
+ * Convert from zigzag long to long.
+ */
+ private long zigzagToLong(long n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ /**
+ * Note that it's important that the mask bytes are long literals,
+ * otherwise they'll default to ints, and when you shift an int left 56 bits,
+ * you just get a messed up int.
+ */
+ private long bytesToLong(byte[] bytes) {
+ return
+ ((bytes[7] & 0xffL) << 56) |
+ ((bytes[6] & 0xffL) << 48) |
+ ((bytes[5] & 0xffL) << 40) |
+ ((bytes[4] & 0xffL) << 32) |
+ ((bytes[3] & 0xffL) << 24) |
+ ((bytes[2] & 0xffL) << 16) |
+ ((bytes[1] & 0xffL) << 8) |
+ ((bytes[0] & 0xffL));
+ }
+
+ //
+ // type testing and converting
+ //
+
+ private boolean isBoolType(byte b) {
+ int lowerNibble = b & 0x0f;
+ return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE;
+ }
+
+ /**
+ * Given a TCompactProtocol.Types constant, convert it to its corresponding
+ * TType value.
+ */
+ private byte getTType(byte type) throws TProtocolException {
+ switch ((byte)(type & 0x0f)) {
+ case TType.STOP:
+ return TType.STOP;
+ case Types.BOOLEAN_FALSE:
+ case Types.BOOLEAN_TRUE:
+ return TType.BOOL;
+ case Types.BYTE:
+ return TType.BYTE;
+ case Types.I16:
+ return TType.I16;
+ case Types.I32:
+ return TType.I32;
+ case Types.I64:
+ return TType.I64;
+ case Types.DOUBLE:
+ return TType.DOUBLE;
+ case Types.BINARY:
+ return TType.STRING;
+ case Types.LIST:
+ return TType.LIST;
+ case Types.SET:
+ return TType.SET;
+ case Types.MAP:
+ return TType.MAP;
+ case Types.STRUCT:
+ return TType.STRUCT;
+ default:
+ throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f));
+ }
+ }
+
+ /**
+ * Given a TType value, find the appropriate TCompactProtocol.Types constant.
+ */
+ private byte getCompactType(byte ttype) {
+ return ttypeToCompactType[ttype];
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TField.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TField.java
new file mode 100644
index 000000000..3872b008f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TField.java
@@ -0,0 +1,65 @@
+/*
+ * 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.thrift.protocol;
+
+/**
+ * Helper class that encapsulates field metadata.
+ * <p>Two fields are considered equal if they have the same type and id.</p>
+ */
+public class TField {
+ public TField() {
+ this("", TType.STOP, (short)0);
+ }
+
+ public TField(String n, byte t, short i) {
+ name = n;
+ type = t;
+ id = i;
+ }
+
+ public final String name;
+ public final byte type;
+ public final short id;
+
+ public String toString() {
+ return "<TField name:'" + name + "' type:" + type + " field-id:" + id + ">";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + id;
+ result = prime * result + type;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TField otherField = (TField) obj;
+ return type == otherField.type && id == otherField.id;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java
new file mode 100644
index 000000000..d37c4937f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java
@@ -0,0 +1,973 @@
+/*
+ * 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.thrift.protocol;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Stack;
+
+import org.apache.thrift.TByteArrayOutputStream;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * JSON protocol implementation for thrift.
+ *
+ * This is a full-featured protocol supporting write and read.
+ *
+ * Please see the C++ class header for a detailed description of the
+ * protocol's wire format.
+ *
+ */
+public class TJSONProtocol extends TProtocol {
+
+ /**
+ * Factory for JSON protocol objects
+ */
+ public static class Factory implements TProtocolFactory {
+ protected boolean fieldNamesAsString_ = false;
+
+ public Factory() {}
+
+ public Factory(boolean fieldNamesAsString) {
+ fieldNamesAsString_ = fieldNamesAsString;
+ }
+
+ public TProtocol getProtocol(TTransport trans) {
+ return new TJSONProtocol(trans, fieldNamesAsString_);
+ }
+
+ }
+
+ private static final byte[] COMMA = new byte[] {','};
+ private static final byte[] COLON = new byte[] {':'};
+ private static final byte[] LBRACE = new byte[] {'{'};
+ private static final byte[] RBRACE = new byte[] {'}'};
+ private static final byte[] LBRACKET = new byte[] {'['};
+ private static final byte[] RBRACKET = new byte[] {']'};
+ private static final byte[] QUOTE = new byte[] {'"'};
+ private static final byte[] BACKSLASH = new byte[] {'\\'};
+ private static final byte[] ZERO = new byte[] {'0'};
+
+ private static final byte[] ESCSEQ = new byte[] {'\\','u','0','0'};
+
+ private static final long VERSION = 1;
+
+ private static final byte[] JSON_CHAR_TABLE = {
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ 0, 0, 0, 0, 0, 0, 0, 0,'b','t','n', 0,'f','r', 0, 0, // 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+ 1, 1,'"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ };
+
+ private static final String ESCAPE_CHARS = "\"\\/bfnrt";
+
+ private static final byte[] ESCAPE_CHAR_VALS = {
+ '"', '\\', '/', '\b', '\f', '\n', '\r', '\t',
+ };
+
+ private static final int DEF_STRING_SIZE = 16;
+
+ private static final byte[] NAME_BOOL = new byte[] {'t', 'f'};
+ private static final byte[] NAME_BYTE = new byte[] {'i','8'};
+ private static final byte[] NAME_I16 = new byte[] {'i','1','6'};
+ private static final byte[] NAME_I32 = new byte[] {'i','3','2'};
+ private static final byte[] NAME_I64 = new byte[] {'i','6','4'};
+ private static final byte[] NAME_DOUBLE = new byte[] {'d','b','l'};
+ private static final byte[] NAME_STRUCT = new byte[] {'r','e','c'};
+ private static final byte[] NAME_STRING = new byte[] {'s','t','r'};
+ private static final byte[] NAME_MAP = new byte[] {'m','a','p'};
+ private static final byte[] NAME_LIST = new byte[] {'l','s','t'};
+ private static final byte[] NAME_SET = new byte[] {'s','e','t'};
+
+ private static final TStruct ANONYMOUS_STRUCT = new TStruct();
+
+ private static final byte[] getTypeNameForTypeID(byte typeID)
+ throws TException {
+ switch (typeID) {
+ case TType.BOOL:
+ return NAME_BOOL;
+ case TType.BYTE:
+ return NAME_BYTE;
+ case TType.I16:
+ return NAME_I16;
+ case TType.I32:
+ return NAME_I32;
+ case TType.I64:
+ return NAME_I64;
+ case TType.DOUBLE:
+ return NAME_DOUBLE;
+ case TType.STRING:
+ return NAME_STRING;
+ case TType.STRUCT:
+ return NAME_STRUCT;
+ case TType.MAP:
+ return NAME_MAP;
+ case TType.SET:
+ return NAME_SET;
+ case TType.LIST:
+ return NAME_LIST;
+ default:
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+ "Unrecognized type");
+ }
+ }
+
+ private static final byte getTypeIDForTypeName(byte[] name)
+ throws TException {
+ byte result = TType.STOP;
+ if (name.length > 1) {
+ switch (name[0]) {
+ case 'd':
+ result = TType.DOUBLE;
+ break;
+ case 'i':
+ switch (name[1]) {
+ case '8':
+ result = TType.BYTE;
+ break;
+ case '1':
+ result = TType.I16;
+ break;
+ case '3':
+ result = TType.I32;
+ break;
+ case '6':
+ result = TType.I64;
+ break;
+ }
+ break;
+ case 'l':
+ result = TType.LIST;
+ break;
+ case 'm':
+ result = TType.MAP;
+ break;
+ case 'r':
+ result = TType.STRUCT;
+ break;
+ case 's':
+ if (name[1] == 't') {
+ result = TType.STRING;
+ }
+ else if (name[1] == 'e') {
+ result = TType.SET;
+ }
+ break;
+ case 't':
+ result = TType.BOOL;
+ break;
+ }
+ }
+ if (result == TType.STOP) {
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+ "Unrecognized type");
+ }
+ return result;
+ }
+
+ // Base class for tracking JSON contexts that may require inserting/reading
+ // additional JSON syntax characters
+ // This base context does nothing.
+ protected class JSONBaseContext {
+ protected void write() throws TException {}
+
+ protected void read() throws TException {}
+
+ protected boolean escapeNum() { return false; }
+ }
+
+ // Context for JSON lists. Will insert/read commas before each item except
+ // for the first one
+ protected class JSONListContext extends JSONBaseContext {
+ private boolean first_ = true;
+
+ @Override
+ protected void write() throws TException {
+ if (first_) {
+ first_ = false;
+ } else {
+ trans_.write(COMMA);
+ }
+ }
+
+ @Override
+ protected void read() throws TException {
+ if (first_) {
+ first_ = false;
+ } else {
+ readJSONSyntaxChar(COMMA);
+ }
+ }
+ }
+
+ // Context for JSON records. Will insert/read colons before the value portion
+ // of each record pair, and commas before each key except the first. In
+ // addition, will indicate that numbers in the key position need to be
+ // escaped in quotes (since JSON keys must be strings).
+ protected class JSONPairContext extends JSONBaseContext {
+ private boolean first_ = true;
+ private boolean colon_ = true;
+
+ @Override
+ protected void write() throws TException {
+ if (first_) {
+ first_ = false;
+ colon_ = true;
+ } else {
+ trans_.write(colon_ ? COLON : COMMA);
+ colon_ = !colon_;
+ }
+ }
+
+ @Override
+ protected void read() throws TException {
+ if (first_) {
+ first_ = false;
+ colon_ = true;
+ } else {
+ readJSONSyntaxChar(colon_ ? COLON : COMMA);
+ colon_ = !colon_;
+ }
+ }
+
+ @Override
+ protected boolean escapeNum() {
+ return colon_;
+ }
+ }
+
+ // Holds up to one byte from the transport
+ protected class LookaheadReader {
+
+ private boolean hasData_;
+ private byte[] data_ = new byte[1];
+
+ // Return and consume the next byte to be read, either taking it from the
+ // data buffer if present or getting it from the transport otherwise.
+ protected byte read() throws TException {
+ if (hasData_) {
+ hasData_ = false;
+ }
+ else {
+ trans_.readAll(data_, 0, 1);
+ }
+ return data_[0];
+ }
+
+ // Return the next byte to be read without consuming, filling the data
+ // buffer if it has not been filled already.
+ protected byte peek() throws TException {
+ if (!hasData_) {
+ trans_.readAll(data_, 0, 1);
+ }
+ hasData_ = true;
+ return data_[0];
+ }
+ }
+
+ // Stack of nested contexts that we may be in
+ private Stack<JSONBaseContext> contextStack_ = new Stack<JSONBaseContext>();
+
+ // Current context that we are in
+ private JSONBaseContext context_ = new JSONBaseContext();
+
+ // Reader that manages a 1-byte buffer
+ private LookaheadReader reader_ = new LookaheadReader();
+
+ // Write out the TField names as a string instead of the default integer value
+ private boolean fieldNamesAsString_ = false;
+
+ // Push a new JSON context onto the stack.
+ private void pushContext(JSONBaseContext c) {
+ contextStack_.push(context_);
+ context_ = c;
+ }
+
+ // Pop the last JSON context off the stack
+ private void popContext() {
+ context_ = contextStack_.pop();
+ }
+
+ // Reset the context stack to its initial state
+ private void resetContext() {
+ while (!contextStack_.isEmpty()) {
+ popContext();
+ }
+ }
+
+ /**
+ * Constructor
+ */
+ public TJSONProtocol(TTransport trans) {
+ super(trans);
+ }
+
+ public TJSONProtocol(TTransport trans, boolean fieldNamesAsString) {
+ super(trans);
+ fieldNamesAsString_ = fieldNamesAsString;
+ }
+
+ @Override
+ public void reset() {
+ contextStack_.clear();
+ context_ = new JSONBaseContext();
+ reader_ = new LookaheadReader();
+ }
+
+ // Temporary buffer used by several methods
+ private byte[] tmpbuf_ = new byte[4];
+
+ // Read a byte that must match b[0]; otherwise an exception is thrown.
+ // Marked protected to avoid synthetic accessor in JSONListContext.read
+ // and JSONPairContext.read
+ protected void readJSONSyntaxChar(byte[] b) throws TException {
+ byte ch = reader_.read();
+ if (ch != b[0]) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Unexpected character:" + (char)ch);
+ }
+ }
+
+ // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
+ // corresponding hex value
+ private static final byte hexVal(byte ch) throws TException {
+ if ((ch >= '0') && (ch <= '9')) {
+ return (byte)((char)ch - '0');
+ }
+ else if ((ch >= 'a') && (ch <= 'f')) {
+ return (byte)((char)ch - 'a' + 10);
+ }
+ else {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected hex character");
+ }
+ }
+
+ // Convert a byte containing a hex value to its corresponding hex character
+ private static final byte hexChar(byte val) {
+ val &= 0x0F;
+ if (val < 10) {
+ return (byte)((char)val + '0');
+ }
+ else {
+ return (byte)((char)(val - 10) + 'a');
+ }
+ }
+
+ // Write the bytes in array buf as a JSON characters, escaping as needed
+ private void writeJSONString(byte[] b) throws TException {
+ context_.write();
+ trans_.write(QUOTE);
+ int len = b.length;
+ for (int i = 0; i < len; i++) {
+ if ((b[i] & 0x00FF) >= 0x30) {
+ if (b[i] == BACKSLASH[0]) {
+ trans_.write(BACKSLASH);
+ trans_.write(BACKSLASH);
+ }
+ else {
+ trans_.write(b, i, 1);
+ }
+ }
+ else {
+ tmpbuf_[0] = JSON_CHAR_TABLE[b[i]];
+ if (tmpbuf_[0] == 1) {
+ trans_.write(b, i, 1);
+ }
+ else if (tmpbuf_[0] > 1) {
+ trans_.write(BACKSLASH);
+ trans_.write(tmpbuf_, 0, 1);
+ }
+ else {
+ trans_.write(ESCSEQ);
+ tmpbuf_[0] = hexChar((byte)(b[i] >> 4));
+ tmpbuf_[1] = hexChar(b[i]);
+ trans_.write(tmpbuf_, 0, 2);
+ }
+ }
+ }
+ trans_.write(QUOTE);
+ }
+
+ // Write out number as a JSON value. If the context dictates so, it will be
+ // wrapped in quotes to output as a JSON string.
+ private void writeJSONInteger(long num) throws TException {
+ context_.write();
+ String str = Long.toString(num);
+ boolean escapeNum = context_.escapeNum();
+ if (escapeNum) {
+ trans_.write(QUOTE);
+ }
+ byte[] buf = str.getBytes(StandardCharsets.UTF_8);
+ trans_.write(buf);
+ if (escapeNum) {
+ trans_.write(QUOTE);
+ }
+ }
+
+ // Write out a double as a JSON value. If it is NaN or infinity or if the
+ // context dictates escaping, write out as JSON string.
+ private void writeJSONDouble(double num) throws TException {
+ context_.write();
+ String str = Double.toString(num);
+ boolean special = false;
+ switch (str.charAt(0)) {
+ case 'N': // NaN
+ case 'I': // Infinity
+ special = true;
+ break;
+ case '-':
+ if (str.charAt(1) == 'I') { // -Infinity
+ special = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ boolean escapeNum = special || context_.escapeNum();
+ if (escapeNum) {
+ trans_.write(QUOTE);
+ }
+ byte[] b = str.getBytes(StandardCharsets.UTF_8);
+ trans_.write(b, 0, b.length);
+ if (escapeNum) {
+ trans_.write(QUOTE);
+ }
+ }
+
+ // Write out contents of byte array b as a JSON string with base-64 encoded
+ // data
+ private void writeJSONBase64(byte[] b, int offset, int length) throws TException {
+ context_.write();
+ trans_.write(QUOTE);
+ int len = length;
+ int off = offset;
+ while (len >= 3) {
+ // Encode 3 bytes at a time
+ TBase64Utils.encode(b, off, 3, tmpbuf_, 0);
+ trans_.write(tmpbuf_, 0, 4);
+ off += 3;
+ len -= 3;
+ }
+ if (len > 0) {
+ // Encode remainder
+ TBase64Utils.encode(b, off, len, tmpbuf_, 0);
+ trans_.write(tmpbuf_, 0, len + 1);
+ }
+ trans_.write(QUOTE);
+ }
+
+ private void writeJSONObjectStart() throws TException {
+ context_.write();
+ trans_.write(LBRACE);
+ pushContext(new JSONPairContext());
+ }
+
+ private void writeJSONObjectEnd() throws TException {
+ popContext();
+ trans_.write(RBRACE);
+ }
+
+ private void writeJSONArrayStart() throws TException {
+ context_.write();
+ trans_.write(LBRACKET);
+ pushContext(new JSONListContext());
+ }
+
+ private void writeJSONArrayEnd() throws TException {
+ popContext();
+ trans_.write(RBRACKET);
+ }
+
+ @Override
+ public void writeMessageBegin(TMessage message) throws TException {
+ resetContext(); // THRIFT-3743
+ writeJSONArrayStart();
+ writeJSONInteger(VERSION);
+ byte[] b = message.name.getBytes(StandardCharsets.UTF_8);
+ writeJSONString(b);
+ writeJSONInteger(message.type);
+ writeJSONInteger(message.seqid);
+ }
+
+ @Override
+ public void writeMessageEnd() throws TException {
+ writeJSONArrayEnd();
+ }
+
+ @Override
+ public void writeStructBegin(TStruct struct) throws TException {
+ writeJSONObjectStart();
+ }
+
+ @Override
+ public void writeStructEnd() throws TException {
+ writeJSONObjectEnd();
+ }
+
+ @Override
+ public void writeFieldBegin(TField field) throws TException {
+ if (fieldNamesAsString_) {
+ writeString(field.name);
+ } else {
+ writeJSONInteger(field.id);
+ }
+ writeJSONObjectStart();
+ writeJSONString(getTypeNameForTypeID(field.type));
+ }
+
+ @Override
+ public void writeFieldEnd() throws TException {
+ writeJSONObjectEnd();
+ }
+
+ @Override
+ public void writeFieldStop() {}
+
+ @Override
+ public void writeMapBegin(TMap map) throws TException {
+ writeJSONArrayStart();
+ writeJSONString(getTypeNameForTypeID(map.keyType));
+ writeJSONString(getTypeNameForTypeID(map.valueType));
+ writeJSONInteger(map.size);
+ writeJSONObjectStart();
+ }
+
+ @Override
+ public void writeMapEnd() throws TException {
+ writeJSONObjectEnd();
+ writeJSONArrayEnd();
+ }
+
+ @Override
+ public void writeListBegin(TList list) throws TException {
+ writeJSONArrayStart();
+ writeJSONString(getTypeNameForTypeID(list.elemType));
+ writeJSONInteger(list.size);
+ }
+
+ @Override
+ public void writeListEnd() throws TException {
+ writeJSONArrayEnd();
+ }
+
+ @Override
+ public void writeSetBegin(TSet set) throws TException {
+ writeJSONArrayStart();
+ writeJSONString(getTypeNameForTypeID(set.elemType));
+ writeJSONInteger(set.size);
+ }
+
+ @Override
+ public void writeSetEnd() throws TException {
+ writeJSONArrayEnd();
+ }
+
+ @Override
+ public void writeBool(boolean b) throws TException {
+ writeJSONInteger(b ? (long)1 : (long)0);
+ }
+
+ @Override
+ public void writeByte(byte b) throws TException {
+ writeJSONInteger((long)b);
+ }
+
+ @Override
+ public void writeI16(short i16) throws TException {
+ writeJSONInteger((long)i16);
+ }
+
+ @Override
+ public void writeI32(int i32) throws TException {
+ writeJSONInteger((long)i32);
+ }
+
+ @Override
+ public void writeI64(long i64) throws TException {
+ writeJSONInteger(i64);
+ }
+
+ @Override
+ public void writeDouble(double dub) throws TException {
+ writeJSONDouble(dub);
+ }
+
+ @Override
+ public void writeString(String str) throws TException {
+ byte[] b = str.getBytes(StandardCharsets.UTF_8);
+ writeJSONString(b);
+ }
+
+ @Override
+ public void writeBinary(ByteBuffer bin) throws TException {
+ writeJSONBase64(bin.array(), bin.position() + bin.arrayOffset(), bin.limit() - bin.position() - bin.arrayOffset());
+ }
+
+ /**
+ * Reading methods.
+ */
+
+ // Read in a JSON string, unescaping as appropriate.. Skip reading from the
+ // context if skipContext is true.
+ private TByteArrayOutputStream readJSONString(boolean skipContext)
+ throws TException {
+ TByteArrayOutputStream arr = new TByteArrayOutputStream(DEF_STRING_SIZE);
+ ArrayList<Character> codeunits = new ArrayList<Character>();
+ if (!skipContext) {
+ context_.read();
+ }
+ readJSONSyntaxChar(QUOTE);
+ while (true) {
+ byte ch = reader_.read();
+ if (ch == QUOTE[0]) {
+ break;
+ }
+ if (ch == ESCSEQ[0]) {
+ ch = reader_.read();
+ if (ch == ESCSEQ[1]) {
+ trans_.readAll(tmpbuf_, 0, 4);
+ short cu = (short)(
+ ((short)hexVal(tmpbuf_[0]) << 12) +
+ ((short)hexVal(tmpbuf_[1]) << 8) +
+ ((short)hexVal(tmpbuf_[2]) << 4) +
+ (short)hexVal(tmpbuf_[3]));
+ try {
+ if (Character.isHighSurrogate((char)cu)) {
+ if (codeunits.size() > 0) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected low surrogate char");
+ }
+ codeunits.add((char)cu);
+ }
+ else if (Character.isLowSurrogate((char)cu)) {
+ if (codeunits.size() == 0) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected high surrogate char");
+ }
+
+ codeunits.add((char)cu);
+ arr.write(
+ (new String(new int[] { codeunits.get(0), codeunits.get(1) },
+ 0, 2)).getBytes(StandardCharsets.UTF_8));
+ codeunits.clear();
+ }
+ else {
+ arr.write((new String(new int[] { cu }, 0, 1))
+ .getBytes(StandardCharsets.UTF_8));
+ }
+ continue;
+ } catch (IOException ex) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Invalid unicode sequence");
+ }
+ }
+ else {
+ int off = ESCAPE_CHARS.indexOf(ch);
+ if (off == -1) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected control char");
+ }
+ ch = ESCAPE_CHAR_VALS[off];
+ }
+ }
+ arr.write(ch);
+ }
+ return arr;
+ }
+
+ // Return true if the given byte could be a valid part of a JSON number.
+ private boolean isJSONNumeric(byte b) {
+ switch (b) {
+ case '+':
+ case '-':
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'E':
+ case 'e':
+ return true;
+ }
+ return false;
+ }
+
+ // Read in a sequence of characters that are all valid in JSON numbers. Does
+ // not do a complete regex check to validate that this is actually a number.
+ private String readJSONNumericChars() throws TException {
+ StringBuilder strbld = new StringBuilder();
+ while (true) {
+ byte ch = reader_.peek();
+ if (!isJSONNumeric(ch)) {
+ break;
+ }
+ strbld.append((char)reader_.read());
+ }
+ return strbld.toString();
+ }
+
+ // Read in a JSON number. If the context dictates, read in enclosing quotes.
+ private long readJSONInteger() throws TException {
+ context_.read();
+ if (context_.escapeNum()) {
+ readJSONSyntaxChar(QUOTE);
+ }
+ String str = readJSONNumericChars();
+ if (context_.escapeNum()) {
+ readJSONSyntaxChar(QUOTE);
+ }
+ try {
+ return Long.valueOf(str);
+ }
+ catch (NumberFormatException ex) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Bad data encounted in numeric data");
+ }
+ }
+
+ // Read in a JSON double value. Throw if the value is not wrapped in quotes
+ // when expected or if wrapped in quotes when not expected.
+ private double readJSONDouble() throws TException {
+ context_.read();
+ if (reader_.peek() == QUOTE[0]) {
+ TByteArrayOutputStream arr = readJSONString(true);
+ double dub = Double.valueOf(arr.toString(StandardCharsets.UTF_8));
+ if (!context_.escapeNum() && !Double.isNaN(dub)
+ && !Double.isInfinite(dub)) {
+ // Throw exception -- we should not be in a string in this case
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Numeric data unexpectedly quoted");
+ }
+ return dub;
+ }
+ else {
+ if (context_.escapeNum()) {
+ // This will throw - we should have had a quote if escapeNum == true
+ readJSONSyntaxChar(QUOTE);
+ }
+ try {
+ return Double.valueOf(readJSONNumericChars());
+ }
+ catch (NumberFormatException ex) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Bad data encounted in numeric data");
+ }
+ }
+ }
+
+ // Read in a JSON string containing base-64 encoded data and decode it.
+ private byte[] readJSONBase64() throws TException {
+ TByteArrayOutputStream arr = readJSONString(false);
+ byte[] b = arr.get();
+ int len = arr.len();
+ int off = 0;
+ int size = 0;
+ // Ignore padding
+ int bound = len >= 2 ? len - 2 : 0;
+ for (int i = len - 1; i >= bound && b[i] == '='; --i) {
+ --len;
+ }
+ while (len >= 4) {
+ // Decode 4 bytes at a time
+ TBase64Utils.decode(b, off, 4, b, size); // NB: decoded in place
+ off += 4;
+ len -= 4;
+ size += 3;
+ }
+ // Don't decode if we hit the end or got a single leftover byte (invalid
+ // base64 but legal for skip of regular string type)
+ if (len > 1) {
+ // Decode remainder
+ TBase64Utils.decode(b, off, len, b, size); // NB: decoded in place
+ size += len - 1;
+ }
+ // Sadly we must copy the byte[] (any way around this?)
+ byte [] result = new byte[size];
+ System.arraycopy(b, 0, result, 0, size);
+ return result;
+ }
+
+ private void readJSONObjectStart() throws TException {
+ context_.read();
+ readJSONSyntaxChar(LBRACE);
+ pushContext(new JSONPairContext());
+ }
+
+ private void readJSONObjectEnd() throws TException {
+ readJSONSyntaxChar(RBRACE);
+ popContext();
+ }
+
+ private void readJSONArrayStart() throws TException {
+ context_.read();
+ readJSONSyntaxChar(LBRACKET);
+ pushContext(new JSONListContext());
+ }
+
+ private void readJSONArrayEnd() throws TException {
+ readJSONSyntaxChar(RBRACKET);
+ popContext();
+ }
+
+ @Override
+ public TMessage readMessageBegin() throws TException {
+ resetContext(); // THRIFT-3743
+ readJSONArrayStart();
+ if (readJSONInteger() != VERSION) {
+ throw new TProtocolException(TProtocolException.BAD_VERSION,
+ "Message contained bad version.");
+ }
+ String name = readJSONString(false).toString(StandardCharsets.UTF_8);
+ byte type = (byte) readJSONInteger();
+ int seqid = (int) readJSONInteger();
+ return new TMessage(name, type, seqid);
+ }
+
+ @Override
+ public void readMessageEnd() throws TException {
+ readJSONArrayEnd();
+ }
+
+ @Override
+ public TStruct readStructBegin() throws TException {
+ readJSONObjectStart();
+ return ANONYMOUS_STRUCT;
+ }
+
+ @Override
+ public void readStructEnd() throws TException {
+ readJSONObjectEnd();
+ }
+
+ @Override
+ public TField readFieldBegin() throws TException {
+ byte ch = reader_.peek();
+ byte type;
+ short id = 0;
+ if (ch == RBRACE[0]) {
+ type = TType.STOP;
+ }
+ else {
+ id = (short) readJSONInteger();
+ readJSONObjectStart();
+ type = getTypeIDForTypeName(readJSONString(false).get());
+ }
+ return new TField("", type, id);
+ }
+
+ @Override
+ public void readFieldEnd() throws TException {
+ readJSONObjectEnd();
+ }
+
+ @Override
+ public TMap readMapBegin() throws TException {
+ readJSONArrayStart();
+ byte keyType = getTypeIDForTypeName(readJSONString(false).get());
+ byte valueType = getTypeIDForTypeName(readJSONString(false).get());
+ int size = (int)readJSONInteger();
+ readJSONObjectStart();
+ return new TMap(keyType, valueType, size);
+ }
+
+ @Override
+ public void readMapEnd() throws TException {
+ readJSONObjectEnd();
+ readJSONArrayEnd();
+ }
+
+ @Override
+ public TList readListBegin() throws TException {
+ readJSONArrayStart();
+ byte elemType = getTypeIDForTypeName(readJSONString(false).get());
+ int size = (int)readJSONInteger();
+ return new TList(elemType, size);
+ }
+
+ @Override
+ public void readListEnd() throws TException {
+ readJSONArrayEnd();
+ }
+
+ @Override
+ public TSet readSetBegin() throws TException {
+ readJSONArrayStart();
+ byte elemType = getTypeIDForTypeName(readJSONString(false).get());
+ int size = (int)readJSONInteger();
+ return new TSet(elemType, size);
+ }
+
+ @Override
+ public void readSetEnd() throws TException {
+ readJSONArrayEnd();
+ }
+
+ @Override
+ public boolean readBool() throws TException {
+ return (readJSONInteger() == 0 ? false : true);
+ }
+
+ @Override
+ public byte readByte() throws TException {
+ return (byte) readJSONInteger();
+ }
+
+ @Override
+ public short readI16() throws TException {
+ return (short) readJSONInteger();
+ }
+
+ @Override
+ public int readI32() throws TException {
+ return (int) readJSONInteger();
+ }
+
+ @Override
+ public long readI64() throws TException {
+ return (long) readJSONInteger();
+ }
+
+ @Override
+ public double readDouble() throws TException {
+ return readJSONDouble();
+ }
+
+ @Override
+ public String readString() throws TException {
+ return readJSONString(false).toString(StandardCharsets.UTF_8);
+ }
+
+ @Override
+ public ByteBuffer readBinary() throws TException {
+ return ByteBuffer.wrap(readJSONBase64());
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TList.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TList.java
new file mode 100644
index 000000000..0d36e83d9
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TList.java
@@ -0,0 +1,38 @@
+/*
+ * 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.thrift.protocol;
+
+/**
+ * Helper class that encapsulates list metadata.
+ *
+ */
+public final class TList {
+ public TList() {
+ this(TType.STOP, 0);
+ }
+
+ public TList(byte t, int s) {
+ elemType = t;
+ size = s;
+ }
+
+ public final byte elemType;
+ public final int size;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMap.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMap.java
new file mode 100644
index 000000000..20881f7ac
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMap.java
@@ -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.thrift.protocol;
+
+/**
+ * Helper class that encapsulates map metadata.
+ *
+ */
+public final class TMap {
+ public TMap() {
+ this(TType.STOP, TType.STOP, 0);
+ }
+
+ public TMap(byte k, byte v, int s) {
+ keyType = k;
+ valueType = v;
+ size = s;
+ }
+
+ public final byte keyType;
+ public final byte valueType;
+ public final int size;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessage.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessage.java
new file mode 100644
index 000000000..f13b8ca50
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessage.java
@@ -0,0 +1,76 @@
+/*
+ * 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.thrift.protocol;
+
+/**
+ * Helper class that encapsulates struct metadata.
+ *
+ */
+public final class TMessage {
+ public TMessage() {
+ this("", TType.STOP, 0);
+ }
+
+ public TMessage(String n, byte t, int s) {
+ name = n;
+ type = t;
+ seqid = s;
+ }
+
+ public final String name;
+ public final byte type;
+ public final int seqid;
+
+ @Override
+ public String toString() {
+ return "<TMessage name:'" + name + "' type: " + type + " seqid:" + seqid + ">";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + seqid;
+ result = prime * result + type;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TMessage other = (TMessage) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (seqid != other.seqid)
+ return false;
+ if (type != other.type)
+ return false;
+ return true;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessageType.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessageType.java
new file mode 100644
index 000000000..aa3f93177
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMessageType.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.thrift.protocol;
+
+/**
+ * Message type constants in the Thrift protocol.
+ *
+ */
+public final class TMessageType {
+ public static final byte CALL = 1;
+ public static final byte REPLY = 2;
+ public static final byte EXCEPTION = 3;
+ public static final byte ONEWAY = 4;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java
new file mode 100644
index 000000000..0ea566ba6
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java
@@ -0,0 +1,93 @@
+/*
+ * 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.thrift.protocol;
+
+import org.apache.thrift.TException;
+
+/**
+ * <code>TMultiplexedProtocol</code> is a protocol-independent concrete decorator
+ * that allows a Thrift client to communicate with a multiplexing Thrift server,
+ * by prepending the service name to the function name during function calls.
+ *
+ * <p>NOTE: THIS IS NOT USED BY SERVERS. On the server, use {@link org.apache.thrift.TMultiplexedProcessor TMultiplexedProcessor} to handle requests
+ * from a multiplexing client.
+ *
+ * <p>This example uses a single socket transport to invoke two services:
+ *
+ * <pre>
+ * {@code
+ * TSocket transport = new TSocket("localhost", 9090);
+ * transport.open();
+ *
+ * TBinaryProtocol protocol = new TBinaryProtocol(transport);
+ *
+ * TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
+ * Calculator.Client service = new Calculator.Client(mp);
+ *
+ * TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
+ * WeatherReport.Client service2 = new WeatherReport.Client(mp2);
+ *
+ * System.out.println(service.add(2,2));
+ * System.out.println(service2.getTemperature());
+ * }
+ * </pre>
+ *
+ * @see org.apache.thrift.protocol.TProtocolDecorator
+ */
+public class TMultiplexedProtocol extends TProtocolDecorator {
+
+ /** Used to delimit the service name from the function name */
+ public static final String SEPARATOR = ":";
+
+ private final String SERVICE_NAME;
+
+ /**
+ * Wrap the specified protocol, allowing it to be used to communicate with a
+ * multiplexing server. The <code>serviceName</code> is required as it is
+ * prepended to the message header so that the multiplexing server can broker
+ * the function call to the proper service.
+ *
+ * @param protocol Your communication protocol of choice, e.g. <code>TBinaryProtocol</code>.
+ * @param serviceName The service name of the service communicating via this protocol.
+ */
+ public TMultiplexedProtocol(TProtocol protocol, String serviceName) {
+ super(protocol);
+ SERVICE_NAME = serviceName;
+ }
+
+ /**
+ * Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
+ *
+ * @param tMessage The original message.
+ * @throws TException Passed through from wrapped <code>TProtocol</code> instance.
+ */
+ @Override
+ public void writeMessageBegin(TMessage tMessage) throws TException {
+ if (tMessage.type == TMessageType.CALL || tMessage.type == TMessageType.ONEWAY) {
+ super.writeMessageBegin(new TMessage(
+ SERVICE_NAME + SEPARATOR + tMessage.name,
+ tMessage.type,
+ tMessage.seqid
+ ));
+ } else {
+ super.writeMessageBegin(tMessage);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocol.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocol.java
new file mode 100644
index 000000000..0e96368d4
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocol.java
@@ -0,0 +1,162 @@
+/*
+ * 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.thrift.protocol;
+
+import java.nio.ByteBuffer;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.scheme.IScheme;
+import org.apache.thrift.scheme.StandardScheme;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * Protocol interface definition.
+ *
+ */
+public abstract class TProtocol {
+
+ /**
+ * Prevent direct instantiation
+ */
+ @SuppressWarnings("unused")
+ private TProtocol() {}
+
+ /**
+ * Transport
+ */
+ protected TTransport trans_;
+
+ /**
+ * Constructor
+ */
+ protected TProtocol(TTransport trans) {
+ trans_ = trans;
+ }
+
+ /**
+ * Transport accessor
+ */
+ public TTransport getTransport() {
+ return trans_;
+ }
+
+ /**
+ * Writing methods.
+ */
+
+ public abstract void writeMessageBegin(TMessage message) throws TException;
+
+ public abstract void writeMessageEnd() throws TException;
+
+ public abstract void writeStructBegin(TStruct struct) throws TException;
+
+ public abstract void writeStructEnd() throws TException;
+
+ public abstract void writeFieldBegin(TField field) throws TException;
+
+ public abstract void writeFieldEnd() throws TException;
+
+ public abstract void writeFieldStop() throws TException;
+
+ public abstract void writeMapBegin(TMap map) throws TException;
+
+ public abstract void writeMapEnd() throws TException;
+
+ public abstract void writeListBegin(TList list) throws TException;
+
+ public abstract void writeListEnd() throws TException;
+
+ public abstract void writeSetBegin(TSet set) throws TException;
+
+ public abstract void writeSetEnd() throws TException;
+
+ public abstract void writeBool(boolean b) throws TException;
+
+ public abstract void writeByte(byte b) throws TException;
+
+ public abstract void writeI16(short i16) throws TException;
+
+ public abstract void writeI32(int i32) throws TException;
+
+ public abstract void writeI64(long i64) throws TException;
+
+ public abstract void writeDouble(double dub) throws TException;
+
+ public abstract void writeString(String str) throws TException;
+
+ public abstract void writeBinary(ByteBuffer buf) throws TException;
+
+ /**
+ * Reading methods.
+ */
+
+ public abstract TMessage readMessageBegin() throws TException;
+
+ public abstract void readMessageEnd() throws TException;
+
+ public abstract TStruct readStructBegin() throws TException;
+
+ public abstract void readStructEnd() throws TException;
+
+ public abstract TField readFieldBegin() throws TException;
+
+ public abstract void readFieldEnd() throws TException;
+
+ public abstract TMap readMapBegin() throws TException;
+
+ public abstract void readMapEnd() throws TException;
+
+ public abstract TList readListBegin() throws TException;
+
+ public abstract void readListEnd() throws TException;
+
+ public abstract TSet readSetBegin() throws TException;
+
+ public abstract void readSetEnd() throws TException;
+
+ public abstract boolean readBool() throws TException;
+
+ public abstract byte readByte() throws TException;
+
+ public abstract short readI16() throws TException;
+
+ public abstract int readI32() throws TException;
+
+ public abstract long readI64() throws TException;
+
+ public abstract double readDouble() throws TException;
+
+ public abstract String readString() throws TException;
+
+ public abstract ByteBuffer readBinary() throws TException;
+
+ /**
+ * Reset any internal state back to a blank slate. This method only needs to
+ * be implemented for stateful protocols.
+ */
+ public void reset() {}
+
+ /**
+ * Scheme accessor
+ */
+ public Class<? extends IScheme> getScheme() {
+ return StandardScheme.class;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolDecorator.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolDecorator.java
new file mode 100644
index 000000000..2d29cd231
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolDecorator.java
@@ -0,0 +1,213 @@
+/*
+ * 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.thrift.protocol;
+
+import org.apache.thrift.TException;
+
+import java.nio.ByteBuffer;
+
+/**
+ * <code>TProtocolDecorator</code> forwards all requests to an enclosed
+ * <code>TProtocol</code> instance, providing a way to author concise
+ * concrete decorator subclasses. While it has no abstract methods, it
+ * is marked abstract as a reminder that by itself, it does not modify
+ * the behaviour of the enclosed <code>TProtocol</code>.
+ *
+ * <p>See p.175 of Design Patterns (by Gamma et al.)</p>
+ *
+ * @see org.apache.thrift.protocol.TMultiplexedProtocol
+ */
+public abstract class TProtocolDecorator extends TProtocol {
+
+ private final TProtocol concreteProtocol;
+
+ /**
+ * Encloses the specified protocol.
+ * @param protocol All operations will be forward to this protocol. Must be non-null.
+ */
+ public TProtocolDecorator(TProtocol protocol) {
+ super(protocol.getTransport());
+ concreteProtocol = protocol;
+ }
+
+ public void writeMessageBegin(TMessage tMessage) throws TException {
+ concreteProtocol.writeMessageBegin(tMessage);
+ }
+
+ public void writeMessageEnd() throws TException {
+ concreteProtocol.writeMessageEnd();
+ }
+
+ public void writeStructBegin(TStruct tStruct) throws TException {
+ concreteProtocol.writeStructBegin(tStruct);
+ }
+
+ public void writeStructEnd() throws TException {
+ concreteProtocol.writeStructEnd();
+ }
+
+ public void writeFieldBegin(TField tField) throws TException {
+ concreteProtocol.writeFieldBegin(tField);
+ }
+
+ public void writeFieldEnd() throws TException {
+ concreteProtocol.writeFieldEnd();
+ }
+
+ public void writeFieldStop() throws TException {
+ concreteProtocol.writeFieldStop();
+ }
+
+ public void writeMapBegin(TMap tMap) throws TException {
+ concreteProtocol.writeMapBegin(tMap);
+ }
+
+ public void writeMapEnd() throws TException {
+ concreteProtocol.writeMapEnd();
+ }
+
+ public void writeListBegin(TList tList) throws TException {
+ concreteProtocol.writeListBegin(tList);
+ }
+
+ public void writeListEnd() throws TException {
+ concreteProtocol.writeListEnd();
+ }
+
+ public void writeSetBegin(TSet tSet) throws TException {
+ concreteProtocol.writeSetBegin(tSet);
+ }
+
+ public void writeSetEnd() throws TException {
+ concreteProtocol.writeSetEnd();
+ }
+
+ public void writeBool(boolean b) throws TException {
+ concreteProtocol.writeBool(b);
+ }
+
+ public void writeByte(byte b) throws TException {
+ concreteProtocol.writeByte(b);
+ }
+
+ public void writeI16(short i) throws TException {
+ concreteProtocol.writeI16(i);
+ }
+
+ public void writeI32(int i) throws TException {
+ concreteProtocol.writeI32(i);
+ }
+
+ public void writeI64(long l) throws TException {
+ concreteProtocol.writeI64(l);
+ }
+
+ public void writeDouble(double v) throws TException {
+ concreteProtocol.writeDouble(v);
+ }
+
+ public void writeString(String s) throws TException {
+ concreteProtocol.writeString(s);
+ }
+
+ public void writeBinary(ByteBuffer buf) throws TException {
+ concreteProtocol.writeBinary(buf);
+ }
+
+ public TMessage readMessageBegin() throws TException {
+ return concreteProtocol.readMessageBegin();
+ }
+
+ public void readMessageEnd() throws TException {
+ concreteProtocol.readMessageEnd();
+ }
+
+ public TStruct readStructBegin() throws TException {
+ return concreteProtocol.readStructBegin();
+ }
+
+ public void readStructEnd() throws TException {
+ concreteProtocol.readStructEnd();
+ }
+
+ public TField readFieldBegin() throws TException {
+ return concreteProtocol.readFieldBegin();
+ }
+
+ public void readFieldEnd() throws TException {
+ concreteProtocol.readFieldEnd();
+ }
+
+ public TMap readMapBegin() throws TException {
+ return concreteProtocol.readMapBegin();
+ }
+
+ public void readMapEnd() throws TException {
+ concreteProtocol.readMapEnd();
+ }
+
+ public TList readListBegin() throws TException {
+ return concreteProtocol.readListBegin();
+ }
+
+ public void readListEnd() throws TException {
+ concreteProtocol.readListEnd();
+ }
+
+ public TSet readSetBegin() throws TException {
+ return concreteProtocol.readSetBegin();
+ }
+
+ public void readSetEnd() throws TException {
+ concreteProtocol.readSetEnd();
+ }
+
+ public boolean readBool() throws TException {
+ return concreteProtocol.readBool();
+ }
+
+ public byte readByte() throws TException {
+ return concreteProtocol.readByte();
+ }
+
+ public short readI16() throws TException {
+ return concreteProtocol.readI16();
+ }
+
+ public int readI32() throws TException {
+ return concreteProtocol.readI32();
+ }
+
+ public long readI64() throws TException {
+ return concreteProtocol.readI64();
+ }
+
+ public double readDouble() throws TException {
+ return concreteProtocol.readDouble();
+ }
+
+ public String readString() throws TException {
+ return concreteProtocol.readString();
+ }
+
+ public ByteBuffer readBinary() throws TException {
+ return concreteProtocol.readBinary();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolException.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolException.java
new file mode 100644
index 000000000..870f1b939
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolException.java
@@ -0,0 +1,82 @@
+/*
+ * 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.thrift.protocol;
+
+import org.apache.thrift.TException;
+
+/**
+ * Protocol exceptions.
+ *
+ */
+public class TProtocolException extends TException {
+
+
+ private static final long serialVersionUID = 1L;
+ public static final int UNKNOWN = 0;
+ public static final int INVALID_DATA = 1;
+ public static final int NEGATIVE_SIZE = 2;
+ public static final int SIZE_LIMIT = 3;
+ public static final int BAD_VERSION = 4;
+ public static final int NOT_IMPLEMENTED = 5;
+ public static final int DEPTH_LIMIT = 6;
+
+ protected int type_ = UNKNOWN;
+
+ public TProtocolException() {
+ super();
+ }
+
+ public TProtocolException(int type) {
+ super();
+ type_ = type;
+ }
+
+ public TProtocolException(int type, String message) {
+ super(message);
+ type_ = type;
+ }
+
+ public TProtocolException(String message) {
+ super(message);
+ }
+
+ public TProtocolException(int type, Throwable cause) {
+ super(cause);
+ type_ = type;
+ }
+
+ public TProtocolException(Throwable cause) {
+ super(cause);
+ }
+
+ public TProtocolException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TProtocolException(int type, String message, Throwable cause) {
+ super(message, cause);
+ type_ = type;
+ }
+
+ public int getType() {
+ return type_;
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolFactory.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolFactory.java
new file mode 100644
index 000000000..b72e87b38
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolFactory.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.thrift.protocol;
+
+import java.io.Serializable;
+
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * Factory interface for constructing protocol instances.
+ */
+public interface TProtocolFactory extends Serializable {
+ public TProtocol getProtocol(TTransport trans);
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java
new file mode 100644
index 000000000..cdaa30b87
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java
@@ -0,0 +1,221 @@
+/*
+ * 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.thrift.protocol;
+
+import org.apache.thrift.TException;
+
+/**
+ * Utility class with static methods for interacting with protocol data
+ * streams.
+ *
+ */
+public class TProtocolUtil {
+
+ /**
+ * The maximum recursive depth the skip() function will traverse before
+ * throwing a TException.
+ */
+ private static int maxSkipDepth = Integer.MAX_VALUE;
+
+ /**
+ * Specifies the maximum recursive depth that the skip function will
+ * traverse before throwing a TException. This is a global setting, so
+ * any call to skip in this JVM will enforce this value.
+ *
+ * @param depth the maximum recursive depth. A value of 2 would allow
+ * the skip function to skip a structure or collection with basic children,
+ * but it would not permit skipping a struct that had a field containing
+ * a child struct. A value of 1 would only allow skipping of simple
+ * types and empty structs/collections.
+ */
+ public static void setMaxSkipDepth(int depth) {
+ maxSkipDepth = depth;
+ }
+
+ /**
+ * Skips over the next data element from the provided input TProtocol object.
+ *
+ * @param prot the protocol object to read from
+ * @param type the next value will be interpreted as this TType value.
+ */
+ public static void skip(TProtocol prot, byte type)
+ throws TException {
+ skip(prot, type, maxSkipDepth);
+ }
+
+ /**
+ * Skips over the next data element from the provided input TProtocol object.
+ *
+ * @param prot the protocol object to read from
+ * @param type the next value will be interpreted as this TType value.
+ * @param maxDepth this function will only skip complex objects to this
+ * recursive depth, to prevent Java stack overflow.
+ */
+ public static void skip(TProtocol prot, byte type, int maxDepth)
+ throws TException {
+ if (maxDepth <= 0) {
+ throw new TException("Maximum skip depth exceeded");
+ }
+ switch (type) {
+ case TType.BOOL:
+ prot.readBool();
+ break;
+
+ case TType.BYTE:
+ prot.readByte();
+ break;
+
+ case TType.I16:
+ prot.readI16();
+ break;
+
+ case TType.I32:
+ prot.readI32();
+ break;
+
+ case TType.I64:
+ prot.readI64();
+ break;
+
+ case TType.DOUBLE:
+ prot.readDouble();
+ break;
+
+ case TType.STRING:
+ prot.readBinary();
+ break;
+
+ case TType.STRUCT:
+ prot.readStructBegin();
+ while (true) {
+ TField field = prot.readFieldBegin();
+ if (field.type == TType.STOP) {
+ break;
+ }
+ skip(prot, field.type, maxDepth - 1);
+ prot.readFieldEnd();
+ }
+ prot.readStructEnd();
+ break;
+
+ case TType.MAP:
+ TMap map = prot.readMapBegin();
+ for (int i = 0; i < map.size; i++) {
+ skip(prot, map.keyType, maxDepth - 1);
+ skip(prot, map.valueType, maxDepth - 1);
+ }
+ prot.readMapEnd();
+ break;
+
+ case TType.SET:
+ TSet set = prot.readSetBegin();
+ for (int i = 0; i < set.size; i++) {
+ skip(prot, set.elemType, maxDepth - 1);
+ }
+ prot.readSetEnd();
+ break;
+
+ case TType.LIST:
+ TList list = prot.readListBegin();
+ for (int i = 0; i < list.size; i++) {
+ skip(prot, list.elemType, maxDepth - 1);
+ }
+ prot.readListEnd();
+ break;
+
+ default:
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Unrecognized type " + type);
+ }
+ }
+
+ /**
+ * Attempt to determine the protocol used to serialize some data.
+ *
+ * The guess is based on known specificities of supported protocols.
+ * In some cases, no guess can be done, in that case we return the
+ * fallback TProtocolFactory.
+ * To be certain to correctly detect the protocol, the first encoded
+ * field should have a field id &lt; 256
+ *
+ * @param data The serialized data to guess the protocol for.
+ * @param fallback The TProtocol to return if no guess can be made.
+ * @return a Class implementing TProtocolFactory which can be used to create a deserializer.
+ */
+ public static TProtocolFactory guessProtocolFactory(byte[] data, TProtocolFactory fallback) {
+ //
+ // If the first and last bytes are opening/closing curly braces we guess the protocol as
+ // being TJSONProtocol.
+ // It could not be a TCompactBinary encoding for a field of type 0xb (Map)
+ // with delta id 7 as the last byte for TCompactBinary is always 0.
+ //
+
+ if ('{' == data[0] && '}' == data[data.length - 1]) {
+ return new TJSONProtocol.Factory();
+ }
+
+ //
+ // If the last byte is not 0, then it cannot be TCompactProtocol, it must be
+ // TBinaryProtocol.
+ //
+
+ if (data[data.length - 1] != 0) {
+ return new TBinaryProtocol.Factory();
+ }
+
+ //
+ // A first byte of value > 16 indicates TCompactProtocol was used, and the first byte
+ // encodes a delta field id (id <= 15) and a field type.
+ //
+
+ if (data[0] > 0x10) {
+ return new TCompactProtocol.Factory();
+ }
+
+ //
+ // If the second byte is 0 then it is a field id < 256 encoded by TBinaryProtocol.
+ // It cannot possibly be TCompactProtocol since a value of 0 would imply a field id
+ // of 0 as the zig zag varint encoding would end.
+ //
+
+ if (data.length > 1 && 0 == data[1]) {
+ return new TBinaryProtocol.Factory();
+ }
+
+ //
+ // If bit 7 of the first byte of the field id is set then we have two choices:
+ // 1. A field id > 63 was encoded with TCompactProtocol.
+ // 2. A field id > 0x7fff (32767) was encoded with TBinaryProtocol and the last byte of the
+ // serialized data is 0.
+ // Option 2 is impossible since field ids are short and thus limited to 32767.
+ //
+
+ if (data.length > 1 && (data[1] & 0x80) != 0) {
+ return new TCompactProtocol.Factory();
+ }
+
+ //
+ // The remaining case is either a field id <= 63 encoded as TCompactProtocol,
+ // one >= 256 encoded with TBinaryProtocol with a last byte at 0, or an empty structure.
+ // As we cannot really decide, we return the fallback protocol.
+ //
+ return fallback;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSet.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSet.java
new file mode 100644
index 000000000..38be9a991
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSet.java
@@ -0,0 +1,42 @@
+/*
+ * 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.thrift.protocol;
+
+/**
+ * Helper class that encapsulates set metadata.
+ *
+ */
+public final class TSet {
+ public TSet() {
+ this(TType.STOP, 0);
+ }
+
+ public TSet(byte t, int s) {
+ elemType = t;
+ size = s;
+ }
+
+ public TSet(TList list) {
+ this(list.elemType, list.size);
+ }
+
+ public final byte elemType;
+ public final int size;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java
new file mode 100644
index 000000000..eb7e23bf9
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java
@@ -0,0 +1,483 @@
+/*
+ * 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.thrift.protocol;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Stack;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * JSON protocol implementation for thrift.
+ *
+ * This protocol is write-only and produces a simple output format
+ * suitable for parsing by scripting languages. It should not be
+ * confused with the full-featured TJSONProtocol.
+ *
+ */
+public class TSimpleJSONProtocol extends TProtocol {
+
+ /**
+ * Factory
+ */
+ public static class Factory implements TProtocolFactory {
+ public TProtocol getProtocol(TTransport trans) {
+ return new TSimpleJSONProtocol(trans);
+ }
+ }
+
+ private static final byte[] COMMA = new byte[] {','};
+ private static final byte[] COLON = new byte[] {':'};
+ private static final byte[] LBRACE = new byte[] {'{'};
+ private static final byte[] RBRACE = new byte[] {'}'};
+ private static final byte[] LBRACKET = new byte[] {'['};
+ private static final byte[] RBRACKET = new byte[] {']'};
+ private static final char QUOTE = '"';
+
+ private static final TStruct ANONYMOUS_STRUCT = new TStruct();
+ private static final TField ANONYMOUS_FIELD = new TField();
+ private static final TMessage EMPTY_MESSAGE = new TMessage();
+ private static final TSet EMPTY_SET = new TSet();
+ private static final TList EMPTY_LIST = new TList();
+ private static final TMap EMPTY_MAP = new TMap();
+ private static final String LIST = "list";
+ private static final String SET = "set";
+ private static final String MAP = "map";
+
+ protected class Context {
+ protected void write() throws TException {}
+
+ /**
+ * Returns whether the current value is a key in a map
+ */
+ protected boolean isMapKey() { return false; }
+ }
+
+ protected class ListContext extends Context {
+ protected boolean first_ = true;
+
+ protected void write() throws TException {
+ if (first_) {
+ first_ = false;
+ } else {
+ trans_.write(COMMA);
+ }
+ }
+ }
+
+ protected class StructContext extends Context {
+ protected boolean first_ = true;
+ protected boolean colon_ = true;
+
+ protected void write() throws TException {
+ if (first_) {
+ first_ = false;
+ colon_ = true;
+ } else {
+ trans_.write(colon_ ? COLON : COMMA);
+ colon_ = !colon_;
+ }
+ }
+ }
+
+ protected class MapContext extends StructContext {
+ protected boolean isKey = true;
+
+ @Override
+ protected void write() throws TException {
+ super.write();
+ isKey = !isKey;
+ }
+
+ protected boolean isMapKey() {
+ // we want to coerce map keys to json strings regardless
+ // of their type
+ return isKey;
+ }
+ }
+
+ protected final Context BASE_CONTEXT = new Context();
+
+ /**
+ * Stack of nested contexts that we may be in.
+ */
+ protected Stack<Context> writeContextStack_ = new Stack<Context>();
+
+ /**
+ * Current context that we are in
+ */
+ protected Context writeContext_ = BASE_CONTEXT;
+
+ /**
+ * Push a new write context onto the stack.
+ */
+ protected void pushWriteContext(Context c) {
+ writeContextStack_.push(writeContext_);
+ writeContext_ = c;
+ }
+
+ /**
+ * Pop the last write context off the stack
+ */
+ protected void popWriteContext() {
+ writeContext_ = writeContextStack_.pop();
+ }
+
+ /**
+ * Reset the write context stack to its initial state.
+ */
+ protected void resetWriteContext() {
+ while (!writeContextStack_.isEmpty()) {
+ popWriteContext();
+ }
+ }
+
+ /**
+ * Used to make sure that we are not encountering a map whose keys are containers
+ */
+ protected void assertContextIsNotMapKey(String invalidKeyType) throws CollectionMapKeyException {
+ if (writeContext_.isMapKey()) {
+ throw new CollectionMapKeyException("Cannot serialize a map with keys that are of type " + invalidKeyType);
+ }
+ }
+
+ /**
+ * Constructor
+ */
+ public TSimpleJSONProtocol(TTransport trans) {
+ super(trans);
+ }
+
+ @Override
+ public void writeMessageBegin(TMessage message) throws TException {
+ resetWriteContext(); // THRIFT-3743
+ trans_.write(LBRACKET);
+ pushWriteContext(new ListContext());
+ writeString(message.name);
+ writeByte(message.type);
+ writeI32(message.seqid);
+ }
+
+ @Override
+ public void writeMessageEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACKET);
+ }
+
+ @Override
+ public void writeStructBegin(TStruct struct) throws TException {
+ writeContext_.write();
+ trans_.write(LBRACE);
+ pushWriteContext(new StructContext());
+ }
+
+ @Override
+ public void writeStructEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACE);
+ }
+
+ @Override
+ public void writeFieldBegin(TField field) throws TException {
+ // Note that extra type information is omitted in JSON!
+ writeString(field.name);
+ }
+
+ @Override
+ public void writeFieldEnd() throws TException {}
+
+ @Override
+ public void writeFieldStop() throws TException {}
+
+ @Override
+ public void writeMapBegin(TMap map) throws TException {
+ assertContextIsNotMapKey(MAP);
+ writeContext_.write();
+ trans_.write(LBRACE);
+ pushWriteContext(new MapContext());
+ // No metadata!
+ }
+
+ @Override
+ public void writeMapEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACE);
+ }
+
+ @Override
+ public void writeListBegin(TList list) throws TException {
+ assertContextIsNotMapKey(LIST);
+ writeContext_.write();
+ trans_.write(LBRACKET);
+ pushWriteContext(new ListContext());
+ // No metadata!
+ }
+
+ @Override
+ public void writeListEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACKET);
+ }
+
+ @Override
+ public void writeSetBegin(TSet set) throws TException {
+ assertContextIsNotMapKey(SET);
+ writeContext_.write();
+ trans_.write(LBRACKET);
+ pushWriteContext(new ListContext());
+ // No metadata!
+ }
+
+ @Override
+ public void writeSetEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACKET);
+ }
+
+ @Override
+ public void writeBool(boolean b) throws TException {
+ writeByte(b ? (byte)1 : (byte)0);
+ }
+
+ @Override
+ public void writeByte(byte b) throws TException {
+ writeI32(b);
+ }
+
+ @Override
+ public void writeI16(short i16) throws TException {
+ writeI32(i16);
+ }
+
+ @Override
+ public void writeI32(int i32) throws TException {
+ if(writeContext_.isMapKey()) {
+ writeString(Integer.toString(i32));
+ } else {
+ writeContext_.write();
+ _writeStringData(Integer.toString(i32));
+ }
+ }
+
+ public void _writeStringData(String s) throws TException {
+ byte[] b = s.getBytes(StandardCharsets.UTF_8);
+ trans_.write(b);
+ }
+
+ @Override
+ public void writeI64(long i64) throws TException {
+ if(writeContext_.isMapKey()) {
+ writeString(Long.toString(i64));
+ } else {
+ writeContext_.write();
+ _writeStringData(Long.toString(i64));
+ }
+ }
+
+ @Override
+ public void writeDouble(double dub) throws TException {
+ if(writeContext_.isMapKey()) {
+ writeString(Double.toString(dub));
+ } else {
+ writeContext_.write();
+ _writeStringData(Double.toString(dub));
+ }
+ }
+
+ @Override
+ public void writeString(String str) throws TException {
+ writeContext_.write();
+ int length = str.length();
+ StringBuffer escape = new StringBuffer(length + 16);
+ escape.append(QUOTE);
+ for (int i = 0; i < length; ++i) {
+ char c = str.charAt(i);
+ switch (c) {
+ case '"':
+ case '\\':
+ escape.append('\\');
+ escape.append(c);
+ break;
+ case '\b':
+ escape.append('\\');
+ escape.append('b');
+ break;
+ case '\f':
+ escape.append('\\');
+ escape.append('f');
+ break;
+ case '\n':
+ escape.append('\\');
+ escape.append('n');
+ break;
+ case '\r':
+ escape.append('\\');
+ escape.append('r');
+ break;
+ case '\t':
+ escape.append('\\');
+ escape.append('t');
+ break;
+ default:
+ // Control characters! According to JSON RFC u0020 (space)
+ if (c < ' ') {
+ String hex = Integer.toHexString(c);
+ escape.append('\\');
+ escape.append('u');
+ for (int j = 4; j > hex.length(); --j) {
+ escape.append('0');
+ }
+ escape.append(hex);
+ } else {
+ escape.append(c);
+ }
+ break;
+ }
+ }
+ escape.append(QUOTE);
+ _writeStringData(escape.toString());
+ }
+
+ @Override
+ public void writeBinary(ByteBuffer bin) throws TException {
+ // TODO(mcslee): Fix this
+ writeString(new String(bin.array(), bin.position() + bin.arrayOffset(),
+ bin.limit() - bin.position() - bin.arrayOffset(),
+ StandardCharsets.UTF_8));
+ }
+
+ /**
+ * Reading methods.
+ */
+
+ @Override
+ public TMessage readMessageBegin() throws TException {
+ // TODO(mcslee): implement
+ return EMPTY_MESSAGE;
+ }
+
+ @Override
+ public void readMessageEnd() throws TException {}
+
+ @Override
+ public TStruct readStructBegin() throws TException {
+ // TODO(mcslee): implement
+ return ANONYMOUS_STRUCT;
+ }
+
+ @Override
+ public void readStructEnd() throws TException {}
+
+ @Override
+ public TField readFieldBegin() throws TException {
+ // TODO(mcslee): implement
+ return ANONYMOUS_FIELD;
+ }
+
+ @Override
+ public void readFieldEnd() throws TException {}
+
+ @Override
+ public TMap readMapBegin() throws TException {
+ // TODO(mcslee): implement
+ return EMPTY_MAP;
+ }
+
+ @Override
+ public void readMapEnd() throws TException {}
+
+ @Override
+ public TList readListBegin() throws TException {
+ // TODO(mcslee): implement
+ return EMPTY_LIST;
+ }
+
+ @Override
+ public void readListEnd() throws TException {}
+
+ @Override
+ public TSet readSetBegin() throws TException {
+ // TODO(mcslee): implement
+ return EMPTY_SET;
+ }
+
+ @Override
+ public void readSetEnd() throws TException {}
+
+ @Override
+ public boolean readBool() throws TException {
+ return (readByte() == 1);
+ }
+
+ @Override
+ public byte readByte() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ @Override
+ public short readI16() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ @Override
+ public int readI32() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ @Override
+ public long readI64() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ @Override
+ public double readDouble() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ @Override
+ public String readString() throws TException {
+ // TODO(mcslee): implement
+ return "";
+ }
+
+ public String readStringBody(int size) throws TException {
+ // TODO(mcslee): implement
+ return "";
+ }
+
+ @Override
+ public ByteBuffer readBinary() throws TException {
+ // TODO(mcslee): implement
+ return ByteBuffer.wrap(new byte[0]);
+ }
+
+ public static class CollectionMapKeyException extends TException {
+ public CollectionMapKeyException(String message) {
+ super(message);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TStruct.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TStruct.java
new file mode 100644
index 000000000..a0f79012a
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TStruct.java
@@ -0,0 +1,36 @@
+/*
+ * 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.thrift.protocol;
+
+/**
+ * Helper class that encapsulates struct metadata.
+ *
+ */
+public final class TStruct {
+ public TStruct() {
+ this("");
+ }
+
+ public TStruct(String n) {
+ name = n;
+ }
+
+ public final String name;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TTupleProtocol.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TTupleProtocol.java
new file mode 100644
index 000000000..74f5226c8
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TTupleProtocol.java
@@ -0,0 +1,98 @@
+/*
+ * 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.thrift.protocol;
+
+import java.util.BitSet;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.scheme.IScheme;
+import org.apache.thrift.scheme.TupleScheme;
+import org.apache.thrift.transport.TTransport;
+
+public final class TTupleProtocol extends TCompactProtocol {
+ public static class Factory implements TProtocolFactory {
+ public Factory() {}
+
+ public TProtocol getProtocol(TTransport trans) {
+ return new TTupleProtocol(trans);
+ }
+ }
+
+ public TTupleProtocol(TTransport transport) {
+ super(transport);
+ }
+
+ @Override
+ public Class<? extends IScheme> getScheme() {
+ return TupleScheme.class;
+ }
+
+ public void writeBitSet(BitSet bs, int vectorWidth) throws TException {
+ byte[] bytes = toByteArray(bs, vectorWidth);
+ for (byte b : bytes) {
+ writeByte(b);
+ }
+ }
+
+ public BitSet readBitSet(int i) throws TException {
+ int length = (int) Math.ceil(i/8.0);
+ byte[] bytes = new byte[length];
+ for (int j = 0; j < length; j++) {
+ bytes[j] = readByte();
+ }
+ BitSet bs = fromByteArray(bytes);
+ return bs;
+ }
+
+ /**
+ * Returns a bitset containing the values in bytes. The byte-ordering must be
+ * big-endian.
+ */
+ public static BitSet fromByteArray(byte[] bytes) {
+ BitSet bits = new BitSet();
+ for (int i = 0; i < bytes.length * 8; i++) {
+ if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
+ bits.set(i);
+ }
+ }
+ return bits;
+ }
+
+ /**
+ * Returns a byte array of at least length 1. The most significant bit in the
+ * result is guaranteed not to be a 1 (since BitSet does not support sign
+ * extension). The byte-ordering of the result is big-endian which means the
+ * most significant bit is in element 0. The bit at index 0 of the bit set is
+ * assumed to be the least significant bit.
+ *
+ * @param bits
+ * @param vectorWidth
+ * @return a byte array of at least length 1
+ */
+ public static byte[] toByteArray(BitSet bits, int vectorWidth) {
+ byte[] bytes = new byte[(int) Math.ceil(vectorWidth/8.0)];
+ for (int i = 0; i < bits.length(); i++) {
+ if (bits.get(i)) {
+ bytes[bytes.length - i / 8 - 1] |= 1 << (i % 8);
+ }
+ }
+ return bytes;
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TType.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TType.java
new file mode 100644
index 000000000..c3c1a0abd
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TType.java
@@ -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.thrift.protocol;
+
+/**
+ * Type constants in the Thrift protocol.
+ */
+public final class TType {
+ public static final byte STOP = 0;
+ public static final byte VOID = 1;
+ public static final byte BOOL = 2;
+ public static final byte BYTE = 3;
+ public static final byte DOUBLE = 4;
+ public static final byte I16 = 6;
+ public static final byte I32 = 8;
+ public static final byte I64 = 10;
+ public static final byte STRING = 11;
+ public static final byte STRUCT = 12;
+ public static final byte MAP = 13;
+ public static final byte SET = 14;
+ public static final byte LIST = 15;
+ public static final byte ENUM = 16;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/IScheme.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/IScheme.java
new file mode 100644
index 000000000..aa3550705
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/IScheme.java
@@ -0,0 +1,29 @@
+/*
+ * 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.thrift.scheme;
+
+import org.apache.thrift.TBase;
+
+public interface IScheme<T extends TBase> {
+
+ public void read(org.apache.thrift.protocol.TProtocol iproto, T struct) throws org.apache.thrift.TException;
+
+ public void write(org.apache.thrift.protocol.TProtocol oproto, T struct) throws org.apache.thrift.TException;
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/SchemeFactory.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/SchemeFactory.java
new file mode 100644
index 000000000..006a66805
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/SchemeFactory.java
@@ -0,0 +1,25 @@
+/*
+ * 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.thrift.scheme;
+
+public interface SchemeFactory {
+
+ public <S extends IScheme> S getScheme();
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/StandardScheme.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/StandardScheme.java
new file mode 100644
index 000000000..ffab04db6
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/StandardScheme.java
@@ -0,0 +1,25 @@
+/*
+ * 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.thrift.scheme;
+
+import org.apache.thrift.TBase;
+
+public abstract class StandardScheme<T extends TBase> implements IScheme<T> {
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/TupleScheme.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/TupleScheme.java
new file mode 100644
index 000000000..365242b11
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/scheme/TupleScheme.java
@@ -0,0 +1,25 @@
+/*
+ * 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.thrift.scheme;
+
+import org.apache.thrift.TBase;
+
+public abstract class TupleScheme<T extends TBase> implements IScheme<T> {
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java
new file mode 100644
index 000000000..8c206e427
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java
@@ -0,0 +1,618 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.thrift.TAsyncProcessor;
+import org.apache.thrift.TByteArrayOutputStream;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TIOStreamTransport;
+import org.apache.thrift.transport.TMemoryInputTransport;
+import org.apache.thrift.transport.TNonblockingServerTransport;
+import org.apache.thrift.transport.TNonblockingTransport;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Provides common methods and classes used by nonblocking TServer
+ * implementations.
+ */
+public abstract class AbstractNonblockingServer extends TServer {
+ protected final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
+
+ public static abstract class AbstractNonblockingServerArgs<T extends AbstractNonblockingServerArgs<T>> extends AbstractServerArgs<T> {
+ public long maxReadBufferBytes = 256 * 1024 * 1024;
+
+ public AbstractNonblockingServerArgs(TNonblockingServerTransport transport) {
+ super(transport);
+ transportFactory(new TFramedTransport.Factory());
+ }
+ }
+
+ /**
+ * The maximum amount of memory we will allocate to client IO buffers at a
+ * time. Without this limit, the server will gladly allocate client buffers
+ * right into an out of memory exception, rather than waiting.
+ */
+ final long MAX_READ_BUFFER_BYTES;
+
+ /**
+ * How many bytes are currently allocated to read buffers.
+ */
+ final AtomicLong readBufferBytesAllocated = new AtomicLong(0);
+
+ public AbstractNonblockingServer(AbstractNonblockingServerArgs args) {
+ super(args);
+ MAX_READ_BUFFER_BYTES = args.maxReadBufferBytes;
+ }
+
+ /**
+ * Begin accepting connections and processing invocations.
+ */
+ public void serve() {
+ // start any IO threads
+ if (!startThreads()) {
+ return;
+ }
+
+ // start listening, or exit
+ if (!startListening()) {
+ return;
+ }
+
+ setServing(true);
+
+ // this will block while we serve
+ waitForShutdown();
+
+ setServing(false);
+
+ // do a little cleanup
+ stopListening();
+ }
+
+ /**
+ * Starts any threads required for serving.
+ *
+ * @return true if everything went ok, false if threads could not be started.
+ */
+ protected abstract boolean startThreads();
+
+ /**
+ * A method that will block until when threads handling the serving have been
+ * shut down.
+ */
+ protected abstract void waitForShutdown();
+
+ /**
+ * Have the server transport start accepting connections.
+ *
+ * @return true if we started listening successfully, false if something went
+ * wrong.
+ */
+ protected boolean startListening() {
+ try {
+ serverTransport_.listen();
+ return true;
+ } catch (TTransportException ttx) {
+ LOGGER.error("Failed to start listening on server socket!", ttx);
+ return false;
+ }
+ }
+
+ /**
+ * Stop listening for connections.
+ */
+ protected void stopListening() {
+ serverTransport_.close();
+ }
+
+ /**
+ * Perform an invocation. This method could behave several different ways -
+ * invoke immediately inline, queue for separate execution, etc.
+ *
+ * @return true if invocation was successfully requested, which is not a
+ * guarantee that invocation has completed. False if the request
+ * failed.
+ */
+ protected abstract boolean requestInvoke(FrameBuffer frameBuffer);
+
+ /**
+ * An abstract thread that handles selecting on a set of transports and
+ * {@link FrameBuffer FrameBuffers} associated with selected keys
+ * corresponding to requests.
+ */
+ protected abstract class AbstractSelectThread extends Thread {
+ protected Selector selector;
+
+ // List of FrameBuffers that want to change their selection interests.
+ protected final Set<FrameBuffer> selectInterestChanges = new HashSet<FrameBuffer>();
+
+ public AbstractSelectThread() throws IOException {
+ this.selector = SelectorProvider.provider().openSelector();
+ }
+
+ /**
+ * If the selector is blocked, wake it up.
+ */
+ public void wakeupSelector() {
+ selector.wakeup();
+ }
+
+ /**
+ * Add FrameBuffer to the list of select interest changes and wake up the
+ * selector if it's blocked. When the select() call exits, it'll give the
+ * FrameBuffer a chance to change its interests.
+ */
+ public void requestSelectInterestChange(FrameBuffer frameBuffer) {
+ synchronized (selectInterestChanges) {
+ selectInterestChanges.add(frameBuffer);
+ }
+ // wakeup the selector, if it's currently blocked.
+ selector.wakeup();
+ }
+
+ /**
+ * Check to see if there are any FrameBuffers that have switched their
+ * interest type from read to write or vice versa.
+ */
+ protected void processInterestChanges() {
+ synchronized (selectInterestChanges) {
+ for (FrameBuffer fb : selectInterestChanges) {
+ fb.changeSelectInterests();
+ }
+ selectInterestChanges.clear();
+ }
+ }
+
+ /**
+ * Do the work required to read from a readable client. If the frame is
+ * fully read, then invoke the method call.
+ */
+ protected void handleRead(SelectionKey key) {
+ FrameBuffer buffer = (FrameBuffer) key.attachment();
+ if (!buffer.read()) {
+ cleanupSelectionKey(key);
+ return;
+ }
+
+ // if the buffer's frame read is complete, invoke the method.
+ if (buffer.isFrameFullyRead()) {
+ if (!requestInvoke(buffer)) {
+ cleanupSelectionKey(key);
+ }
+ }
+ }
+
+ /**
+ * Let a writable client get written, if there's data to be written.
+ */
+ protected void handleWrite(SelectionKey key) {
+ FrameBuffer buffer = (FrameBuffer) key.attachment();
+ if (!buffer.write()) {
+ cleanupSelectionKey(key);
+ }
+ }
+
+ /**
+ * Do connection-close cleanup on a given SelectionKey.
+ */
+ protected void cleanupSelectionKey(SelectionKey key) {
+ // remove the records from the two maps
+ FrameBuffer buffer = (FrameBuffer) key.attachment();
+ if (buffer != null) {
+ // close the buffer
+ buffer.close();
+ }
+ // cancel the selection key
+ key.cancel();
+ }
+ } // SelectThread
+
+ /**
+ * Possible states for the FrameBuffer state machine.
+ */
+ private enum FrameBufferState {
+ // in the midst of reading the frame size off the wire
+ READING_FRAME_SIZE,
+ // reading the actual frame data now, but not all the way done yet
+ READING_FRAME,
+ // completely read the frame, so an invocation can now happen
+ READ_FRAME_COMPLETE,
+ // waiting to get switched to listening for write events
+ AWAITING_REGISTER_WRITE,
+ // started writing response data, not fully complete yet
+ WRITING,
+ // another thread wants this framebuffer to go back to reading
+ AWAITING_REGISTER_READ,
+ // we want our transport and selection key invalidated in the selector
+ // thread
+ AWAITING_CLOSE
+ }
+
+ /**
+ * Class that implements a sort of state machine around the interaction with a
+ * client and an invoker. It manages reading the frame size and frame data,
+ * getting it handed off as wrapped transports, and then the writing of
+ * response data back to the client. In the process it manages flipping the
+ * read and write bits on the selection key for its client.
+ */
+ public class FrameBuffer {
+ private final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
+
+ // the actual transport hooked up to the client.
+ protected final TNonblockingTransport trans_;
+
+ // the SelectionKey that corresponds to our transport
+ protected final SelectionKey selectionKey_;
+
+ // the SelectThread that owns the registration of our transport
+ protected final AbstractSelectThread selectThread_;
+
+ // where in the process of reading/writing are we?
+ protected FrameBufferState state_ = FrameBufferState.READING_FRAME_SIZE;
+
+ // the ByteBuffer we'll be using to write and read, depending on the state
+ protected ByteBuffer buffer_;
+
+ protected final TByteArrayOutputStream response_;
+
+ // the frame that the TTransport should wrap.
+ protected final TMemoryInputTransport frameTrans_;
+
+ // the transport that should be used to connect to clients
+ protected final TTransport inTrans_;
+
+ protected final TTransport outTrans_;
+
+ // the input protocol to use on frames
+ protected final TProtocol inProt_;
+
+ // the output protocol to use on frames
+ protected final TProtocol outProt_;
+
+ // context associated with this connection
+ protected final ServerContext context_;
+
+ public FrameBuffer(final TNonblockingTransport trans,
+ final SelectionKey selectionKey,
+ final AbstractSelectThread selectThread) {
+ trans_ = trans;
+ selectionKey_ = selectionKey;
+ selectThread_ = selectThread;
+ buffer_ = ByteBuffer.allocate(4);
+
+ frameTrans_ = new TMemoryInputTransport();
+ response_ = new TByteArrayOutputStream();
+ inTrans_ = inputTransportFactory_.getTransport(frameTrans_);
+ outTrans_ = outputTransportFactory_.getTransport(new TIOStreamTransport(response_));
+ inProt_ = inputProtocolFactory_.getProtocol(inTrans_);
+ outProt_ = outputProtocolFactory_.getProtocol(outTrans_);
+
+ if (eventHandler_ != null) {
+ context_ = eventHandler_.createContext(inProt_, outProt_);
+ } else {
+ context_ = null;
+ }
+ }
+
+ /**
+ * Give this FrameBuffer a chance to read. The selector loop should have
+ * received a read event for this FrameBuffer.
+ *
+ * @return true if the connection should live on, false if it should be
+ * closed
+ */
+ public boolean read() {
+ if (state_ == FrameBufferState.READING_FRAME_SIZE) {
+ // try to read the frame size completely
+ if (!internalRead()) {
+ return false;
+ }
+
+ // if the frame size has been read completely, then prepare to read the
+ // actual frame.
+ if (buffer_.remaining() == 0) {
+ // pull out the frame size as an integer.
+ int frameSize = buffer_.getInt(0);
+ if (frameSize <= 0) {
+ LOGGER.error("Read an invalid frame size of " + frameSize
+ + ". Are you using TFramedTransport on the client side?");
+ return false;
+ }
+
+ // if this frame will always be too large for this server, log the
+ // error and close the connection.
+ if (frameSize > MAX_READ_BUFFER_BYTES) {
+ LOGGER.error("Read a frame size of " + frameSize
+ + ", which is bigger than the maximum allowable buffer size for ALL connections.");
+ return false;
+ }
+
+ // if this frame will push us over the memory limit, then return.
+ // with luck, more memory will free up the next time around.
+ if (readBufferBytesAllocated.get() + frameSize > MAX_READ_BUFFER_BYTES) {
+ return true;
+ }
+
+ // increment the amount of memory allocated to read buffers
+ readBufferBytesAllocated.addAndGet(frameSize + 4);
+
+ // reallocate the readbuffer as a frame-sized buffer
+ buffer_ = ByteBuffer.allocate(frameSize + 4);
+ buffer_.putInt(frameSize);
+
+ state_ = FrameBufferState.READING_FRAME;
+ } else {
+ // this skips the check of READING_FRAME state below, since we can't
+ // possibly go on to that state if there's data left to be read at
+ // this one.
+ return true;
+ }
+ }
+
+ // it is possible to fall through from the READING_FRAME_SIZE section
+ // to READING_FRAME if there's already some frame data available once
+ // READING_FRAME_SIZE is complete.
+
+ if (state_ == FrameBufferState.READING_FRAME) {
+ if (!internalRead()) {
+ return false;
+ }
+
+ // since we're already in the select loop here for sure, we can just
+ // modify our selection key directly.
+ if (buffer_.remaining() == 0) {
+ // get rid of the read select interests
+ selectionKey_.interestOps(0);
+ state_ = FrameBufferState.READ_FRAME_COMPLETE;
+ }
+
+ return true;
+ }
+
+ // if we fall through to this point, then the state must be invalid.
+ LOGGER.error("Read was called but state is invalid (" + state_ + ")");
+ return false;
+ }
+
+ /**
+ * Give this FrameBuffer a chance to write its output to the final client.
+ */
+ public boolean write() {
+ if (state_ == FrameBufferState.WRITING) {
+ try {
+ if (trans_.write(buffer_) < 0) {
+ return false;
+ }
+ } catch (IOException e) {
+ LOGGER.warn("Got an IOException during write!", e);
+ return false;
+ }
+
+ // we're done writing. now we need to switch back to reading.
+ if (buffer_.remaining() == 0) {
+ prepareRead();
+ }
+ return true;
+ }
+
+ LOGGER.error("Write was called, but state is invalid (" + state_ + ")");
+ return false;
+ }
+
+ /**
+ * Give this FrameBuffer a chance to set its interest to write, once data
+ * has come in.
+ */
+ public void changeSelectInterests() {
+ switch (state_) {
+ case AWAITING_REGISTER_WRITE:
+ // set the OP_WRITE interest
+ selectionKey_.interestOps(SelectionKey.OP_WRITE);
+ state_ = FrameBufferState.WRITING;
+ break;
+ case AWAITING_REGISTER_READ:
+ prepareRead();
+ break;
+ case AWAITING_CLOSE:
+ close();
+ selectionKey_.cancel();
+ break;
+ default:
+ LOGGER.error(
+ "changeSelectInterest was called, but state is invalid ({})",
+ state_);
+ }
+ }
+
+ /**
+ * Shut the connection down.
+ */
+ public void close() {
+ // if we're being closed due to an error, we might have allocated a
+ // buffer that we need to subtract for our memory accounting.
+ if (state_ == FrameBufferState.READING_FRAME ||
+ state_ == FrameBufferState.READ_FRAME_COMPLETE ||
+ state_ == FrameBufferState.AWAITING_CLOSE) {
+ readBufferBytesAllocated.addAndGet(-buffer_.array().length);
+ }
+ trans_.close();
+ if (eventHandler_ != null) {
+ eventHandler_.deleteContext(context_, inProt_, outProt_);
+ }
+ }
+
+ /**
+ * Check if this FrameBuffer has a full frame read.
+ */
+ public boolean isFrameFullyRead() {
+ return state_ == FrameBufferState.READ_FRAME_COMPLETE;
+ }
+
+ /**
+ * After the processor has processed the invocation, whatever thread is
+ * managing invocations should call this method on this FrameBuffer so we
+ * know it's time to start trying to write again. Also, if it turns out that
+ * there actually isn't any data in the response buffer, we'll skip trying
+ * to write and instead go back to reading.
+ */
+ public void responseReady() {
+ // the read buffer is definitely no longer in use, so we will decrement
+ // our read buffer count. we do this here as well as in close because
+ // we'd like to free this read memory up as quickly as possible for other
+ // clients.
+ readBufferBytesAllocated.addAndGet(-buffer_.array().length);
+
+ if (response_.len() == 0) {
+ // go straight to reading again. this was probably an oneway method
+ state_ = FrameBufferState.AWAITING_REGISTER_READ;
+ buffer_ = null;
+ } else {
+ buffer_ = ByteBuffer.wrap(response_.get(), 0, response_.len());
+
+ // set state that we're waiting to be switched to write. we do this
+ // asynchronously through requestSelectInterestChange() because there is
+ // a possibility that we're not in the main thread, and thus currently
+ // blocked in select(). (this functionality is in place for the sake of
+ // the HsHa server.)
+ state_ = FrameBufferState.AWAITING_REGISTER_WRITE;
+ }
+ requestSelectInterestChange();
+ }
+
+ /**
+ * Actually invoke the method signified by this FrameBuffer.
+ */
+ public void invoke() {
+ frameTrans_.reset(buffer_.array());
+ response_.reset();
+
+ try {
+ if (eventHandler_ != null) {
+ eventHandler_.processContext(context_, inTrans_, outTrans_);
+ }
+ processorFactory_.getProcessor(inTrans_).process(inProt_, outProt_);
+ responseReady();
+ return;
+ } catch (TException te) {
+ LOGGER.warn("Exception while invoking!", te);
+ } catch (Throwable t) {
+ LOGGER.error("Unexpected throwable while invoking!", t);
+ }
+ // This will only be reached when there is a throwable.
+ state_ = FrameBufferState.AWAITING_CLOSE;
+ requestSelectInterestChange();
+ }
+
+ /**
+ * Perform a read into buffer.
+ *
+ * @return true if the read succeeded, false if there was an error or the
+ * connection closed.
+ */
+ private boolean internalRead() {
+ try {
+ if (trans_.read(buffer_) < 0) {
+ return false;
+ }
+ return true;
+ } catch (IOException e) {
+ LOGGER.warn("Got an IOException in internalRead!", e);
+ return false;
+ }
+ }
+
+ /**
+ * We're done writing, so reset our interest ops and change state
+ * accordingly.
+ */
+ private void prepareRead() {
+ // we can set our interest directly without using the queue because
+ // we're in the select thread.
+ selectionKey_.interestOps(SelectionKey.OP_READ);
+ // get ready for another go-around
+ buffer_ = ByteBuffer.allocate(4);
+ state_ = FrameBufferState.READING_FRAME_SIZE;
+ }
+
+ /**
+ * When this FrameBuffer needs to change its select interests and execution
+ * might not be in its select thread, then this method will make sure the
+ * interest change gets done when the select thread wakes back up. When the
+ * current thread is this FrameBuffer's select thread, then it just does the
+ * interest change immediately.
+ */
+ protected void requestSelectInterestChange() {
+ if (Thread.currentThread() == this.selectThread_) {
+ changeSelectInterests();
+ } else {
+ this.selectThread_.requestSelectInterestChange(this);
+ }
+ }
+ } // FrameBuffer
+
+ public class AsyncFrameBuffer extends FrameBuffer {
+ public AsyncFrameBuffer(TNonblockingTransport trans, SelectionKey selectionKey, AbstractSelectThread selectThread) {
+ super(trans, selectionKey, selectThread);
+ }
+
+ public TProtocol getInputProtocol() {
+ return inProt_;
+ }
+
+ public TProtocol getOutputProtocol() {
+ return outProt_;
+ }
+
+
+ public void invoke() {
+ frameTrans_.reset(buffer_.array());
+ response_.reset();
+
+ try {
+ if (eventHandler_ != null) {
+ eventHandler_.processContext(context_, inTrans_, outTrans_);
+ }
+ ((TAsyncProcessor)processorFactory_.getProcessor(inTrans_)).process(this);
+ return;
+ } catch (TException te) {
+ LOGGER.warn("Exception while invoking!", te);
+ } catch (Throwable t) {
+ LOGGER.error("Unexpected throwable while invoking!", t);
+ }
+ // This will only be reached when there is a throwable.
+ state_ = FrameBufferState.AWAITING_CLOSE;
+ requestSelectInterestChange();
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/Invocation.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/Invocation.java
new file mode 100644
index 000000000..e8210f419
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/Invocation.java
@@ -0,0 +1,20 @@
+package org.apache.thrift.server;
+
+import org.apache.thrift.server.AbstractNonblockingServer.FrameBuffer;
+
+/**
+ * An Invocation represents a method call that is prepared to execute, given
+ * an idle worker thread. It contains the input and output protocols the
+ * thread's processor should use to perform the usual Thrift invocation.
+ */
+class Invocation implements Runnable {
+ private final FrameBuffer frameBuffer;
+
+ public Invocation(final FrameBuffer frameBuffer) {
+ this.frameBuffer = frameBuffer;
+ }
+
+ public void run() {
+ frameBuffer.invoke();
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/ServerContext.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/ServerContext.java
new file mode 100644
index 000000000..9b0b99eea
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/ServerContext.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Interface for storing server's connection context
+ */
+
+package org.apache.thrift.server;
+
+public interface ServerContext {}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java
new file mode 100644
index 000000000..75082c0f7
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java
@@ -0,0 +1,171 @@
+/*
+ * 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.thrift.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TIOStreamTransport;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * Servlet implementation class ThriftServer, that allows {@link TProcessor} and
+ * {@link TProtocolFactory} to be supplied after the {@link #init()} method has
+ * finished. <br>
+ * Subclasses must implement the abstract methods that return the TProcessor and
+ * two TProtocolFactory. Those methods are guaranteed to be called exactly once,
+ * and that {@link ServletContext} is available.
+ */
+public abstract class TExtensibleServlet extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ private TProcessor processor;
+
+ private TProtocolFactory inFactory;
+
+ private TProtocolFactory outFactory;
+
+ private Collection<Map.Entry<String, String>> customHeaders;
+
+ /**
+ * Returns the appropriate {@link TProcessor}. This will be called <b>once</b> just
+ * after the {@link #init()} method
+ *
+ * @return the appropriate {@link TProcessor}
+ */
+ protected abstract TProcessor getProcessor();
+
+ /**
+ * Returns the appropriate in {@link TProtocolFactory}. This will be called
+ * <b>once</b> just after the {@link #init()} method
+ *
+ * @return the appropriate in {@link TProtocolFactory}
+ */
+ protected abstract TProtocolFactory getInProtocolFactory();
+
+ /**
+ * Returns the appropriate out {@link TProtocolFactory}. This will be called
+ * <b>once</b> just after the {@link #init()} method
+ *
+ * @return the appropriate out {@link TProtocolFactory}
+ */
+ protected abstract TProtocolFactory getOutProtocolFactory();
+
+ @Override
+ public final void init(ServletConfig config) throws ServletException {
+ super.init(config); //no-args init() happens here
+ this.processor = getProcessor();
+ this.inFactory = getInProtocolFactory();
+ this.outFactory = getOutProtocolFactory();
+ this.customHeaders = new ArrayList<Map.Entry<String, String>>();
+
+ if (processor == null) {
+ throw new ServletException("processor must be set");
+ }
+ if (inFactory == null) {
+ throw new ServletException("inFactory must be set");
+ }
+ if (outFactory == null) {
+ throw new ServletException("outFactory must be set");
+ }
+ }
+
+ /**
+ * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ TTransport inTransport = null;
+ TTransport outTransport = null;
+
+ try {
+ response.setContentType("application/x-thrift");
+
+ if (null != this.customHeaders) {
+ for (Map.Entry<String, String> header : this.customHeaders) {
+ response.addHeader(header.getKey(), header.getValue());
+ }
+ }
+
+ InputStream in = request.getInputStream();
+ OutputStream out = response.getOutputStream();
+
+ TTransport transport = new TIOStreamTransport(in, out);
+ inTransport = transport;
+ outTransport = transport;
+
+ TProtocol inProtocol = inFactory.getProtocol(inTransport);
+ TProtocol outProtocol = inFactory.getProtocol(outTransport);
+
+ processor.process(inProtocol, outProtocol);
+ out.flush();
+ } catch (TException te) {
+ throw new ServletException(te);
+ }
+ }
+
+ /**
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ doPost(req, resp);
+ }
+
+ public void addCustomHeader(final String key, final String value) {
+ this.customHeaders.add(new Map.Entry<String, String>() {
+ public String getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String setValue(String value) {
+ return null;
+ }
+ });
+ }
+
+ public void setCustomHeaders(Collection<Map.Entry<String, String>> headers) {
+ this.customHeaders.clear();
+ this.customHeaders.addAll(headers);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/THsHaServer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/THsHaServer.java
new file mode 100644
index 000000000..4c5d7b5b5
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/THsHaServer.java
@@ -0,0 +1,204 @@
+/*
+ * 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.thrift.server;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.thrift.transport.TNonblockingServerTransport;
+
+/**
+ * An extension of the TNonblockingServer to a Half-Sync/Half-Async server.
+ * Like TNonblockingServer, it relies on the use of TFramedTransport.
+ */
+public class THsHaServer extends TNonblockingServer {
+
+ public static class Args extends AbstractNonblockingServerArgs<Args> {
+ public int minWorkerThreads = 5;
+ public int maxWorkerThreads = Integer.MAX_VALUE;
+ private int stopTimeoutVal = 60;
+ private TimeUnit stopTimeoutUnit = TimeUnit.SECONDS;
+ private ExecutorService executorService = null;
+
+ public Args(TNonblockingServerTransport transport) {
+ super(transport);
+ }
+
+
+ /**
+ * Sets the min and max threads.
+ *
+ * @deprecated use {@link #minWorkerThreads(int)} and {@link #maxWorkerThreads(int)} instead.
+ */
+ @Deprecated
+ public Args workerThreads(int n) {
+ minWorkerThreads = n;
+ maxWorkerThreads = n;
+ return this;
+ }
+
+ /**
+ * @return what the min threads was set to.
+ * @deprecated use {@link #getMinWorkerThreads()} and {@link #getMaxWorkerThreads()} instead.
+ */
+ @Deprecated
+ public int getWorkerThreads() {
+ return minWorkerThreads;
+ }
+
+ public Args minWorkerThreads(int n) {
+ minWorkerThreads = n;
+ return this;
+ }
+
+ public Args maxWorkerThreads(int n) {
+ maxWorkerThreads = n;
+ return this;
+ }
+
+ public int getMinWorkerThreads() {
+ return minWorkerThreads;
+ }
+
+ public int getMaxWorkerThreads() {
+ return maxWorkerThreads;
+ }
+
+ public int getStopTimeoutVal() {
+ return stopTimeoutVal;
+ }
+
+ public Args stopTimeoutVal(int stopTimeoutVal) {
+ this.stopTimeoutVal = stopTimeoutVal;
+ return this;
+ }
+
+ public TimeUnit getStopTimeoutUnit() {
+ return stopTimeoutUnit;
+ }
+
+ public Args stopTimeoutUnit(TimeUnit stopTimeoutUnit) {
+ this.stopTimeoutUnit = stopTimeoutUnit;
+ return this;
+ }
+
+ public ExecutorService getExecutorService() {
+ return executorService;
+ }
+
+ public Args executorService(ExecutorService executorService) {
+ this.executorService = executorService;
+ return this;
+ }
+ }
+
+
+ // This wraps all the functionality of queueing and thread pool management
+ // for the passing of Invocations from the Selector to workers.
+ private final ExecutorService invoker;
+
+ private final Args args;
+
+ /**
+ * Create the server with the specified Args configuration
+ */
+ public THsHaServer(Args args) {
+ super(args);
+
+ invoker = args.executorService == null ? createInvokerPool(args) : args.executorService;
+ this.args = args;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void waitForShutdown() {
+ joinSelector();
+ gracefullyShutdownInvokerPool();
+ }
+
+ /**
+ * Helper to create an invoker pool
+ */
+ protected static ExecutorService createInvokerPool(Args options) {
+ int minWorkerThreads = options.minWorkerThreads;
+ int maxWorkerThreads = options.maxWorkerThreads;
+ int stopTimeoutVal = options.stopTimeoutVal;
+ TimeUnit stopTimeoutUnit = options.stopTimeoutUnit;
+
+ LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
+ ExecutorService invoker = new ThreadPoolExecutor(minWorkerThreads,
+ maxWorkerThreads, stopTimeoutVal, stopTimeoutUnit, queue);
+
+ return invoker;
+ }
+
+ protected ExecutorService getInvoker() {
+ return invoker;
+ }
+
+ protected void gracefullyShutdownInvokerPool() {
+ // try to gracefully shut down the executor service
+ invoker.shutdown();
+
+ // Loop until awaitTermination finally does return without a interrupted
+ // exception. If we don't do this, then we'll shut down prematurely. We want
+ // to let the executorService clear it's task queue, closing client sockets
+ // appropriately.
+ long timeoutMS = args.stopTimeoutUnit.toMillis(args.stopTimeoutVal);
+ long now = System.currentTimeMillis();
+ while (timeoutMS >= 0) {
+ try {
+ invoker.awaitTermination(timeoutMS, TimeUnit.MILLISECONDS);
+ break;
+ } catch (InterruptedException ix) {
+ long newnow = System.currentTimeMillis();
+ timeoutMS -= (newnow - now);
+ now = newnow;
+ }
+ }
+ }
+
+ /**
+ * We override the standard invoke method here to queue the invocation for
+ * invoker service instead of immediately invoking. The thread pool takes care
+ * of the rest.
+ */
+ @Override
+ protected boolean requestInvoke(FrameBuffer frameBuffer) {
+ try {
+ Runnable invocation = getRunnable(frameBuffer);
+ invoker.execute(invocation);
+ return true;
+ } catch (RejectedExecutionException rx) {
+ LOGGER.warn("ExecutorService rejected execution!", rx);
+ return false;
+ }
+ }
+
+ protected Runnable getRunnable(FrameBuffer frameBuffer){
+ return new Invocation(frameBuffer);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TNonblockingServer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TNonblockingServer.java
new file mode 100644
index 000000000..79610b0f7
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TNonblockingServer.java
@@ -0,0 +1,247 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.thrift.transport.TNonblockingServerTransport;
+import org.apache.thrift.transport.TNonblockingTransport;
+import org.apache.thrift.transport.TTransportException;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.util.Iterator;
+
+/**
+ * A nonblocking TServer implementation. This allows for fairness amongst all
+ * connected clients in terms of invocations.
+ *
+ * This server is inherently single-threaded. If you want a limited thread pool
+ * coupled with invocation-fairness, see THsHaServer.
+ *
+ * To use this server, you MUST use a TFramedTransport at the outermost
+ * transport, otherwise this server will be unable to determine when a whole
+ * method call has been read off the wire. Clients must also use TFramedTransport.
+ */
+public class TNonblockingServer extends AbstractNonblockingServer {
+
+ public static class Args extends AbstractNonblockingServerArgs<Args> {
+ public Args(TNonblockingServerTransport transport) {
+ super(transport);
+ }
+ }
+
+ private SelectAcceptThread selectAcceptThread_;
+
+ public TNonblockingServer(AbstractNonblockingServerArgs args) {
+ super(args);
+ }
+
+
+ /**
+ * Start the selector thread to deal with accepts and client messages.
+ *
+ * @return true if everything went ok, false if we couldn't start for some
+ * reason.
+ */
+ @Override
+ protected boolean startThreads() {
+ // start the selector
+ try {
+ selectAcceptThread_ = new SelectAcceptThread((TNonblockingServerTransport)serverTransport_);
+ selectAcceptThread_.start();
+ return true;
+ } catch (IOException e) {
+ LOGGER.error("Failed to start selector thread!", e);
+ return false;
+ }
+ }
+
+ @Override
+ protected void waitForShutdown() {
+ joinSelector();
+ }
+
+ /**
+ * Block until the selector thread exits.
+ */
+ protected void joinSelector() {
+ // wait until the selector thread exits
+ try {
+ selectAcceptThread_.join();
+ } catch (InterruptedException e) {
+ LOGGER.debug("Interrupted while waiting for accept thread", e);
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ /**
+ * Stop serving and shut everything down.
+ */
+ @Override
+ public void stop() {
+ stopped_ = true;
+ if (selectAcceptThread_ != null) {
+ selectAcceptThread_.wakeupSelector();
+ }
+ }
+
+ /**
+ * Perform an invocation. This method could behave several different ways
+ * - invoke immediately inline, queue for separate execution, etc.
+ */
+ @Override
+ protected boolean requestInvoke(FrameBuffer frameBuffer) {
+ frameBuffer.invoke();
+ return true;
+ }
+
+
+ public boolean isStopped() {
+ return selectAcceptThread_.isStopped();
+ }
+
+ /**
+ * The thread that will be doing all the selecting, managing new connections
+ * and those that still need to be read.
+ */
+ protected class SelectAcceptThread extends AbstractSelectThread {
+
+ // The server transport on which new client transports will be accepted
+ private final TNonblockingServerTransport serverTransport;
+
+ /**
+ * Set up the thread that will handle the non-blocking accepts, reads, and
+ * writes.
+ */
+ public SelectAcceptThread(final TNonblockingServerTransport serverTransport)
+ throws IOException {
+ this.serverTransport = serverTransport;
+ serverTransport.registerSelector(selector);
+ }
+
+ public boolean isStopped() {
+ return stopped_;
+ }
+
+ /**
+ * The work loop. Handles both selecting (all IO operations) and managing
+ * the selection preferences of all existing connections.
+ */
+ public void run() {
+ try {
+ if (eventHandler_ != null) {
+ eventHandler_.preServe();
+ }
+
+ while (!stopped_) {
+ select();
+ processInterestChanges();
+ }
+ for (SelectionKey selectionKey : selector.keys()) {
+ cleanupSelectionKey(selectionKey);
+ }
+ } catch (Throwable t) {
+ LOGGER.error("run() exiting due to uncaught error", t);
+ } finally {
+ try {
+ selector.close();
+ } catch (IOException e) {
+ LOGGER.error("Got an IOException while closing selector!", e);
+ }
+ stopped_ = true;
+ }
+ }
+
+ /**
+ * Select and process IO events appropriately:
+ * If there are connections to be accepted, accept them.
+ * If there are existing connections with data waiting to be read, read it,
+ * buffering until a whole frame has been read.
+ * If there are any pending responses, buffer them until their target client
+ * is available, and then send the data.
+ */
+ private void select() {
+ try {
+ // wait for io events.
+ selector.select();
+
+ // process the io events we received
+ Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
+ while (!stopped_ && selectedKeys.hasNext()) {
+ SelectionKey key = selectedKeys.next();
+ selectedKeys.remove();
+
+ // skip if not valid
+ if (!key.isValid()) {
+ cleanupSelectionKey(key);
+ continue;
+ }
+
+ // if the key is marked Accept, then it has to be the server
+ // transport.
+ if (key.isAcceptable()) {
+ handleAccept();
+ } else if (key.isReadable()) {
+ // deal with reads
+ handleRead(key);
+ } else if (key.isWritable()) {
+ // deal with writes
+ handleWrite(key);
+ } else {
+ LOGGER.warn("Unexpected state in select! " + key.interestOps());
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.warn("Got an IOException while selecting!", e);
+ }
+ }
+
+ protected FrameBuffer createFrameBuffer(final TNonblockingTransport trans,
+ final SelectionKey selectionKey,
+ final AbstractSelectThread selectThread) {
+ return processorFactory_.isAsyncProcessor() ?
+ new AsyncFrameBuffer(trans, selectionKey, selectThread) :
+ new FrameBuffer(trans, selectionKey, selectThread);
+ }
+
+ /**
+ * Accept a new connection.
+ */
+ private void handleAccept() throws IOException {
+ SelectionKey clientKey = null;
+ TNonblockingTransport client = null;
+ try {
+ // accept the connection
+ client = (TNonblockingTransport)serverTransport.accept();
+ clientKey = client.registerSelector(selector, SelectionKey.OP_READ);
+
+ // add this key to the map
+ FrameBuffer frameBuffer = createFrameBuffer(client, clientKey, SelectAcceptThread.this);
+
+ clientKey.attach(frameBuffer);
+ } catch (TTransportException tte) {
+ // something went wrong accepting.
+ LOGGER.warn("Exception trying to accept!", tte);
+ if (clientKey != null) cleanupSelectionKey(clientKey);
+ if (client != null) client.close();
+ }
+ }
+ } // SelectAcceptThread
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServer.java
new file mode 100644
index 000000000..bac06b26b
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServer.java
@@ -0,0 +1,177 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.TProcessorFactory;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TServerTransport;
+import org.apache.thrift.transport.TTransportFactory;
+
+/**
+ * Generic interface for a Thrift server.
+ *
+ */
+public abstract class TServer {
+
+ public static class Args extends AbstractServerArgs<Args> {
+ public Args(TServerTransport transport) {
+ super(transport);
+ }
+ }
+
+ public static abstract class AbstractServerArgs<T extends AbstractServerArgs<T>> {
+ final TServerTransport serverTransport;
+ TProcessorFactory processorFactory;
+ TTransportFactory inputTransportFactory = new TTransportFactory();
+ TTransportFactory outputTransportFactory = new TTransportFactory();
+ TProtocolFactory inputProtocolFactory = new TBinaryProtocol.Factory();
+ TProtocolFactory outputProtocolFactory = new TBinaryProtocol.Factory();
+
+ public AbstractServerArgs(TServerTransport transport) {
+ serverTransport = transport;
+ }
+
+ public T processorFactory(TProcessorFactory factory) {
+ this.processorFactory = factory;
+ return (T) this;
+ }
+
+ public T processor(TProcessor processor) {
+ this.processorFactory = new TProcessorFactory(processor);
+ return (T) this;
+ }
+
+ public T transportFactory(TTransportFactory factory) {
+ this.inputTransportFactory = factory;
+ this.outputTransportFactory = factory;
+ return (T) this;
+ }
+
+ public T inputTransportFactory(TTransportFactory factory) {
+ this.inputTransportFactory = factory;
+ return (T) this;
+ }
+
+ public T outputTransportFactory(TTransportFactory factory) {
+ this.outputTransportFactory = factory;
+ return (T) this;
+ }
+
+ public T protocolFactory(TProtocolFactory factory) {
+ this.inputProtocolFactory = factory;
+ this.outputProtocolFactory = factory;
+ return (T) this;
+ }
+
+ public T inputProtocolFactory(TProtocolFactory factory) {
+ this.inputProtocolFactory = factory;
+ return (T) this;
+ }
+
+ public T outputProtocolFactory(TProtocolFactory factory) {
+ this.outputProtocolFactory = factory;
+ return (T) this;
+ }
+ }
+
+ /**
+ * Core processor
+ */
+ protected TProcessorFactory processorFactory_;
+
+ /**
+ * Server transport
+ */
+ protected TServerTransport serverTransport_;
+
+ /**
+ * Input Transport Factory
+ */
+ protected TTransportFactory inputTransportFactory_;
+
+ /**
+ * Output Transport Factory
+ */
+ protected TTransportFactory outputTransportFactory_;
+
+ /**
+ * Input Protocol Factory
+ */
+ protected TProtocolFactory inputProtocolFactory_;
+
+ /**
+ * Output Protocol Factory
+ */
+ protected TProtocolFactory outputProtocolFactory_;
+
+ private volatile boolean isServing;
+
+ protected TServerEventHandler eventHandler_;
+
+ // Flag for stopping the server
+ // Please see THRIFT-1795 for the usage of this flag
+ protected volatile boolean stopped_ = false;
+
+ protected TServer(AbstractServerArgs args) {
+ processorFactory_ = args.processorFactory;
+ serverTransport_ = args.serverTransport;
+ inputTransportFactory_ = args.inputTransportFactory;
+ outputTransportFactory_ = args.outputTransportFactory;
+ inputProtocolFactory_ = args.inputProtocolFactory;
+ outputProtocolFactory_ = args.outputProtocolFactory;
+ }
+
+ /**
+ * The run method fires up the server and gets things going.
+ */
+ public abstract void serve();
+
+ /**
+ * Stop the server. This is optional on a per-implementation basis. Not
+ * all servers are required to be cleanly stoppable.
+ */
+ public void stop() {}
+
+ public boolean isServing() {
+ return isServing;
+ }
+
+ protected void setServing(boolean serving) {
+ isServing = serving;
+ }
+
+ public void setServerEventHandler(TServerEventHandler eventHandler) {
+ eventHandler_ = eventHandler;
+ }
+
+ public TServerEventHandler getEventHandler() {
+ return eventHandler_;
+ }
+
+ public boolean getShouldStop() {
+ return this.stopped_;
+ }
+
+ public void setShouldStop(boolean shouldStop) {
+ this.stopped_ = shouldStop;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServerEventHandler.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServerEventHandler.java
new file mode 100644
index 000000000..f069b9bfb
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServerEventHandler.java
@@ -0,0 +1,59 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * Interface that can handle events from the server core. To
+ * use this you should subclass it and implement the methods that you care
+ * about. Your subclass can also store local data that you may care about,
+ * such as additional "arguments" to these methods (stored in the object
+ * instance's state).
+ */
+public interface TServerEventHandler {
+
+ /**
+ * Called before the server begins.
+ */
+ void preServe();
+
+ /**
+ * Called when a new client has connected and is about to being processing.
+ */
+ ServerContext createContext(TProtocol input,
+ TProtocol output);
+
+ /**
+ * Called when a client has finished request-handling to delete server
+ * context.
+ */
+ void deleteContext(ServerContext serverContext,
+ TProtocol input,
+ TProtocol output);
+
+ /**
+ * Called when a client is about to call the processor.
+ */
+ void processContext(ServerContext serverContext,
+ TTransport inputTransport, TTransport outputTransport);
+
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServlet.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServlet.java
new file mode 100644
index 000000000..c1ab9df55
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TServlet.java
@@ -0,0 +1,119 @@
+package org.apache.thrift.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TIOStreamTransport;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * Servlet implementation class ThriftServer
+ */
+public class TServlet extends HttpServlet {
+
+ private final TProcessor processor;
+
+ private final TProtocolFactory inProtocolFactory;
+
+ private final TProtocolFactory outProtocolFactory;
+
+ private final Collection<Map.Entry<String, String>> customHeaders;
+
+ /**
+ * @see HttpServlet#HttpServlet()
+ */
+ public TServlet(TProcessor processor, TProtocolFactory inProtocolFactory,
+ TProtocolFactory outProtocolFactory) {
+ super();
+ this.processor = processor;
+ this.inProtocolFactory = inProtocolFactory;
+ this.outProtocolFactory = outProtocolFactory;
+ this.customHeaders = new ArrayList<Map.Entry<String, String>>();
+ }
+
+ /**
+ * @see HttpServlet#HttpServlet()
+ */
+ public TServlet(TProcessor processor, TProtocolFactory protocolFactory) {
+ this(processor, protocolFactory, protocolFactory);
+ }
+
+ /**
+ * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+
+ TTransport inTransport = null;
+ TTransport outTransport = null;
+
+ try {
+ response.setContentType("application/x-thrift");
+
+ if (null != this.customHeaders) {
+ for (Map.Entry<String, String> header : this.customHeaders) {
+ response.addHeader(header.getKey(), header.getValue());
+ }
+ }
+ InputStream in = request.getInputStream();
+ OutputStream out = response.getOutputStream();
+
+ TTransport transport = new TIOStreamTransport(in, out);
+ inTransport = transport;
+ outTransport = transport;
+
+ TProtocol inProtocol = inProtocolFactory.getProtocol(inTransport);
+ TProtocol outProtocol = outProtocolFactory.getProtocol(outTransport);
+
+ processor.process(inProtocol, outProtocol);
+ out.flush();
+ } catch (TException te) {
+ throw new ServletException(te);
+ }
+ }
+
+ /**
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ doPost(request, response);
+ }
+
+ public void addCustomHeader(final String key, final String value) {
+ this.customHeaders.add(new Map.Entry<String, String>() {
+ public String getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String setValue(String value) {
+ return null;
+ }
+ });
+ }
+
+ public void setCustomHeaders(Collection<Map.Entry<String, String>> headers) {
+ this.customHeaders.clear();
+ this.customHeaders.addAll(headers);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TSimpleServer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TSimpleServer.java
new file mode 100644
index 000000000..13501efc6
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TSimpleServer.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.thrift.server;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Simple singlethreaded server for testing.
+ *
+ */
+public class TSimpleServer extends TServer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TSimpleServer.class.getName());
+
+ public TSimpleServer(AbstractServerArgs args) {
+ super(args);
+ }
+
+ public void serve() {
+ try {
+ serverTransport_.listen();
+ } catch (TTransportException ttx) {
+ LOGGER.error("Error occurred during listening.", ttx);
+ return;
+ }
+
+ // Run the preServe event
+ if (eventHandler_ != null) {
+ eventHandler_.preServe();
+ }
+
+ setServing(true);
+
+ while (!stopped_) {
+ TTransport client = null;
+ TProcessor processor = null;
+ TTransport inputTransport = null;
+ TTransport outputTransport = null;
+ TProtocol inputProtocol = null;
+ TProtocol outputProtocol = null;
+ ServerContext connectionContext = null;
+ try {
+ client = serverTransport_.accept();
+ if (client != null) {
+ processor = processorFactory_.getProcessor(client);
+ inputTransport = inputTransportFactory_.getTransport(client);
+ outputTransport = outputTransportFactory_.getTransport(client);
+ inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);
+ outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);
+ if (eventHandler_ != null) {
+ connectionContext = eventHandler_.createContext(inputProtocol, outputProtocol);
+ }
+ while (true) {
+ if (eventHandler_ != null) {
+ eventHandler_.processContext(connectionContext, inputTransport, outputTransport);
+ }
+ processor.process(inputProtocol, outputProtocol);
+ }
+ }
+ } catch (TTransportException ttx) {
+ // Client died, just move on
+ } catch (TException tx) {
+ if (!stopped_) {
+ LOGGER.error("Thrift error occurred during processing of message.", tx);
+ }
+ } catch (Exception x) {
+ if (!stopped_) {
+ LOGGER.error("Error occurred during processing of message.", x);
+ }
+ }
+
+ if (eventHandler_ != null) {
+ eventHandler_.deleteContext(connectionContext, inputProtocol, outputProtocol);
+ }
+
+ if (inputTransport != null) {
+ inputTransport.close();
+ }
+
+ if (outputTransport != null) {
+ outputTransport.close();
+ }
+
+ }
+ setServing(false);
+ }
+
+ public void stop() {
+ stopped_ = true;
+ serverTransport_.interrupt();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java
new file mode 100644
index 000000000..87e873381
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java
@@ -0,0 +1,359 @@
+/*
+ * 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.thrift.server;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TServerTransport;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Server which uses Java's built in ThreadPool management to spawn off
+ * a worker pool that
+ *
+ */
+public class TThreadPoolServer extends TServer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TThreadPoolServer.class.getName());
+
+ public static class Args extends AbstractServerArgs<Args> {
+ public int minWorkerThreads = 5;
+ public int maxWorkerThreads = Integer.MAX_VALUE;
+ public ExecutorService executorService;
+ public int stopTimeoutVal = 60;
+ public TimeUnit stopTimeoutUnit = TimeUnit.SECONDS;
+ public int requestTimeout = 20;
+ public TimeUnit requestTimeoutUnit = TimeUnit.SECONDS;
+ public int beBackoffSlotLength = 100;
+ public TimeUnit beBackoffSlotLengthUnit = TimeUnit.MILLISECONDS;
+
+ public Args(TServerTransport transport) {
+ super(transport);
+ }
+
+ public Args minWorkerThreads(int n) {
+ minWorkerThreads = n;
+ return this;
+ }
+
+ public Args maxWorkerThreads(int n) {
+ maxWorkerThreads = n;
+ return this;
+ }
+
+ public Args stopTimeoutVal(int n) {
+ stopTimeoutVal = n;
+ return this;
+ }
+
+ public Args stopTimeoutUnit(TimeUnit tu) {
+ stopTimeoutUnit = tu;
+ return this;
+ }
+
+ public Args requestTimeout(int n) {
+ requestTimeout = n;
+ return this;
+ }
+
+ public Args requestTimeoutUnit(TimeUnit tu) {
+ requestTimeoutUnit = tu;
+ return this;
+ }
+ //Binary exponential backoff slot length
+ public Args beBackoffSlotLength(int n) {
+ beBackoffSlotLength = n;
+ return this;
+ }
+
+ //Binary exponential backoff slot time unit
+ public Args beBackoffSlotLengthUnit(TimeUnit tu) {
+ beBackoffSlotLengthUnit = tu;
+ return this;
+ }
+
+ public Args executorService(ExecutorService executorService) {
+ this.executorService = executorService;
+ return this;
+ }
+ }
+
+ // Executor service for handling client connections
+ private ExecutorService executorService_;
+
+ private final TimeUnit stopTimeoutUnit;
+
+ private final long stopTimeoutVal;
+
+ private final TimeUnit requestTimeoutUnit;
+
+ private final long requestTimeout;
+
+ private final long beBackoffSlotInMillis;
+
+ private Random random = new Random(System.currentTimeMillis());
+
+ public TThreadPoolServer(Args args) {
+ super(args);
+
+ stopTimeoutUnit = args.stopTimeoutUnit;
+ stopTimeoutVal = args.stopTimeoutVal;
+ requestTimeoutUnit = args.requestTimeoutUnit;
+ requestTimeout = args.requestTimeout;
+ beBackoffSlotInMillis = args.beBackoffSlotLengthUnit.toMillis(args.beBackoffSlotLength);
+
+ executorService_ = args.executorService != null ?
+ args.executorService : createDefaultExecutorService(args);
+ }
+
+ private static ExecutorService createDefaultExecutorService(Args args) {
+ SynchronousQueue<Runnable> executorQueue =
+ new SynchronousQueue<Runnable>();
+ return new ThreadPoolExecutor(args.minWorkerThreads,
+ args.maxWorkerThreads,
+ args.stopTimeoutVal,
+ args.stopTimeoutUnit,
+ executorQueue);
+ }
+
+ protected ExecutorService getExecutorService() {
+ return executorService_;
+ }
+
+ protected boolean preServe() {
+ try {
+ serverTransport_.listen();
+ } catch (TTransportException ttx) {
+ LOGGER.error("Error occurred during listening.", ttx);
+ return false;
+ }
+
+ // Run the preServe event
+ if (eventHandler_ != null) {
+ eventHandler_.preServe();
+ }
+ stopped_ = false;
+ setServing(true);
+
+ return true;
+ }
+
+ public void serve() {
+ if (!preServe()) {
+ return;
+ }
+
+ execute();
+ waitForShutdown();
+
+ setServing(false);
+ }
+
+ protected void execute() {
+ int failureCount = 0;
+ while (!stopped_) {
+ try {
+ TTransport client = serverTransport_.accept();
+ WorkerProcess wp = new WorkerProcess(client);
+
+ int retryCount = 0;
+ long remainTimeInMillis = requestTimeoutUnit.toMillis(requestTimeout);
+ while(true) {
+ try {
+ executorService_.execute(wp);
+ break;
+ } catch(Throwable t) {
+ if (t instanceof RejectedExecutionException) {
+ retryCount++;
+ try {
+ if (remainTimeInMillis > 0) {
+ //do a truncated 20 binary exponential backoff sleep
+ long sleepTimeInMillis = ((long) (random.nextDouble() *
+ (1L << Math.min(retryCount, 20)))) * beBackoffSlotInMillis;
+ sleepTimeInMillis = Math.min(sleepTimeInMillis, remainTimeInMillis);
+ TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis);
+ remainTimeInMillis = remainTimeInMillis - sleepTimeInMillis;
+ } else {
+ client.close();
+ wp = null;
+ LOGGER.warn("Task has been rejected by ExecutorService " + retryCount
+ + " times till timedout, reason: " + t);
+ break;
+ }
+ } catch (InterruptedException e) {
+ LOGGER.warn("Interrupted while waiting to place client on executor queue.");
+ Thread.currentThread().interrupt();
+ break;
+ }
+ } else if (t instanceof Error) {
+ LOGGER.error("ExecutorService threw error: " + t, t);
+ throw (Error)t;
+ } else {
+ //for other possible runtime errors from ExecutorService, should also not kill serve
+ LOGGER.warn("ExecutorService threw error: " + t, t);
+ break;
+ }
+ }
+ }
+ } catch (TTransportException ttx) {
+ if (!stopped_) {
+ ++failureCount;
+ LOGGER.warn("Transport error occurred during acceptance of message.", ttx);
+ }
+ }
+ }
+ }
+
+ protected void waitForShutdown() {
+ executorService_.shutdown();
+
+ // Loop until awaitTermination finally does return without a interrupted
+ // exception. If we don't do this, then we'll shut down prematurely. We want
+ // to let the executorService clear it's task queue, closing client sockets
+ // appropriately.
+ long timeoutMS = stopTimeoutUnit.toMillis(stopTimeoutVal);
+ long now = System.currentTimeMillis();
+ while (timeoutMS >= 0) {
+ try {
+ executorService_.awaitTermination(timeoutMS, TimeUnit.MILLISECONDS);
+ break;
+ } catch (InterruptedException ix) {
+ long newnow = System.currentTimeMillis();
+ timeoutMS -= (newnow - now);
+ now = newnow;
+ }
+ }
+ }
+
+ public void stop() {
+ stopped_ = true;
+ serverTransport_.interrupt();
+ }
+
+ private class WorkerProcess implements Runnable {
+
+ /**
+ * Client that this services.
+ */
+ private TTransport client_;
+
+ /**
+ * Default constructor.
+ *
+ * @param client Transport to process
+ */
+ private WorkerProcess(TTransport client) {
+ client_ = client;
+ }
+
+ /**
+ * Loops on processing a client forever
+ */
+ public void run() {
+ TProcessor processor = null;
+ TTransport inputTransport = null;
+ TTransport outputTransport = null;
+ TProtocol inputProtocol = null;
+ TProtocol outputProtocol = null;
+
+ TServerEventHandler eventHandler = null;
+ ServerContext connectionContext = null;
+
+ try {
+ processor = processorFactory_.getProcessor(client_);
+ inputTransport = inputTransportFactory_.getTransport(client_);
+ outputTransport = outputTransportFactory_.getTransport(client_);
+ inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);
+ outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);
+
+ eventHandler = getEventHandler();
+ if (eventHandler != null) {
+ connectionContext = eventHandler.createContext(inputProtocol, outputProtocol);
+ }
+ // we check stopped_ first to make sure we're not supposed to be shutting
+ // down. this is necessary for graceful shutdown.
+ while (true) {
+
+ if (eventHandler != null) {
+ eventHandler.processContext(connectionContext, inputTransport, outputTransport);
+ }
+
+ if (stopped_) {
+ break;
+ }
+ processor.process(inputProtocol, outputProtocol);
+ }
+ } catch (Exception x) {
+ // We'll usually receive RuntimeException types here
+ // Need to unwrap to ascertain real causing exception before we choose to ignore
+ // Ignore err-logging all transport-level/type exceptions
+ if (!isIgnorableException(x)) {
+ // Log the exception at error level and continue
+ LOGGER.error((x instanceof TException? "Thrift " : "") + "Error occurred during processing of message.", x);
+ }
+ } finally {
+ if (eventHandler != null) {
+ eventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+ }
+ if (inputTransport != null) {
+ inputTransport.close();
+ }
+ if (outputTransport != null) {
+ outputTransport.close();
+ }
+ if (client_.isOpen()) {
+ client_.close();
+ }
+ }
+ }
+
+ private boolean isIgnorableException(Exception x) {
+ TTransportException tTransportException = null;
+
+ if (x instanceof TTransportException) {
+ tTransportException = (TTransportException)x;
+ }
+ else if (x.getCause() instanceof TTransportException) {
+ tTransportException = (TTransportException)x.getCause();
+ }
+
+ if (tTransportException != null) {
+ switch(tTransportException.getType()) {
+ case TTransportException.END_OF_FILE:
+ case TTransportException.TIMED_OUT:
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java
new file mode 100644
index 000000000..038507e9c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java
@@ -0,0 +1,744 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.thrift.transport.TNonblockingServerTransport;
+import org.apache.thrift.transport.TNonblockingTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A Half-Sync/Half-Async server with a separate pool of threads to handle
+ * non-blocking I/O. Accepts are handled on a single thread, and a configurable
+ * number of nonblocking selector threads manage reading and writing of client
+ * connections. A synchronous worker thread pool handles processing of requests.
+ *
+ * Performs better than TNonblockingServer/THsHaServer in multi-core
+ * environments when the the bottleneck is CPU on the single selector thread
+ * handling I/O. In addition, because the accept handling is decoupled from
+ * reads/writes and invocation, the server has better ability to handle back-
+ * pressure from new connections (e.g. stop accepting when busy).
+ *
+ * Like TNonblockingServer, it relies on the use of TFramedTransport.
+ */
+public class TThreadedSelectorServer extends AbstractNonblockingServer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TThreadedSelectorServer.class.getName());
+
+ public static class Args extends AbstractNonblockingServerArgs<Args> {
+
+ /** The number of threads for selecting on already-accepted connections */
+ public int selectorThreads = 2;
+ /**
+ * The size of the executor service (if none is specified) that will handle
+ * invocations. This may be set to 0, in which case invocations will be
+ * handled directly on the selector threads (as is in TNonblockingServer)
+ */
+ private int workerThreads = 5;
+ /** Time to wait for server to stop gracefully */
+ private int stopTimeoutVal = 60;
+ private TimeUnit stopTimeoutUnit = TimeUnit.SECONDS;
+ /** The ExecutorService for handling dispatched requests */
+ private ExecutorService executorService = null;
+ /**
+ * The size of the blocking queue per selector thread for passing accepted
+ * connections to the selector thread
+ */
+ private int acceptQueueSizePerThread = 4;
+
+ /**
+ * Determines the strategy for handling new accepted connections.
+ */
+ public static enum AcceptPolicy {
+ /**
+ * Require accepted connection registration to be handled by the executor.
+ * If the worker pool is saturated, further accepts will be closed
+ * immediately. Slightly increases latency due to an extra scheduling.
+ */
+ FAIR_ACCEPT,
+ /**
+ * Handle the accepts as fast as possible, disregarding the status of the
+ * executor service.
+ */
+ FAST_ACCEPT
+ }
+
+ private AcceptPolicy acceptPolicy = AcceptPolicy.FAST_ACCEPT;
+
+ public Args(TNonblockingServerTransport transport) {
+ super(transport);
+ }
+
+ public Args selectorThreads(int i) {
+ selectorThreads = i;
+ return this;
+ }
+
+ public int getSelectorThreads() {
+ return selectorThreads;
+ }
+
+ public Args workerThreads(int i) {
+ workerThreads = i;
+ return this;
+ }
+
+ public int getWorkerThreads() {
+ return workerThreads;
+ }
+
+ public int getStopTimeoutVal() {
+ return stopTimeoutVal;
+ }
+
+ public Args stopTimeoutVal(int stopTimeoutVal) {
+ this.stopTimeoutVal = stopTimeoutVal;
+ return this;
+ }
+
+ public TimeUnit getStopTimeoutUnit() {
+ return stopTimeoutUnit;
+ }
+
+ public Args stopTimeoutUnit(TimeUnit stopTimeoutUnit) {
+ this.stopTimeoutUnit = stopTimeoutUnit;
+ return this;
+ }
+
+ public ExecutorService getExecutorService() {
+ return executorService;
+ }
+
+ public Args executorService(ExecutorService executorService) {
+ this.executorService = executorService;
+ return this;
+ }
+
+ public int getAcceptQueueSizePerThread() {
+ return acceptQueueSizePerThread;
+ }
+
+ public Args acceptQueueSizePerThread(int acceptQueueSizePerThread) {
+ this.acceptQueueSizePerThread = acceptQueueSizePerThread;
+ return this;
+ }
+
+ public AcceptPolicy getAcceptPolicy() {
+ return acceptPolicy;
+ }
+
+ public Args acceptPolicy(AcceptPolicy acceptPolicy) {
+ this.acceptPolicy = acceptPolicy;
+ return this;
+ }
+
+ public void validate() {
+ if (selectorThreads <= 0) {
+ throw new IllegalArgumentException("selectorThreads must be positive.");
+ }
+ if (workerThreads < 0) {
+ throw new IllegalArgumentException("workerThreads must be non-negative.");
+ }
+ if (acceptQueueSizePerThread <= 0) {
+ throw new IllegalArgumentException("acceptQueueSizePerThread must be positive.");
+ }
+ }
+ }
+
+ // The thread handling all accepts
+ private AcceptThread acceptThread;
+
+ // Threads handling events on client transports
+ private final Set<SelectorThread> selectorThreads = new HashSet<SelectorThread>();
+
+ // This wraps all the functionality of queueing and thread pool management
+ // for the passing of Invocations from the selector thread(s) to the workers
+ // (if any).
+ private final ExecutorService invoker;
+
+ private final Args args;
+
+ /**
+ * Create the server with the specified Args configuration
+ */
+ public TThreadedSelectorServer(Args args) {
+ super(args);
+ args.validate();
+ invoker = args.executorService == null ? createDefaultExecutor(args) : args.executorService;
+ this.args = args;
+ }
+
+ /**
+ * Start the accept and selector threads running to deal with clients.
+ *
+ * @return true if everything went ok, false if we couldn't start for some
+ * reason.
+ */
+ @Override
+ protected boolean startThreads() {
+ try {
+ for (int i = 0; i < args.selectorThreads; ++i) {
+ selectorThreads.add(new SelectorThread(args.acceptQueueSizePerThread));
+ }
+ acceptThread = new AcceptThread((TNonblockingServerTransport) serverTransport_,
+ createSelectorThreadLoadBalancer(selectorThreads));
+ for (SelectorThread thread : selectorThreads) {
+ thread.start();
+ }
+ acceptThread.start();
+ return true;
+ } catch (IOException e) {
+ LOGGER.error("Failed to start threads!", e);
+ return false;
+ }
+ }
+
+ /**
+ * Joins the accept and selector threads and shuts down the executor service.
+ */
+ @Override
+ protected void waitForShutdown() {
+ try {
+ joinThreads();
+ } catch (InterruptedException e) {
+ // Non-graceful shutdown occurred
+ LOGGER.error("Interrupted while joining threads!", e);
+ }
+ gracefullyShutdownInvokerPool();
+ }
+
+ protected void joinThreads() throws InterruptedException {
+ // wait until the io threads exit
+ acceptThread.join();
+ for (SelectorThread thread : selectorThreads) {
+ thread.join();
+ }
+ }
+
+ /**
+ * Stop serving and shut everything down.
+ */
+ @Override
+ public void stop() {
+ stopped_ = true;
+
+ // Stop queuing connect attempts asap
+ stopListening();
+
+ if (acceptThread != null) {
+ acceptThread.wakeupSelector();
+ }
+ if (selectorThreads != null) {
+ for (SelectorThread thread : selectorThreads) {
+ if (thread != null)
+ thread.wakeupSelector();
+ }
+ }
+ }
+
+ protected void gracefullyShutdownInvokerPool() {
+ // try to gracefully shut down the executor service
+ invoker.shutdown();
+
+ // Loop until awaitTermination finally does return without a interrupted
+ // exception. If we don't do this, then we'll shut down prematurely. We want
+ // to let the executorService clear it's task queue, closing client sockets
+ // appropriately.
+ long timeoutMS = args.stopTimeoutUnit.toMillis(args.stopTimeoutVal);
+ long now = System.currentTimeMillis();
+ while (timeoutMS >= 0) {
+ try {
+ invoker.awaitTermination(timeoutMS, TimeUnit.MILLISECONDS);
+ break;
+ } catch (InterruptedException ix) {
+ long newnow = System.currentTimeMillis();
+ timeoutMS -= (newnow - now);
+ now = newnow;
+ }
+ }
+ }
+
+ /**
+ * We override the standard invoke method here to queue the invocation for
+ * invoker service instead of immediately invoking. If there is no thread
+ * pool, handle the invocation inline on this thread
+ */
+ @Override
+ protected boolean requestInvoke(FrameBuffer frameBuffer) {
+ Runnable invocation = getRunnable(frameBuffer);
+ if (invoker != null) {
+ try {
+ invoker.execute(invocation);
+ return true;
+ } catch (RejectedExecutionException rx) {
+ LOGGER.warn("ExecutorService rejected execution!", rx);
+ return false;
+ }
+ } else {
+ // Invoke on the caller's thread
+ invocation.run();
+ return true;
+ }
+ }
+
+ protected Runnable getRunnable(FrameBuffer frameBuffer) {
+ return new Invocation(frameBuffer);
+ }
+
+ /**
+ * Helper to create the invoker if one is not specified
+ */
+ protected static ExecutorService createDefaultExecutor(Args options) {
+ return (options.workerThreads > 0) ? Executors.newFixedThreadPool(options.workerThreads) : null;
+ }
+
+ private static BlockingQueue<TNonblockingTransport> createDefaultAcceptQueue(int queueSize) {
+ if (queueSize == 0) {
+ // Unbounded queue
+ return new LinkedBlockingQueue<TNonblockingTransport>();
+ }
+ return new ArrayBlockingQueue<TNonblockingTransport>(queueSize);
+ }
+
+ /**
+ * The thread that selects on the server transport (listen socket) and accepts
+ * new connections to hand off to the IO selector threads
+ */
+ protected class AcceptThread extends Thread {
+
+ // The listen socket to accept on
+ private final TNonblockingServerTransport serverTransport;
+ private final Selector acceptSelector;
+
+ private final SelectorThreadLoadBalancer threadChooser;
+
+ /**
+ * Set up the AcceptThead
+ *
+ * @throws IOException
+ */
+ public AcceptThread(TNonblockingServerTransport serverTransport,
+ SelectorThreadLoadBalancer threadChooser) throws IOException {
+ this.serverTransport = serverTransport;
+ this.threadChooser = threadChooser;
+ this.acceptSelector = SelectorProvider.provider().openSelector();
+ this.serverTransport.registerSelector(acceptSelector);
+ }
+
+ /**
+ * The work loop. Selects on the server transport and accepts. If there was
+ * a server transport that had blocking accepts, and returned on blocking
+ * client transports, that should be used instead
+ */
+ public void run() {
+ try {
+ if (eventHandler_ != null) {
+ eventHandler_.preServe();
+ }
+
+ while (!stopped_) {
+ select();
+ }
+ } catch (Throwable t) {
+ LOGGER.error("run() on AcceptThread exiting due to uncaught error", t);
+ } finally {
+ try {
+ acceptSelector.close();
+ } catch (IOException e) {
+ LOGGER.error("Got an IOException while closing accept selector!", e);
+ }
+ // This will wake up the selector threads
+ TThreadedSelectorServer.this.stop();
+ }
+ }
+
+ /**
+ * If the selector is blocked, wake it up.
+ */
+ public void wakeupSelector() {
+ acceptSelector.wakeup();
+ }
+
+ /**
+ * Select and process IO events appropriately: If there are connections to
+ * be accepted, accept them.
+ */
+ private void select() {
+ try {
+ // wait for connect events.
+ acceptSelector.select();
+
+ // process the io events we received
+ Iterator<SelectionKey> selectedKeys = acceptSelector.selectedKeys().iterator();
+ while (!stopped_ && selectedKeys.hasNext()) {
+ SelectionKey key = selectedKeys.next();
+ selectedKeys.remove();
+
+ // skip if not valid
+ if (!key.isValid()) {
+ continue;
+ }
+
+ if (key.isAcceptable()) {
+ handleAccept();
+ } else {
+ LOGGER.warn("Unexpected state in select! " + key.interestOps());
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.warn("Got an IOException while selecting!", e);
+ }
+ }
+
+ /**
+ * Accept a new connection.
+ */
+ private void handleAccept() {
+ final TNonblockingTransport client = doAccept();
+ if (client != null) {
+ // Pass this connection to a selector thread
+ final SelectorThread targetThread = threadChooser.nextThread();
+
+ if (args.acceptPolicy == Args.AcceptPolicy.FAST_ACCEPT || invoker == null) {
+ doAddAccept(targetThread, client);
+ } else {
+ // FAIR_ACCEPT
+ try {
+ invoker.submit(new Runnable() {
+ public void run() {
+ doAddAccept(targetThread, client);
+ }
+ });
+ } catch (RejectedExecutionException rx) {
+ LOGGER.warn("ExecutorService rejected accept registration!", rx);
+ // close immediately
+ client.close();
+ }
+ }
+ }
+ }
+
+ private TNonblockingTransport doAccept() {
+ try {
+ return (TNonblockingTransport) serverTransport.accept();
+ } catch (TTransportException tte) {
+ // something went wrong accepting.
+ LOGGER.warn("Exception trying to accept!", tte);
+ return null;
+ }
+ }
+
+ private void doAddAccept(SelectorThread thread, TNonblockingTransport client) {
+ if (!thread.addAcceptedConnection(client)) {
+ client.close();
+ }
+ }
+ } // AcceptThread
+
+ /**
+ * The SelectorThread(s) will be doing all the selecting on accepted active
+ * connections.
+ */
+ protected class SelectorThread extends AbstractSelectThread {
+
+ // Accepted connections added by the accept thread.
+ private final BlockingQueue<TNonblockingTransport> acceptedQueue;
+ private int SELECTOR_AUTO_REBUILD_THRESHOLD = 512;
+ private long MONITOR_PERIOD = 1000L;
+ private int jvmBug = 0;
+
+ /**
+ * Set up the SelectorThread with an unbounded queue for incoming accepts.
+ *
+ * @throws IOException
+ * if a selector cannot be created
+ */
+ public SelectorThread() throws IOException {
+ this(new LinkedBlockingQueue<TNonblockingTransport>());
+ }
+
+ /**
+ * Set up the SelectorThread with an bounded queue for incoming accepts.
+ *
+ * @throws IOException
+ * if a selector cannot be created
+ */
+ public SelectorThread(int maxPendingAccepts) throws IOException {
+ this(createDefaultAcceptQueue(maxPendingAccepts));
+ }
+
+ /**
+ * Set up the SelectorThread with a specified queue for connections.
+ *
+ * @param acceptedQueue
+ * The BlockingQueue implementation for holding incoming accepted
+ * connections.
+ * @throws IOException
+ * if a selector cannot be created.
+ */
+ public SelectorThread(BlockingQueue<TNonblockingTransport> acceptedQueue) throws IOException {
+ this.acceptedQueue = acceptedQueue;
+ }
+
+ /**
+ * Hands off an accepted connection to be handled by this thread. This
+ * method will block if the queue for new connections is at capacity.
+ *
+ * @param accepted
+ * The connection that has been accepted.
+ * @return true if the connection has been successfully added.
+ */
+ public boolean addAcceptedConnection(TNonblockingTransport accepted) {
+ try {
+ acceptedQueue.put(accepted);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Interrupted while adding accepted connection!", e);
+ return false;
+ }
+ selector.wakeup();
+ return true;
+ }
+
+ /**
+ * The work loop. Handles selecting (read/write IO), dispatching, and
+ * managing the selection preferences of all existing connections.
+ */
+ public void run() {
+ try {
+ while (!stopped_) {
+ select();
+ processAcceptedConnections();
+ processInterestChanges();
+ }
+ for (SelectionKey selectionKey : selector.keys()) {
+ cleanupSelectionKey(selectionKey);
+ }
+ } catch (Throwable t) {
+ LOGGER.error("run() on SelectorThread exiting due to uncaught error", t);
+ } finally {
+ try {
+ selector.close();
+ } catch (IOException e) {
+ LOGGER.error("Got an IOException while closing selector!", e);
+ }
+ // This will wake up the accept thread and the other selector threads
+ TThreadedSelectorServer.this.stop();
+ }
+ }
+
+ /**
+ * Select and process IO events appropriately: If there are existing
+ * connections with data waiting to be read, read it, buffering until a
+ * whole frame has been read. If there are any pending responses, buffer
+ * them until their target client is available, and then send the data.
+ */
+ private void select() {
+ try {
+
+ doSelect();
+
+ // process the io events we received
+ Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
+ while (!stopped_ && selectedKeys.hasNext()) {
+ SelectionKey key = selectedKeys.next();
+ selectedKeys.remove();
+
+ // skip if not valid
+ if (!key.isValid()) {
+ cleanupSelectionKey(key);
+ continue;
+ }
+
+ if (key.isReadable()) {
+ // deal with reads
+ handleRead(key);
+ } else if (key.isWritable()) {
+ // deal with writes
+ handleWrite(key);
+ } else {
+ LOGGER.warn("Unexpected state in select! " + key.interestOps());
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.warn("Got an IOException while selecting!", e);
+ }
+ }
+
+ /**
+ * Do select and judge epoll bug happen.
+ * See : https://issues.apache.org/jira/browse/THRIFT-4251
+ */
+ private void doSelect() throws IOException {
+ long beforeSelect = System.currentTimeMillis();
+ int selectedNums = selector.select();
+ long afterSelect = System.currentTimeMillis();
+
+ if (selectedNums == 0) {
+ jvmBug++;
+ } else {
+ jvmBug = 0;
+ }
+
+ long selectedTime = afterSelect - beforeSelect;
+ if (selectedTime >= MONITOR_PERIOD) {
+ jvmBug = 0;
+ } else if (jvmBug > SELECTOR_AUTO_REBUILD_THRESHOLD) {
+ LOGGER.warn("In {} ms happen {} times jvm bug; rebuilding selector.", MONITOR_PERIOD, jvmBug);
+ rebuildSelector();
+ selector.selectNow();
+ jvmBug = 0;
+ }
+
+ }
+
+ /**
+ * Replaces the current Selector of this SelectorThread with newly created Selector to work
+ * around the infamous epoll 100% CPU bug.
+ */
+ private synchronized void rebuildSelector() {
+ final Selector oldSelector = selector;
+ if (oldSelector == null) {
+ return;
+ }
+ Selector newSelector = null;
+ try {
+ newSelector = Selector.open();
+ LOGGER.warn("Created new Selector.");
+ } catch (IOException e) {
+ LOGGER.error("Create new Selector error.", e);
+ }
+
+ for (SelectionKey key : oldSelector.selectedKeys()) {
+ if (!key.isValid() && key.readyOps() == 0)
+ continue;
+ SelectableChannel channel = key.channel();
+ Object attachment = key.attachment();
+
+ try {
+ if (attachment == null) {
+ channel.register(newSelector, key.readyOps());
+ } else {
+ channel.register(newSelector, key.readyOps(), attachment);
+ }
+ } catch (ClosedChannelException e) {
+ LOGGER.error("Register new selector key error.", e);
+ }
+
+ }
+
+ selector = newSelector;
+ try {
+ oldSelector.close();
+ } catch (IOException e) {
+ LOGGER.error("Close old selector error.", e);
+ }
+ LOGGER.warn("Replace new selector success.");
+ }
+
+ private void processAcceptedConnections() {
+ // Register accepted connections
+ while (!stopped_) {
+ TNonblockingTransport accepted = acceptedQueue.poll();
+ if (accepted == null) {
+ break;
+ }
+ registerAccepted(accepted);
+ }
+ }
+
+ protected FrameBuffer createFrameBuffer(final TNonblockingTransport trans,
+ final SelectionKey selectionKey,
+ final AbstractSelectThread selectThread) {
+ return processorFactory_.isAsyncProcessor() ?
+ new AsyncFrameBuffer(trans, selectionKey, selectThread) :
+ new FrameBuffer(trans, selectionKey, selectThread);
+ }
+
+ private void registerAccepted(TNonblockingTransport accepted) {
+ SelectionKey clientKey = null;
+ try {
+ clientKey = accepted.registerSelector(selector, SelectionKey.OP_READ);
+
+ FrameBuffer frameBuffer = createFrameBuffer(accepted, clientKey, SelectorThread.this);
+
+ clientKey.attach(frameBuffer);
+ } catch (IOException e) {
+ LOGGER.warn("Failed to register accepted connection to selector!", e);
+ if (clientKey != null) {
+ cleanupSelectionKey(clientKey);
+ }
+ accepted.close();
+ }
+ }
+ } // SelectorThread
+
+ /**
+ * Creates a SelectorThreadLoadBalancer to be used by the accept thread for
+ * assigning newly accepted connections across the threads.
+ */
+ protected SelectorThreadLoadBalancer createSelectorThreadLoadBalancer(Collection<? extends SelectorThread> threads) {
+ return new SelectorThreadLoadBalancer(threads);
+ }
+
+ /**
+ * A round robin load balancer for choosing selector threads for new
+ * connections.
+ */
+ protected static class SelectorThreadLoadBalancer {
+ private final Collection<? extends SelectorThread> threads;
+ private Iterator<? extends SelectorThread> nextThreadIterator;
+
+ public <T extends SelectorThread> SelectorThreadLoadBalancer(Collection<T> threads) {
+ if (threads.isEmpty()) {
+ throw new IllegalArgumentException("At least one selector thread is required");
+ }
+ this.threads = Collections.unmodifiableList(new ArrayList<T>(threads));
+ nextThreadIterator = this.threads.iterator();
+ }
+
+ public SelectorThread nextThread() {
+ // Choose a selector thread (round robin)
+ if (!nextThreadIterator.hasNext()) {
+ nextThreadIterator = threads.iterator();
+ }
+ return nextThreadIterator.next();
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java
new file mode 100644
index 000000000..fc3aa92df
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.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.thrift.transport;
+
+import java.util.Arrays;
+
+/**
+ * Helper class that wraps a byte[] so that it can expand and be reused. Users
+ * should call resizeIfNecessary to make sure the buffer has suitable capacity,
+ * and then use the array as needed. Note that the internal array will grow at a
+ * rate slightly faster than the requested capacity with the (untested)
+ * objective of avoiding expensive buffer allocations and copies.
+ */
+class AutoExpandingBuffer {
+ private byte[] array;
+
+ public AutoExpandingBuffer(int initialCapacity) {
+ this.array = new byte[initialCapacity];
+ }
+
+ public void resizeIfNecessary(int size) {
+ final int currentCapacity = this.array.length;
+ if (currentCapacity < size) {
+ // Increase by a factor of 1.5x
+ int growCapacity = currentCapacity + (currentCapacity >> 1);
+ int newCapacity = Math.max(growCapacity, size);
+ this.array = Arrays.copyOf(array, newCapacity);
+ }
+ }
+
+ public byte[] array() {
+ return this.array;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java
new file mode 100644
index 000000000..a28d25485
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java
@@ -0,0 +1,84 @@
+/*
+ * 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.thrift.transport;
+
+/**
+ * TTransport for reading from an AutoExpandingBuffer.
+ */
+public class AutoExpandingBufferReadTransport extends TTransport {
+
+ private final AutoExpandingBuffer buf;
+
+ private int pos = 0;
+ private int limit = 0;
+
+ public AutoExpandingBufferReadTransport(int initialCapacity) {
+ this.buf = new AutoExpandingBuffer(initialCapacity);
+ }
+
+ public void fill(TTransport inTrans, int length) throws TTransportException {
+ buf.resizeIfNecessary(length);
+ inTrans.readAll(buf.array(), 0, length);
+ pos = 0;
+ limit = length;
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean isOpen() { return true; }
+
+ @Override
+ public void open() throws TTransportException {}
+
+ @Override
+ public final int read(byte[] target, int off, int len) throws TTransportException {
+ int amtToRead = Math.min(len, getBytesRemainingInBuffer());
+ System.arraycopy(buf.array(), pos, target, off, amtToRead);
+ consumeBuffer(amtToRead);
+ return amtToRead;
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final void consumeBuffer(int len) {
+ pos += len;
+ }
+
+ @Override
+ public final byte[] getBuffer() {
+ return buf.array();
+ }
+
+ @Override
+ public final int getBufferPosition() {
+ return pos;
+ }
+
+ @Override
+ public final int getBytesRemainingInBuffer() {
+ return limit - pos;
+ }
+}
+ \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java
new file mode 100644
index 000000000..ec7e7d45a
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java
@@ -0,0 +1,88 @@
+/*
+ * 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.thrift.transport;
+
+/**
+ * TTransport for writing to an AutoExpandingBuffer.
+ */
+public final class AutoExpandingBufferWriteTransport extends TTransport {
+
+ private final AutoExpandingBuffer buf;
+ private int pos;
+ private int res;
+
+ /**
+ * Constructor.
+ * @param initialCapacity the initial capacity of the buffer
+ * @param frontReserve space, if any, to reserve at the beginning such
+ * that the first write is after this reserve.
+ * This allows framed transport to reserve space
+ * for the frame buffer length.
+ * @throws IllegalArgumentException if initialCapacity is less than one
+ * @throws IllegalArgumentException if frontReserve is less than zero
+ * @throws IllegalArgumentException if frontReserve is greater than initialCapacity
+ */
+ public AutoExpandingBufferWriteTransport(int initialCapacity, int frontReserve) {
+ if (initialCapacity < 1) {
+ throw new IllegalArgumentException("initialCapacity");
+ }
+ if (frontReserve < 0 || initialCapacity < frontReserve) {
+ throw new IllegalArgumentException("frontReserve");
+ }
+ this.buf = new AutoExpandingBuffer(initialCapacity);
+ this.pos = frontReserve;
+ this.res = frontReserve;
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean isOpen() {return true;}
+
+ @Override
+ public void open() throws TTransportException {}
+
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void write(byte[] toWrite, int off, int len) throws TTransportException {
+ buf.resizeIfNecessary(pos + len);
+ System.arraycopy(toWrite, off, buf.array(), pos, len);
+ pos += len;
+ }
+
+ public AutoExpandingBuffer getBuf() {
+ return buf;
+ }
+
+ /**
+ * @return length of the buffer, including any front reserve
+ */
+ public int getLength() {
+ return pos;
+ }
+
+ public void reset() {
+ pos = res;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TByteBuffer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TByteBuffer.java
new file mode 100644
index 000000000..b6b065748
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TByteBuffer.java
@@ -0,0 +1,87 @@
+package org.apache.thrift.transport;
+
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+
+/**
+ * ByteBuffer-backed implementation of TTransport.
+ */
+public final class TByteBuffer extends TTransport {
+ private final ByteBuffer byteBuffer;
+
+ /**
+ * Creates a new TByteBuffer wrapping a given NIO ByteBuffer.
+ */
+ public TByteBuffer(ByteBuffer byteBuffer) {
+ this.byteBuffer = byteBuffer;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public void open() {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ final int n = Math.min(byteBuffer.remaining(), len);
+ if (n > 0) {
+ try {
+ byteBuffer.get(buf, off, n);
+ } catch (BufferUnderflowException e) {
+ throw new TTransportException("Unexpected end of input buffer", e);
+ }
+ }
+ return n;
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ try {
+ byteBuffer.put(buf, off, len);
+ } catch (BufferOverflowException e) {
+ throw new TTransportException("Not enough room in output buffer", e);
+ }
+ }
+
+ /**
+ * Get the underlying NIO ByteBuffer.
+ */
+ public ByteBuffer getByteBuffer() {
+ return byteBuffer;
+ }
+
+ /**
+ * Convenience method to call clear() on the underlying NIO ByteBuffer.
+ */
+ public TByteBuffer clear() {
+ byteBuffer.clear();
+ return this;
+ }
+
+ /**
+ * Convenience method to call flip() on the underlying NIO ByteBuffer.
+ */
+ public TByteBuffer flip() {
+ byteBuffer.flip();
+ return this;
+ }
+
+ /**
+ * Convenience method to convert the underlying NIO ByteBuffer to a
+ * plain old byte array.
+ */
+ public byte[] toByteArray() {
+ final byte[] data = new byte[byteBuffer.remaining()];
+ byteBuffer.slice().get(data);
+ return data;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java
new file mode 100644
index 000000000..a1fd2490a
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java
@@ -0,0 +1,200 @@
+/*
+ * 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.thrift.transport;
+
+/**
+ * This transport is wire compatible with {@link TFramedTransport}, but makes
+ * use of reusable, expanding read and write buffers in order to avoid
+ * allocating new byte[]s all the time. Since the buffers only expand, you
+ * should probably only use this transport if your messages are not too variably
+ * large, unless the persistent memory cost is not an issue.
+ *
+ * This implementation is NOT threadsafe.
+ */
+public class TFastFramedTransport extends TTransport {
+
+ public static class Factory extends TTransportFactory {
+ private final int initialCapacity;
+ private final int maxLength;
+
+ public Factory() {
+ this(DEFAULT_BUF_CAPACITY, DEFAULT_MAX_LENGTH);
+ }
+
+ public Factory(int initialCapacity) {
+ this(initialCapacity, DEFAULT_MAX_LENGTH);
+ }
+
+ public Factory(int initialCapacity, int maxLength) {
+ this.initialCapacity = initialCapacity;
+ this.maxLength = maxLength;
+ }
+
+ @Override
+ public TTransport getTransport(TTransport trans) {
+ return new TFastFramedTransport(trans,
+ initialCapacity,
+ maxLength);
+ }
+ }
+
+ /**
+ * How big should the default read and write buffers be?
+ */
+ public static final int DEFAULT_BUF_CAPACITY = 1024;
+ /**
+ * How big is the largest allowable frame? Defaults to 16MB.
+ */
+ public static final int DEFAULT_MAX_LENGTH = 16384000;
+
+ private final TTransport underlying;
+ private final AutoExpandingBufferWriteTransport writeBuffer;
+ private AutoExpandingBufferReadTransport readBuffer;
+ private final int initialBufferCapacity;
+ private final byte[] i32buf = new byte[4];
+ private final int maxLength;
+
+ /**
+ * Create a new {@link TFastFramedTransport}. Use the defaults
+ * for initial buffer size and max frame length.
+ * @param underlying Transport that real reads and writes will go through to.
+ */
+ public TFastFramedTransport(TTransport underlying) {
+ this(underlying, DEFAULT_BUF_CAPACITY, DEFAULT_MAX_LENGTH);
+ }
+
+ /**
+ * Create a new {@link TFastFramedTransport}. Use the specified
+ * initial buffer capacity and the default max frame length.
+ * @param underlying Transport that real reads and writes will go through to.
+ * @param initialBufferCapacity The initial size of the read and write buffers.
+ * In practice, it's not critical to set this unless you know in advance that
+ * your messages are going to be very large.
+ */
+ public TFastFramedTransport(TTransport underlying, int initialBufferCapacity) {
+ this(underlying, initialBufferCapacity, DEFAULT_MAX_LENGTH);
+ }
+
+ /**
+ *
+ * @param underlying Transport that real reads and writes will go through to.
+ * @param initialBufferCapacity The initial size of the read and write buffers.
+ * In practice, it's not critical to set this unless you know in advance that
+ * your messages are going to be very large. (You can pass
+ * TFramedTransportWithReusableBuffer.DEFAULT_BUF_CAPACITY if you're only
+ * using this constructor because you want to set the maxLength.)
+ * @param maxLength The max frame size you are willing to read. You can use
+ * this parameter to limit how much memory can be allocated.
+ */
+ public TFastFramedTransport(TTransport underlying, int initialBufferCapacity, int maxLength) {
+ this.underlying = underlying;
+ this.maxLength = maxLength;
+ this.initialBufferCapacity = initialBufferCapacity;
+ readBuffer = new AutoExpandingBufferReadTransport(initialBufferCapacity);
+ writeBuffer = new AutoExpandingBufferWriteTransport(initialBufferCapacity, 4);
+ }
+
+ @Override
+ public void close() {
+ underlying.close();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return underlying.isOpen();
+ }
+
+ @Override
+ public void open() throws TTransportException {
+ underlying.open();
+ }
+
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ int got = readBuffer.read(buf, off, len);
+ if (got > 0) {
+ return got;
+ }
+
+ // Read another frame of data
+ readFrame();
+
+ return readBuffer.read(buf, off, len);
+ }
+
+ private void readFrame() throws TTransportException {
+ underlying.readAll(i32buf , 0, 4);
+ int size = TFramedTransport.decodeFrameSize(i32buf);
+
+ if (size < 0) {
+ close();
+ throw new TTransportException(TTransportException.CORRUPTED_DATA, "Read a negative frame size (" + size + ")!");
+ }
+
+ if (size > maxLength) {
+ close();
+ throw new TTransportException(TTransportException.CORRUPTED_DATA,
+ "Frame size (" + size + ") larger than max length (" + maxLength + ")!");
+ }
+
+ readBuffer.fill(underlying, size);
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ writeBuffer.write(buf, off, len);
+ }
+
+ @Override
+ public void consumeBuffer(int len) {
+ readBuffer.consumeBuffer(len);
+ }
+
+ /**
+ * Only clears the read buffer!
+ */
+ public void clear() {
+ readBuffer = new AutoExpandingBufferReadTransport(initialBufferCapacity);
+ }
+
+ @Override
+ public void flush() throws TTransportException {
+ int payloadLength = writeBuffer.getLength() - 4;
+ byte[] data = writeBuffer.getBuf().array();
+ TFramedTransport.encodeFrameSize(payloadLength, data);
+ underlying.write(data, 0, payloadLength + 4);
+ writeBuffer.reset();
+ underlying.flush();
+ }
+
+ @Override
+ public byte[] getBuffer() {
+ return readBuffer.getBuffer();
+ }
+
+ @Override
+ public int getBufferPosition() {
+ return readBuffer.getBufferPosition();
+ }
+
+ @Override
+ public int getBytesRemainingInBuffer() {
+ return readBuffer.getBytesRemainingInBuffer();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileProcessor.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileProcessor.java
new file mode 100644
index 000000000..96087d1a3
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileProcessor.java
@@ -0,0 +1,118 @@
+/*
+ * 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.thrift.transport;
+
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+
+/**
+ * FileProcessor: helps in processing files generated by TFileTransport.
+ * Port of original cpp implementation
+ */
+public class TFileProcessor {
+
+ private TProcessor processor_;
+ private TProtocolFactory inputProtocolFactory_;
+ private TProtocolFactory outputProtocolFactory_;
+ private TFileTransport inputTransport_;
+ private TTransport outputTransport_;
+
+ public TFileProcessor(TProcessor processor, TProtocolFactory protocolFactory,
+ TFileTransport inputTransport,
+ TTransport outputTransport) {
+ processor_ = processor;
+ inputProtocolFactory_ = outputProtocolFactory_ = protocolFactory;
+ inputTransport_ = inputTransport;
+ outputTransport_ = outputTransport;
+ }
+
+ public TFileProcessor(TProcessor processor,
+ TProtocolFactory inputProtocolFactory,
+ TProtocolFactory outputProtocolFactory,
+ TFileTransport inputTransport,
+ TTransport outputTransport) {
+ processor_ = processor;
+ inputProtocolFactory_ = inputProtocolFactory;
+ outputProtocolFactory_ = outputProtocolFactory;
+ inputTransport_ = inputTransport;
+ outputTransport_ = outputTransport;
+ }
+
+ private void processUntil(int lastChunk) throws TException {
+ TProtocol ip = inputProtocolFactory_.getProtocol(inputTransport_);
+ TProtocol op = outputProtocolFactory_.getProtocol(outputTransport_);
+ int curChunk = inputTransport_.getCurChunk();
+
+ try {
+ while (lastChunk >= curChunk) {
+ processor_.process(ip, op);
+ int newChunk = inputTransport_.getCurChunk();
+ curChunk = newChunk;
+ }
+ } catch (TTransportException e) {
+ // if we are processing the last chunk - we could have just hit EOF
+ // on EOF - trap the error and stop processing.
+ if(e.getType() != TTransportException.END_OF_FILE)
+ throw e;
+ else {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Process from start to last chunk both inclusive where chunks begin from 0
+
+ * @param startChunkNum first chunk to be processed
+ * @param endChunkNum last chunk to be processed
+ */
+ public void processChunk(int startChunkNum, int endChunkNum) throws TException {
+ int numChunks = inputTransport_.getNumChunks();
+ if(endChunkNum < 0)
+ endChunkNum += numChunks;
+
+ if(startChunkNum < 0)
+ startChunkNum += numChunks;
+
+ if(endChunkNum < startChunkNum)
+ throw new TException("endChunkNum " + endChunkNum + " is less than " + startChunkNum);
+
+ inputTransport_.seekToChunk(startChunkNum);
+ processUntil(endChunkNum);
+ }
+
+ /**
+ * Process a single chunk
+ *
+ * @param chunkNum chunk to be processed
+ */
+ public void processChunk(int chunkNum) throws TException {
+ processChunk(chunkNum, chunkNum);
+ }
+
+ /**
+ * Process a current chunk
+ */
+ public void processChunk() throws TException {
+ processChunk(inputTransport_.getCurChunk());
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileTransport.java
new file mode 100644
index 000000000..88b73e54d
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFileTransport.java
@@ -0,0 +1,624 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * FileTransport implementation of the TTransport interface.
+ * Currently this is a straightforward port of the cpp implementation
+ *
+ * It may make better sense to provide a basic stream access on top of the framed file format
+ * The FileTransport can then be a user of this framed file format with some additional logic
+ * for chunking.
+ */
+public class TFileTransport extends TTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TFileTransport.class.getName());
+
+ public static class TruncableBufferedInputStream extends BufferedInputStream {
+ public void trunc() {
+ pos = count = 0;
+ }
+ public TruncableBufferedInputStream(InputStream in) {
+ super(in);
+ }
+ public TruncableBufferedInputStream(InputStream in, int size) {
+ super(in, size);
+ }
+ }
+
+
+ public static class Event {
+ private byte[] buf_;
+ private int nread_;
+ private int navailable_;
+
+ /**
+ * Initialize an event. Initially, it has no valid contents
+ *
+ * @param buf byte array buffer to store event
+ */
+ public Event(byte[] buf) {
+ buf_ = buf;
+ nread_ = navailable_ = 0;
+ }
+
+ public byte[] getBuf() { return buf_;}
+ public int getSize() { return buf_.length; }
+
+
+ public void setAvailable(int sz) { nread_ = 0; navailable_=sz;}
+ public int getRemaining() { return (navailable_ - nread_); }
+
+ public int emit(byte[] buf, int offset, int ndesired) {
+ if((ndesired == 0) || (ndesired > getRemaining()))
+ ndesired = getRemaining();
+
+ if(ndesired <= 0)
+ return (ndesired);
+
+ System.arraycopy(buf_, nread_, buf, offset, ndesired);
+ nread_ += ndesired;
+
+ return(ndesired);
+ }
+ };
+
+ public static class ChunkState {
+ /**
+ * Chunk Size. Must be same across all implementations
+ */
+ public static final int DEFAULT_CHUNK_SIZE = 16 * 1024 * 1024;
+
+ private int chunk_size_ = DEFAULT_CHUNK_SIZE;
+ private long offset_ = 0;
+
+ public ChunkState() {}
+ public ChunkState(int chunk_size) { chunk_size_ = chunk_size; }
+
+ public void skip(int size) {offset_ += size; }
+ public void seek(long offset) {offset_ = offset;}
+
+ public int getChunkSize() { return chunk_size_;}
+ public int getChunkNum() { return ((int)(offset_/chunk_size_));}
+ public int getRemaining() { return (chunk_size_ - ((int)(offset_ % chunk_size_)));}
+ public long getOffset() { return (offset_);}
+ }
+
+ public static enum TailPolicy {
+
+ NOWAIT(0, 0),
+ WAIT_FOREVER(500, -1);
+
+ /**
+ * Time in milliseconds to sleep before next read
+ * If 0, no sleep
+ */
+ public final int timeout_;
+
+ /**
+ * Number of retries before giving up
+ * if 0, no retries
+ * if -1, retry forever
+ */
+ public final int retries_;
+
+ /**
+ * ctor for policy
+ *
+ * @param timeout sleep time for this particular policy
+ * @param retries number of retries
+ */
+
+ TailPolicy(int timeout, int retries) {
+ timeout_ = timeout;
+ retries_ = retries;
+ }
+ }
+
+ /**
+ * Current tailing policy
+ */
+ TailPolicy currentPolicy_ = TailPolicy.NOWAIT;
+
+
+ /**
+ * Underlying file being read
+ */
+ protected TSeekableFile inputFile_ = null;
+
+ /**
+ * Underlying outputStream
+ */
+ protected OutputStream outputStream_ = null;
+
+
+ /**
+ * Event currently read in
+ */
+ Event currentEvent_ = null;
+
+ /**
+ * InputStream currently being used for reading
+ */
+ InputStream inputStream_ = null;
+
+ /**
+ * current Chunk state
+ */
+ ChunkState cs = null;
+
+ /**
+ * is read only?
+ */
+ private boolean readOnly_ = false;
+
+ /**
+ * Get File Tailing Policy
+ *
+ * @return current read policy
+ */
+ public TailPolicy getTailPolicy() {
+ return (currentPolicy_);
+ }
+
+ /**
+ * Set file Tailing Policy
+ *
+ * @param policy New policy to set
+ * @return Old policy
+ */
+ public TailPolicy setTailPolicy(TailPolicy policy) {
+ TailPolicy old = currentPolicy_;
+ currentPolicy_ = policy;
+ return (old);
+ }
+
+
+ /**
+ * Initialize read input stream
+ *
+ * @return input stream to read from file
+ */
+ private InputStream createInputStream() throws TTransportException {
+ InputStream is;
+ try {
+ if(inputStream_ != null) {
+ ((TruncableBufferedInputStream)inputStream_).trunc();
+ is = inputStream_;
+ } else {
+ is = new TruncableBufferedInputStream(inputFile_.getInputStream());
+ }
+ } catch (IOException iox) {
+ throw new TTransportException(iox.getMessage(), iox);
+ }
+ return(is);
+ }
+
+ /**
+ * Read (potentially tailing) an input stream
+ *
+ * @param is InputStream to read from
+ * @param buf Buffer to read into
+ * @param off Offset in buffer to read into
+ * @param len Number of bytes to read
+ * @param tp policy to use if we hit EOF
+ *
+ * @return number of bytes read
+ */
+ private int tailRead(InputStream is, byte[] buf,
+ int off, int len, TailPolicy tp) throws TTransportException {
+ int orig_len = len;
+ try {
+ int retries = 0;
+ while(len > 0) {
+ int cnt = is.read(buf, off, len);
+ if(cnt > 0) {
+ off += cnt;
+ len -= cnt;
+ retries = 0;
+ cs.skip(cnt); // remember that we read so many bytes
+ } else if (cnt == -1) {
+ // EOF
+ retries++;
+
+ if((tp.retries_ != -1) && tp.retries_ < retries)
+ return (orig_len - len);
+
+ if(tp.timeout_ > 0) {
+ try {Thread.sleep(tp.timeout_);} catch(InterruptedException e) {}
+ }
+ } else {
+ // either non-zero or -1 is what the contract says!
+ throw new
+ TTransportException("Unexpected return from InputStream.read = "
+ + cnt);
+ }
+ }
+ } catch (IOException iox) {
+ throw new TTransportException(iox.getMessage(), iox);
+ }
+
+ return(orig_len - len);
+ }
+
+ /**
+ * Event is corrupted. Do recovery
+ *
+ * @return true if recovery could be performed and we can read more data
+ * false is returned only when nothing more can be read
+ */
+ private boolean performRecovery() throws TTransportException {
+ int numChunks = getNumChunks();
+ int curChunk = cs.getChunkNum();
+
+ if(curChunk >= (numChunks-1)) {
+ return false;
+ }
+ seekToChunk(curChunk+1);
+ return true;
+ }
+
+ /**
+ * Read event from underlying file
+ *
+ * @return true if event could be read, false otherwise (on EOF)
+ */
+ private boolean readEvent() throws TTransportException {
+ byte[] ebytes = new byte[4];
+ int esize;
+ int nread;
+ int nrequested;
+
+ retry:
+ do {
+ // corner case. read to end of chunk
+ nrequested = cs.getRemaining();
+ if(nrequested < 4) {
+ nread = tailRead(inputStream_, ebytes, 0, nrequested, currentPolicy_);
+ if(nread != nrequested) {
+ return(false);
+ }
+ }
+
+ // assuming serialized on little endian machine
+ nread = tailRead(inputStream_, ebytes, 0, 4, currentPolicy_);
+ if(nread != 4) {
+ return(false);
+ }
+
+ esize=0;
+ for(int i=3; i>=0; i--) {
+ int val = (0x000000ff & (int)ebytes[i]);
+ esize |= (val << (i*8));
+ }
+
+ // check if event is corrupted and do recovery as required
+ if(esize > cs.getRemaining()) {
+ throw new TTransportException("FileTransport error: bad event size");
+ /*
+ if(performRecovery()) {
+ esize=0;
+ } else {
+ return false;
+ }
+ */
+ }
+ } while (esize == 0);
+
+ // reset existing event or get a larger one
+ if(currentEvent_.getSize() < esize)
+ currentEvent_ = new Event(new byte [esize]);
+
+ // populate the event
+ byte[] buf = currentEvent_.getBuf();
+ nread = tailRead(inputStream_, buf, 0, esize, currentPolicy_);
+ if(nread != esize) {
+ return(false);
+ }
+ currentEvent_.setAvailable(esize);
+ return(true);
+ }
+
+ /**
+ * open if both input/output open unless readonly
+ *
+ * @return true
+ */
+ public boolean isOpen() {
+ return ((inputStream_ != null) && (readOnly_ || (outputStream_ != null)));
+ }
+
+
+ /**
+ * Diverging from the cpp model and sticking to the TSocket model
+ * Files are not opened in ctor - but in explicit open call
+ */
+ public void open() throws TTransportException {
+ if (isOpen())
+ throw new TTransportException(TTransportException.ALREADY_OPEN);
+
+ try {
+ inputStream_ = createInputStream();
+ cs = new ChunkState();
+ currentEvent_ = new Event(new byte [256]);
+
+ if(!readOnly_)
+ outputStream_ = new BufferedOutputStream(inputFile_.getOutputStream());
+ } catch (IOException iox) {
+ throw new TTransportException(TTransportException.NOT_OPEN, iox);
+ }
+ }
+
+ /**
+ * Closes the transport.
+ */
+ public void close() {
+ if (inputFile_ != null) {
+ try {
+ inputFile_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("WARNING: Error closing input file: " +
+ iox.getMessage());
+ }
+ inputFile_ = null;
+ }
+ if (outputStream_ != null) {
+ try {
+ outputStream_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("WARNING: Error closing output stream: " +
+ iox.getMessage());
+ }
+ outputStream_ = null;
+ }
+ }
+
+
+ /**
+ * File Transport ctor
+ *
+ * @param path File path to read and write from
+ * @param readOnly Whether this is a read-only transport
+ */
+ public TFileTransport(final String path, boolean readOnly) throws IOException {
+ inputFile_ = new TStandardFile(path);
+ readOnly_ = readOnly;
+ }
+
+ /**
+ * File Transport ctor
+ *
+ * @param inputFile open TSeekableFile to read/write from
+ * @param readOnly Whether this is a read-only transport
+ */
+ public TFileTransport(TSeekableFile inputFile, boolean readOnly) {
+ inputFile_ = inputFile;
+ readOnly_ = readOnly;
+ }
+
+
+ /**
+ * Cloned from TTransport.java:readAll(). Only difference is throwing an EOF exception
+ * where one is detected.
+ */
+ public int readAll(byte[] buf, int off, int len)
+ throws TTransportException {
+ int got = 0;
+ int ret = 0;
+ while (got < len) {
+ ret = read(buf, off+got, len-got);
+ if (ret < 0) {
+ throw new TTransportException("Error in reading from file");
+ }
+ if(ret == 0) {
+ throw new TTransportException(TTransportException.END_OF_FILE,
+ "End of File reached");
+ }
+ got += ret;
+ }
+ return got;
+ }
+
+
+ /**
+ * Reads up to len bytes into buffer buf, starting at offset off.
+ *
+ * @param buf Array to read into
+ * @param off Index to start reading at
+ * @param len Maximum number of bytes to read
+ * @return The number of bytes actually read
+ * @throws TTransportException if there was an error reading data
+ */
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ if(!isOpen())
+ throw new TTransportException(TTransportException.NOT_OPEN,
+ "Must open before reading");
+
+ if(currentEvent_.getRemaining() == 0) {
+ if(!readEvent())
+ return(0);
+ }
+
+ int nread = currentEvent_.emit(buf, off, len);
+ return nread;
+ }
+
+ public int getNumChunks() throws TTransportException {
+ if(!isOpen())
+ throw new TTransportException(TTransportException.NOT_OPEN,
+ "Must open before getNumChunks");
+ try {
+ long len = inputFile_.length();
+ if(len == 0)
+ return 0;
+ else
+ return (((int)(len/cs.getChunkSize())) + 1);
+
+ } catch (IOException iox) {
+ throw new TTransportException(iox.getMessage(), iox);
+ }
+ }
+
+ public int getCurChunk() throws TTransportException {
+ if(!isOpen())
+ throw new TTransportException(TTransportException.NOT_OPEN,
+ "Must open before getCurChunk");
+ return (cs.getChunkNum());
+
+ }
+
+
+ public void seekToChunk(int chunk) throws TTransportException {
+ if(!isOpen())
+ throw new TTransportException(TTransportException.NOT_OPEN,
+ "Must open before seeking");
+
+ int numChunks = getNumChunks();
+
+ // file is empty, seeking to chunk is pointless
+ if (numChunks == 0) {
+ return;
+ }
+
+ // negative indicates reverse seek (from the end)
+ if (chunk < 0) {
+ chunk += numChunks;
+ }
+
+ // too large a value for reverse seek, just seek to beginning
+ if (chunk < 0) {
+ chunk = 0;
+ }
+
+ long eofOffset=0;
+ boolean seekToEnd = (chunk >= numChunks);
+ if(seekToEnd) {
+ chunk = chunk - 1;
+ try { eofOffset = inputFile_.length(); }
+ catch (IOException iox) {throw new TTransportException(iox.getMessage(),
+ iox);}
+ }
+
+ if(chunk*cs.getChunkSize() != cs.getOffset()) {
+ try { inputFile_.seek((long)chunk*cs.getChunkSize()); }
+ catch (IOException iox) {
+ throw new TTransportException("Seek to chunk " +
+ chunk + " " +iox.getMessage(), iox);
+ }
+
+ cs.seek((long)chunk*cs.getChunkSize());
+ currentEvent_.setAvailable(0);
+ inputStream_ = createInputStream();
+ }
+
+ if(seekToEnd) {
+ // waiting forever here - otherwise we can hit EOF and end up
+ // having consumed partial data from the data stream.
+ TailPolicy old = setTailPolicy(TailPolicy.WAIT_FOREVER);
+ while(cs.getOffset() < eofOffset) { readEvent(); }
+ currentEvent_.setAvailable(0);
+ setTailPolicy(old);
+ }
+ }
+
+ public void seekToEnd() throws TTransportException {
+ if(!isOpen())
+ throw new TTransportException(TTransportException.NOT_OPEN,
+ "Must open before seeking");
+ seekToChunk(getNumChunks());
+ }
+
+
+ /**
+ * Writes up to len bytes from the buffer.
+ *
+ * @param buf The output data buffer
+ * @param off The offset to start writing from
+ * @param len The number of bytes to write
+ * @throws TTransportException if there was an error writing data
+ */
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ throw new TTransportException("Not Supported");
+ }
+
+ /**
+ * Flush any pending data out of a transport buffer.
+ *
+ * @throws TTransportException if there was an error writing out data.
+ */
+ public void flush() throws TTransportException {
+ throw new TTransportException("Not Supported");
+ }
+
+ /**
+ * test program
+ *
+ */
+ public static void main(String[] args) throws Exception {
+
+ int num_chunks = 10;
+
+ if((args.length < 1) || args[0].equals("--help")
+ || args[0].equals("-h") || args[0].equals("-?")) {
+ printUsage();
+ }
+
+ if(args.length > 1) {
+ try {
+ num_chunks = Integer.parseInt(args[1]);
+ } catch (Exception e) {
+ LOGGER.error("Cannot parse " + args[1]);
+ printUsage();
+ }
+ }
+
+ TFileTransport t = new TFileTransport(args[0], true);
+ t.open();
+ LOGGER.info("NumChunks="+t.getNumChunks());
+
+ Random r = new Random();
+ for(int j=0; j<num_chunks; j++) {
+ byte[] buf = new byte[4096];
+ int cnum = r.nextInt(t.getNumChunks()-1);
+ LOGGER.info("Reading chunk "+cnum);
+ t.seekToChunk(cnum);
+ for(int i=0; i<4096; i++) {
+ t.read(buf, 0, 4096);
+ }
+ }
+ }
+
+ private static void printUsage() {
+ LOGGER.error("Usage: TFileTransport <filename> [num_chunks]");
+ LOGGER.error(" (Opens and reads num_chunks chunks from file randomly)");
+ System.exit(1);
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFramedTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFramedTransport.java
new file mode 100644
index 000000000..a006c3a6a
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TFramedTransport.java
@@ -0,0 +1,190 @@
+/*
+ * 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.thrift.transport;
+
+import org.apache.thrift.TByteArrayOutputStream;
+
+/**
+ * TFramedTransport is a buffered TTransport that ensures a fully read message
+ * every time by preceding messages with a 4-byte frame size.
+ */
+public class TFramedTransport extends TTransport {
+
+ protected static final int DEFAULT_MAX_LENGTH = 16384000;
+
+ private int maxLength_;
+
+ /**
+ * Underlying transport
+ */
+ private TTransport transport_ = null;
+
+ /**
+ * Buffer for output
+ */
+ private final TByteArrayOutputStream writeBuffer_ =
+ new TByteArrayOutputStream(1024);
+
+ /**
+ * Buffer for input
+ */
+ private final TMemoryInputTransport readBuffer_ =
+ new TMemoryInputTransport(new byte[0]);
+
+ public static class Factory extends TTransportFactory {
+ private int maxLength_;
+
+ public Factory() {
+ maxLength_ = TFramedTransport.DEFAULT_MAX_LENGTH;
+ }
+
+ public Factory(int maxLength) {
+ maxLength_ = maxLength;
+ }
+
+ @Override
+ public TTransport getTransport(TTransport base) {
+ return new TFramedTransport(base, maxLength_);
+ }
+ }
+
+ /**
+ * Something to fill in the first four bytes of the buffer
+ * to make room for the frame size. This allows the
+ * implementation to write once instead of twice.
+ */
+ private static final byte[] sizeFiller_ = new byte[] { 0x00, 0x00, 0x00, 0x00 };
+
+ /**
+ * Constructor wraps around another transport
+ */
+ public TFramedTransport(TTransport transport, int maxLength) {
+ transport_ = transport;
+ maxLength_ = maxLength;
+ writeBuffer_.write(sizeFiller_, 0, 4);
+ }
+
+ public TFramedTransport(TTransport transport) {
+ transport_ = transport;
+ maxLength_ = TFramedTransport.DEFAULT_MAX_LENGTH;
+ writeBuffer_.write(sizeFiller_, 0, 4);
+ }
+
+ public void open() throws TTransportException {
+ transport_.open();
+ }
+
+ public boolean isOpen() {
+ return transport_.isOpen();
+ }
+
+ public void close() {
+ transport_.close();
+ }
+
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ int got = readBuffer_.read(buf, off, len);
+ if (got > 0) {
+ return got;
+ }
+
+ // Read another frame of data
+ readFrame();
+
+ return readBuffer_.read(buf, off, len);
+ }
+
+ @Override
+ public byte[] getBuffer() {
+ return readBuffer_.getBuffer();
+ }
+
+ @Override
+ public int getBufferPosition() {
+ return readBuffer_.getBufferPosition();
+ }
+
+ @Override
+ public int getBytesRemainingInBuffer() {
+ return readBuffer_.getBytesRemainingInBuffer();
+ }
+
+ @Override
+ public void consumeBuffer(int len) {
+ readBuffer_.consumeBuffer(len);
+ }
+
+ public void clear() {
+ readBuffer_.clear();
+ }
+
+ private final byte[] i32buf = new byte[4];
+
+ private void readFrame() throws TTransportException {
+ transport_.readAll(i32buf, 0, 4);
+ int size = decodeFrameSize(i32buf);
+
+ if (size < 0) {
+ close();
+ throw new TTransportException(TTransportException.CORRUPTED_DATA, "Read a negative frame size (" + size + ")!");
+ }
+
+ if (size > maxLength_) {
+ close();
+ throw new TTransportException(TTransportException.CORRUPTED_DATA,
+ "Frame size (" + size + ") larger than max length (" + maxLength_ + ")!");
+ }
+
+ byte[] buff = new byte[size];
+ transport_.readAll(buff, 0, size);
+ readBuffer_.reset(buff);
+ }
+
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ writeBuffer_.write(buf, off, len);
+ }
+
+ @Override
+ public void flush() throws TTransportException {
+ byte[] buf = writeBuffer_.get();
+ int len = writeBuffer_.len() - 4; // account for the prepended frame size
+ writeBuffer_.reset();
+ writeBuffer_.write(sizeFiller_, 0, 4); // make room for the next frame's size data
+
+ encodeFrameSize(len, buf); // this is the frame length without the filler
+ transport_.write(buf, 0, len + 4); // we have to write the frame size and frame data
+ transport_.flush();
+ }
+
+ public static final void encodeFrameSize(final int frameSize, final byte[] buf) {
+ buf[0] = (byte)(0xff & (frameSize >> 24));
+ buf[1] = (byte)(0xff & (frameSize >> 16));
+ buf[2] = (byte)(0xff & (frameSize >> 8));
+ buf[3] = (byte)(0xff & (frameSize));
+ }
+
+ public static final int decodeFrameSize(final byte[] buf) {
+ return
+ ((buf[0] & 0xff) << 24) |
+ ((buf[1] & 0xff) << 16) |
+ ((buf[2] & 0xff) << 8) |
+ ((buf[3] & 0xff));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/THttpClient.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/THttpClient.java
new file mode 100644
index 000000000..c3063fe43
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/THttpClient.java
@@ -0,0 +1,362 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.params.CoreConnectionPNames;
+
+/**
+ * HTTP implementation of the TTransport interface. Used for working with a
+ * Thrift web services implementation (using for example TServlet).
+ *
+ * This class offers two implementations of the HTTP transport.
+ * One uses HttpURLConnection instances, the other HttpClient from Apache
+ * Http Components.
+ * The chosen implementation depends on the constructor used to
+ * create the THttpClient instance.
+ * Using the THttpClient(String url) constructor or passing null as the
+ * HttpClient to THttpClient(String url, HttpClient client) will create an
+ * instance which will use HttpURLConnection.
+ *
+ * When using HttpClient, the following configuration leads to 5-15%
+ * better performance than the HttpURLConnection implementation:
+ *
+ * http.protocol.version=HttpVersion.HTTP_1_1
+ * http.protocol.content-charset=UTF-8
+ * http.protocol.expect-continue=false
+ * http.connection.stalecheck=false
+ *
+ * Also note that under high load, the HttpURLConnection implementation
+ * may exhaust the open file descriptor limit.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/THRIFT-970">THRIFT-970</a>
+ */
+
+public class THttpClient extends TTransport {
+
+ private URL url_ = null;
+
+ private final ByteArrayOutputStream requestBuffer_ = new ByteArrayOutputStream();
+
+ private InputStream inputStream_ = null;
+
+ private int connectTimeout_ = 0;
+
+ private int readTimeout_ = 0;
+
+ private Map<String,String> customHeaders_ = null;
+
+ private final HttpHost host;
+
+ private final HttpClient client;
+
+ public static class Factory extends TTransportFactory {
+
+ private final String url;
+ private final HttpClient client;
+
+ public Factory(String url) {
+ this.url = url;
+ this.client = null;
+ }
+
+ public Factory(String url, HttpClient client) {
+ this.url = url;
+ this.client = client;
+ }
+
+ @Override
+ public TTransport getTransport(TTransport trans) {
+ try {
+ if (null != client) {
+ return new THttpClient(url, client);
+ } else {
+ return new THttpClient(url);
+ }
+ } catch (TTransportException tte) {
+ return null;
+ }
+ }
+ }
+
+ public THttpClient(String url) throws TTransportException {
+ try {
+ url_ = new URL(url);
+ this.client = null;
+ this.host = null;
+ } catch (IOException iox) {
+ throw new TTransportException(iox);
+ }
+ }
+
+ public THttpClient(String url, HttpClient client) throws TTransportException {
+ try {
+ url_ = new URL(url);
+ this.client = client;
+ this.host = new HttpHost(url_.getHost(), -1 == url_.getPort() ? url_.getDefaultPort() : url_.getPort(), url_.getProtocol());
+ } catch (IOException iox) {
+ throw new TTransportException(iox);
+ }
+ }
+
+ public void setConnectTimeout(int timeout) {
+ connectTimeout_ = timeout;
+ if (null != this.client) {
+ // WARNING, this modifies the HttpClient params, this might have an impact elsewhere if the
+ // same HttpClient is used for something else.
+ client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectTimeout_);
+ }
+ }
+
+ public void setReadTimeout(int timeout) {
+ readTimeout_ = timeout;
+ if (null != this.client) {
+ // WARNING, this modifies the HttpClient params, this might have an impact elsewhere if the
+ // same HttpClient is used for something else.
+ client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, readTimeout_);
+ }
+ }
+
+ public void setCustomHeaders(Map<String,String> headers) {
+ customHeaders_ = headers;
+ }
+
+ public void setCustomHeader(String key, String value) {
+ if (customHeaders_ == null) {
+ customHeaders_ = new HashMap<String, String>();
+ }
+ customHeaders_.put(key, value);
+ }
+
+ public void open() {}
+
+ public void close() {
+ if (null != inputStream_) {
+ try {
+ inputStream_.close();
+ } catch (IOException ioe) {
+ ;
+ }
+ inputStream_ = null;
+ }
+ }
+
+ public boolean isOpen() {
+ return true;
+ }
+
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ if (inputStream_ == null) {
+ throw new TTransportException("Response buffer is empty, no request.");
+ }
+ try {
+ int ret = inputStream_.read(buf, off, len);
+ if (ret == -1) {
+ throw new TTransportException("No more data available.");
+ }
+ return ret;
+ } catch (IOException iox) {
+ throw new TTransportException(iox);
+ }
+ }
+
+ public void write(byte[] buf, int off, int len) {
+ requestBuffer_.write(buf, off, len);
+ }
+
+ /**
+ * copy from org.apache.http.util.EntityUtils#consume. Android has it's own httpcore
+ * that doesn't have a consume.
+ */
+ private static void consume(final HttpEntity entity) throws IOException {
+ if (entity == null) {
+ return;
+ }
+ if (entity.isStreaming()) {
+ InputStream instream = entity.getContent();
+ if (instream != null) {
+ instream.close();
+ }
+ }
+ }
+
+ private void flushUsingHttpClient() throws TTransportException {
+
+ if (null == this.client) {
+ throw new TTransportException("Null HttpClient, aborting.");
+ }
+
+ // Extract request and reset buffer
+ byte[] data = requestBuffer_.toByteArray();
+ requestBuffer_.reset();
+
+ HttpPost post = null;
+
+ InputStream is = null;
+
+ try {
+ // Set request to path + query string
+ post = new HttpPost(this.url_.getFile());
+
+ //
+ // Headers are added to the HttpPost instance, not
+ // to HttpClient.
+ //
+
+ post.setHeader("Content-Type", "application/x-thrift");
+ post.setHeader("Accept", "application/x-thrift");
+ post.setHeader("User-Agent", "Java/THttpClient/HC");
+
+ if (null != customHeaders_) {
+ for (Map.Entry<String, String> header : customHeaders_.entrySet()) {
+ post.setHeader(header.getKey(), header.getValue());
+ }
+ }
+
+ post.setEntity(new ByteArrayEntity(data));
+
+ HttpResponse response = this.client.execute(this.host, post);
+ int responseCode = response.getStatusLine().getStatusCode();
+
+ //
+ // Retrieve the inputstream BEFORE checking the status code so
+ // resources get freed in the finally clause.
+ //
+
+ is = response.getEntity().getContent();
+
+ if (responseCode != HttpStatus.SC_OK) {
+ throw new TTransportException("HTTP Response code: " + responseCode);
+ }
+
+ // Read the responses into a byte array so we can release the connection
+ // early. This implies that the whole content will have to be read in
+ // memory, and that momentarily we might use up twice the memory (while the
+ // thrift struct is being read up the chain).
+ // Proceeding differently might lead to exhaustion of connections and thus
+ // to app failure.
+
+ byte[] buf = new byte[1024];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ int len = 0;
+ do {
+ len = is.read(buf);
+ if (len > 0) {
+ baos.write(buf, 0, len);
+ }
+ } while (-1 != len);
+
+ try {
+ // Indicate we're done with the content.
+ consume(response.getEntity());
+ } catch (IOException ioe) {
+ // We ignore this exception, it might only mean the server has no
+ // keep-alive capability.
+ }
+
+ inputStream_ = new ByteArrayInputStream(baos.toByteArray());
+ } catch (IOException ioe) {
+ // Abort method so the connection gets released back to the connection manager
+ if (null != post) {
+ post.abort();
+ }
+ throw new TTransportException(ioe);
+ } finally {
+ if (null != is) {
+ // Close the entity's input stream, this will release the underlying connection
+ try {
+ is.close();
+ } catch (IOException ioe) {
+ throw new TTransportException(ioe);
+ }
+ }
+ if (post != null) {
+ post.releaseConnection();
+ }
+ }
+ }
+
+ public void flush() throws TTransportException {
+
+ if (null != this.client) {
+ flushUsingHttpClient();
+ return;
+ }
+
+ // Extract request and reset buffer
+ byte[] data = requestBuffer_.toByteArray();
+ requestBuffer_.reset();
+
+ try {
+ // Create connection object
+ HttpURLConnection connection = (HttpURLConnection)url_.openConnection();
+
+ // Timeouts, only if explicitly set
+ if (connectTimeout_ > 0) {
+ connection.setConnectTimeout(connectTimeout_);
+ }
+ if (readTimeout_ > 0) {
+ connection.setReadTimeout(readTimeout_);
+ }
+
+ // Make the request
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", "application/x-thrift");
+ connection.setRequestProperty("Accept", "application/x-thrift");
+ connection.setRequestProperty("User-Agent", "Java/THttpClient");
+ if (customHeaders_ != null) {
+ for (Map.Entry<String, String> header : customHeaders_.entrySet()) {
+ connection.setRequestProperty(header.getKey(), header.getValue());
+ }
+ }
+ connection.setDoOutput(true);
+ connection.connect();
+ connection.getOutputStream().write(data);
+
+ int responseCode = connection.getResponseCode();
+ if (responseCode != HttpURLConnection.HTTP_OK) {
+ throw new TTransportException("HTTP Response code: " + responseCode);
+ }
+
+ // Read the responses
+ inputStream_ = connection.getInputStream();
+
+ } catch (IOException iox) {
+ throw new TTransportException(iox);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TIOStreamTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TIOStreamTransport.java
new file mode 100644
index 000000000..2d31f392f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TIOStreamTransport.java
@@ -0,0 +1,162 @@
+/*
+ * 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.thrift.transport;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This is the most commonly used base transport. It takes an InputStream
+ * and an OutputStream and uses those to perform all transport operations.
+ * This allows for compatibility with all the nice constructs Java already
+ * has to provide a variety of types of streams.
+ *
+ */
+public class TIOStreamTransport extends TTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TIOStreamTransport.class.getName());
+
+ /** Underlying inputStream */
+ protected InputStream inputStream_ = null;
+
+ /** Underlying outputStream */
+ protected OutputStream outputStream_ = null;
+
+ /**
+ * Subclasses can invoke the default constructor and then assign the input
+ * streams in the open method.
+ */
+ protected TIOStreamTransport() {}
+
+ /**
+ * Input stream constructor.
+ *
+ * @param is Input stream to read from
+ */
+ public TIOStreamTransport(InputStream is) {
+ inputStream_ = is;
+ }
+
+ /**
+ * Output stream constructor.
+ *
+ * @param os Output stream to read from
+ */
+ public TIOStreamTransport(OutputStream os) {
+ outputStream_ = os;
+ }
+
+ /**
+ * Two-way stream constructor.
+ *
+ * @param is Input stream to read from
+ * @param os Output stream to read from
+ */
+ public TIOStreamTransport(InputStream is, OutputStream os) {
+ inputStream_ = is;
+ outputStream_ = os;
+ }
+
+ /**
+ *
+ * @return false after close is called.
+ */
+ public boolean isOpen() {
+ return inputStream_ != null && outputStream_ != null;
+ }
+
+ /**
+ * The streams must already be open. This method does nothing.
+ */
+ public void open() throws TTransportException {}
+
+ /**
+ * Closes both the input and output streams.
+ */
+ public void close() {
+ if (inputStream_ != null) {
+ try {
+ inputStream_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("Error closing input stream.", iox);
+ }
+ inputStream_ = null;
+ }
+ if (outputStream_ != null) {
+ try {
+ outputStream_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("Error closing output stream.", iox);
+ }
+ outputStream_ = null;
+ }
+ }
+
+ /**
+ * Reads from the underlying input stream if not null.
+ */
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ if (inputStream_ == null) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Cannot read from null inputStream");
+ }
+ int bytesRead;
+ try {
+ bytesRead = inputStream_.read(buf, off, len);
+ } catch (IOException iox) {
+ throw new TTransportException(TTransportException.UNKNOWN, iox);
+ }
+ if (bytesRead < 0) {
+ throw new TTransportException(TTransportException.END_OF_FILE, "Socket is closed by peer.");
+ }
+ return bytesRead;
+ }
+
+ /**
+ * Writes to the underlying output stream if not null.
+ */
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ if (outputStream_ == null) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Cannot write to null outputStream");
+ }
+ try {
+ outputStream_.write(buf, off, len);
+ } catch (IOException iox) {
+ throw new TTransportException(TTransportException.UNKNOWN, iox);
+ }
+ }
+
+ /**
+ * Flushes the underlying output stream if not null.
+ */
+ public void flush() throws TTransportException {
+ if (outputStream_ == null) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Cannot flush null outputStream");
+ }
+ try {
+ outputStream_.flush();
+ } catch (IOException iox) {
+ throw new TTransportException(TTransportException.UNKNOWN, iox);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java
new file mode 100644
index 000000000..b19ac86d2
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java
@@ -0,0 +1,104 @@
+/*
+ * 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.thrift.transport;
+
+import org.apache.thrift.TByteArrayOutputStream;
+import java.nio.charset.Charset;
+
+/**
+ * Memory buffer-based implementation of the TTransport interface.
+ */
+public class TMemoryBuffer extends TTransport {
+ /**
+ * Create a TMemoryBuffer with an initial buffer size of <i>size</i>. The
+ * internal buffer will grow as necessary to accommodate the size of the data
+ * being written to it.
+ *
+ * @param size the initial size of the buffer
+ */
+ public TMemoryBuffer(int size) {
+ arr_ = new TByteArrayOutputStream(size);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public void open() {
+ /* Do nothing */
+ }
+
+ @Override
+ public void close() {
+ /* Do nothing */
+ }
+
+ @Override
+ public int read(byte[] buf, int off, int len) {
+ byte[] src = arr_.get();
+ int amtToRead = (len > arr_.len() - pos_ ? arr_.len() - pos_ : len);
+ if (amtToRead > 0) {
+ System.arraycopy(src, pos_, buf, off, amtToRead);
+ pos_ += amtToRead;
+ }
+ return amtToRead;
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ arr_.write(buf, off, len);
+ }
+
+ /**
+ * Output the contents of the memory buffer as a String, using the supplied
+ * encoding
+ * @param charset the encoding to use
+ * @return the contents of the memory buffer as a String
+ */
+ public String toString(Charset charset) {
+ return arr_.toString(charset);
+ }
+
+ public String inspect() {
+ StringBuilder buf = new StringBuilder();
+ byte[] bytes = arr_.toByteArray();
+ for (int i = 0; i < bytes.length; i++) {
+ buf.append(pos_ == i ? "==>" : "" ).append(Integer.toHexString(bytes[i] & 0xff)).append(" ");
+ }
+ return buf.toString();
+ }
+
+ // The contents of the buffer
+ private TByteArrayOutputStream arr_;
+
+ // Position to read next byte from
+ private int pos_;
+
+ public int length() {
+ return arr_.size();
+ }
+
+ public byte[] getArray() {
+ return arr_.get();
+ }
+}
+
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryInputTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryInputTransport.java
new file mode 100644
index 000000000..2530dcc36
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TMemoryInputTransport.java
@@ -0,0 +1,96 @@
+/*
+ * 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.thrift.transport;
+
+public final class TMemoryInputTransport extends TTransport {
+
+ private byte[] buf_;
+ private int pos_;
+ private int endPos_;
+
+ public TMemoryInputTransport() {
+ }
+
+ public TMemoryInputTransport(byte[] buf) {
+ reset(buf);
+ }
+
+ public TMemoryInputTransport(byte[] buf, int offset, int length) {
+ reset(buf, offset, length);
+ }
+
+ public void reset(byte[] buf) {
+ reset(buf, 0, buf.length);
+ }
+
+ public void reset(byte[] buf, int offset, int length) {
+ buf_ = buf;
+ pos_ = offset;
+ endPos_ = offset + length;
+ }
+
+ public void clear() {
+ buf_ = null;
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public void open() throws TTransportException {}
+
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ int bytesRemaining = getBytesRemainingInBuffer();
+ int amtToRead = (len > bytesRemaining ? bytesRemaining : len);
+ if (amtToRead > 0) {
+ System.arraycopy(buf_, pos_, buf, off, amtToRead);
+ consumeBuffer(amtToRead);
+ }
+ return amtToRead;
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ throw new UnsupportedOperationException("No writing allowed!");
+ }
+
+ @Override
+ public byte[] getBuffer() {
+ return buf_;
+ }
+
+ public int getBufferPosition() {
+ return pos_;
+ }
+
+ public int getBytesRemainingInBuffer() {
+ return endPos_ - pos_;
+ }
+
+ public void consumeBuffer(int len) {
+ pos_ += len;
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java
new file mode 100644
index 000000000..df37cb06e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java
@@ -0,0 +1,163 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.SocketException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Wrapper around ServerSocketChannel
+ */
+public class TNonblockingServerSocket extends TNonblockingServerTransport {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TNonblockingServerSocket.class.getName());
+
+ /**
+ * This channel is where all the nonblocking magic happens.
+ */
+ private ServerSocketChannel serverSocketChannel = null;
+
+ /**
+ * Underlying ServerSocket object
+ */
+ private ServerSocket serverSocket_ = null;
+
+ /**
+ * Timeout for client sockets from accept
+ */
+ private int clientTimeout_ = 0;
+
+ public static class NonblockingAbstractServerSocketArgs extends
+ AbstractServerTransportArgs<NonblockingAbstractServerSocketArgs> {}
+
+ /**
+ * Creates just a port listening server socket
+ */
+ public TNonblockingServerSocket(int port) throws TTransportException {
+ this(port, 0);
+ }
+
+ /**
+ * Creates just a port listening server socket
+ */
+ public TNonblockingServerSocket(int port, int clientTimeout) throws TTransportException {
+ this(new NonblockingAbstractServerSocketArgs().port(port).clientTimeout(clientTimeout));
+ }
+
+ public TNonblockingServerSocket(InetSocketAddress bindAddr) throws TTransportException {
+ this(bindAddr, 0);
+ }
+
+ public TNonblockingServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
+ this(new NonblockingAbstractServerSocketArgs().bindAddr(bindAddr).clientTimeout(clientTimeout));
+ }
+
+ public TNonblockingServerSocket(NonblockingAbstractServerSocketArgs args) throws TTransportException {
+ clientTimeout_ = args.clientTimeout;
+ try {
+ serverSocketChannel = ServerSocketChannel.open();
+ serverSocketChannel.configureBlocking(false);
+
+ // Make server socket
+ serverSocket_ = serverSocketChannel.socket();
+ // Prevent 2MSL delay problem on server restarts
+ serverSocket_.setReuseAddress(true);
+ // Bind to listening port
+ serverSocket_.bind(args.bindAddr, args.backlog);
+ } catch (IOException ioe) {
+ serverSocket_ = null;
+ throw new TTransportException("Could not create ServerSocket on address " + args.bindAddr.toString() + ".", ioe);
+ }
+ }
+
+ public void listen() throws TTransportException {
+ // Make sure not to block on accept
+ if (serverSocket_ != null) {
+ try {
+ serverSocket_.setSoTimeout(0);
+ } catch (SocketException sx) {
+ LOGGER.error("Socket exception while setting socket timeout", sx);
+ }
+ }
+ }
+
+ protected TNonblockingSocket acceptImpl() throws TTransportException {
+ if (serverSocket_ == null) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "No underlying server socket.");
+ }
+ try {
+ SocketChannel socketChannel = serverSocketChannel.accept();
+ if (socketChannel == null) {
+ return null;
+ }
+
+ TNonblockingSocket tsocket = new TNonblockingSocket(socketChannel);
+ tsocket.setTimeout(clientTimeout_);
+ return tsocket;
+ } catch (IOException iox) {
+ throw new TTransportException(iox);
+ }
+ }
+
+ public void registerSelector(Selector selector) {
+ try {
+ // Register the server socket channel, indicating an interest in
+ // accepting new connections
+ serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
+ } catch (ClosedChannelException e) {
+ // this shouldn't happen, ideally...
+ // TODO: decide what to do with this.
+ }
+ }
+
+ public void close() {
+ if (serverSocket_ != null) {
+ try {
+ serverSocket_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("WARNING: Could not close server socket: " + iox.getMessage());
+ }
+ serverSocket_ = null;
+ }
+ }
+
+ public void interrupt() {
+ // The thread-safeness of this is dubious, but Java documentation suggests
+ // that it is safe to do this from a different thread context
+ close();
+ }
+
+ public int getPort() {
+ if (serverSocket_ == null)
+ return -1;
+ return serverSocket_.getLocalPort();
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerTransport.java
new file mode 100644
index 000000000..ba45b09dc
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerTransport.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.thrift.transport;
+
+import java.nio.channels.Selector;
+
+/**
+ * Server transport that can be operated in a nonblocking fashion.
+ */
+public abstract class TNonblockingServerTransport extends TServerTransport {
+
+ public abstract void registerSelector(Selector selector);
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java
new file mode 100644
index 000000000..f86a48b42
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java
@@ -0,0 +1,210 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Transport for use with async client.
+ */
+public class TNonblockingSocket extends TNonblockingTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TNonblockingSocket.class.getName());
+
+ /**
+ * Host and port if passed in, used for lazy non-blocking connect.
+ */
+ private final SocketAddress socketAddress_;
+
+ private final SocketChannel socketChannel_;
+
+ public TNonblockingSocket(String host, int port) throws IOException {
+ this(host, port, 0);
+ }
+
+ /**
+ * Create a new nonblocking socket transport that will be connected to host:port.
+ * @param host
+ * @param port
+ * @throws IOException
+ */
+ public TNonblockingSocket(String host, int port, int timeout) throws IOException {
+ this(SocketChannel.open(), timeout, new InetSocketAddress(host, port));
+ }
+
+ /**
+ * Constructor that takes an already created socket.
+ *
+ * @param socketChannel Already created SocketChannel object
+ * @throws IOException if there is an error setting up the streams
+ */
+ public TNonblockingSocket(SocketChannel socketChannel) throws IOException {
+ this(socketChannel, 0, null);
+ if (!socketChannel.isConnected()) throw new IOException("Socket must already be connected");
+ }
+
+ private TNonblockingSocket(SocketChannel socketChannel, int timeout, SocketAddress socketAddress)
+ throws IOException {
+ socketChannel_ = socketChannel;
+ socketAddress_ = socketAddress;
+
+ // make it a nonblocking channel
+ socketChannel.configureBlocking(false);
+
+ // set options
+ Socket socket = socketChannel.socket();
+ socket.setSoLinger(false, 0);
+ socket.setTcpNoDelay(true);
+ socket.setKeepAlive(true);
+ setTimeout(timeout);
+ }
+
+ /**
+ * Register the new SocketChannel with our Selector, indicating
+ * we'd like to be notified when it's ready for I/O.
+ *
+ * @param selector
+ * @return the selection key for this socket.
+ */
+ public SelectionKey registerSelector(Selector selector, int interests) throws IOException {
+ return socketChannel_.register(selector, interests);
+ }
+
+ /**
+ * Sets the socket timeout, although this implementation never uses blocking operations so it is unused.
+ *
+ * @param timeout Milliseconds timeout
+ */
+ public void setTimeout(int timeout) {
+ try {
+ socketChannel_.socket().setSoTimeout(timeout);
+ } catch (SocketException sx) {
+ LOGGER.warn("Could not set socket timeout.", sx);
+ }
+ }
+
+ /**
+ * Returns a reference to the underlying SocketChannel.
+ */
+ public SocketChannel getSocketChannel() {
+ return socketChannel_;
+ }
+
+ /**
+ * Checks whether the socket is connected.
+ */
+ public boolean isOpen() {
+ // isConnected() does not return false after close(), but isOpen() does
+ return socketChannel_.isOpen() && socketChannel_.isConnected();
+ }
+
+ /**
+ * Do not call, the implementation provides its own lazy non-blocking connect.
+ */
+ public void open() throws TTransportException {
+ throw new RuntimeException("open() is not implemented for TNonblockingSocket");
+ }
+
+ /**
+ * Perform a nonblocking read into buffer.
+ */
+ public int read(ByteBuffer buffer) throws IOException {
+ return socketChannel_.read(buffer);
+ }
+
+
+ /**
+ * Reads from the underlying input stream if not null.
+ */
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ if ((socketChannel_.validOps() & SelectionKey.OP_READ) != SelectionKey.OP_READ) {
+ throw new TTransportException(TTransportException.NOT_OPEN,
+ "Cannot read from write-only socket channel");
+ }
+ try {
+ return socketChannel_.read(ByteBuffer.wrap(buf, off, len));
+ } catch (IOException iox) {
+ throw new TTransportException(TTransportException.UNKNOWN, iox);
+ }
+ }
+
+ /**
+ * Perform a nonblocking write of the data in buffer;
+ */
+ public int write(ByteBuffer buffer) throws IOException {
+ return socketChannel_.write(buffer);
+ }
+
+ /**
+ * Writes to the underlying output stream if not null.
+ */
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ if ((socketChannel_.validOps() & SelectionKey.OP_WRITE) != SelectionKey.OP_WRITE) {
+ throw new TTransportException(TTransportException.NOT_OPEN,
+ "Cannot write to write-only socket channel");
+ }
+ try {
+ socketChannel_.write(ByteBuffer.wrap(buf, off, len));
+ } catch (IOException iox) {
+ throw new TTransportException(TTransportException.UNKNOWN, iox);
+ }
+ }
+
+ /**
+ * Noop.
+ */
+ public void flush() throws TTransportException {
+ // Not supported by SocketChannel.
+ }
+
+ /**
+ * Closes the socket.
+ */
+ public void close() {
+ try {
+ socketChannel_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("Could not close socket.", iox);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean startConnect() throws IOException {
+ return socketChannel_.connect(socketAddress_);
+ }
+
+ /** {@inheritDoc} */
+ public boolean finishConnect() throws IOException {
+ return socketChannel_.finishConnect();
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingTransport.java
new file mode 100644
index 000000000..43c130688
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingTransport.java
@@ -0,0 +1,47 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+
+public abstract class TNonblockingTransport extends TTransport {
+
+ /**
+ * Non-blocking connection initialization.
+ * @see java.nio.channels.SocketChannel#connect(SocketAddress remote)
+ */
+ public abstract boolean startConnect() throws IOException;
+
+ /**
+ * Non-blocking connection completion.
+ * @see java.nio.channels.SocketChannel#finishConnect()
+ */
+ public abstract boolean finishConnect() throws IOException;
+
+ public abstract SelectionKey registerSelector(Selector selector, int interests) throws IOException;
+
+ public abstract int read(ByteBuffer buffer) throws IOException;
+
+ public abstract int write(ByteBuffer buffer) throws IOException;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java
new file mode 100644
index 000000000..73dfaaf18
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java
@@ -0,0 +1,447 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.security.KeyStore;
+import java.util.Arrays;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Factory for providing and setting up Client and Server SSL wrapped
+ * TSocket and TServerSocket
+ */
+public class TSSLTransportFactory {
+
+ private static final Logger LOGGER =
+ LoggerFactory.getLogger(TSSLTransportFactory.class);
+
+ /**
+ * Get a SSL wrapped TServerSocket bound to the specified port. In this
+ * configuration the default settings are used. Default settings are retrieved
+ * from System properties that are set.
+ *
+ * Example system properties:
+ * -Djavax.net.ssl.trustStore=&lt;truststore location&gt;
+ * -Djavax.net.ssl.trustStorePassword=password
+ * -Djavax.net.ssl.keyStore=&lt;keystore location&gt;
+ * -Djavax.net.ssl.keyStorePassword=password
+ *
+ * @param port
+ * @return A SSL wrapped TServerSocket
+ * @throws TTransportException
+ */
+ public static TServerSocket getServerSocket(int port) throws TTransportException {
+ return getServerSocket(port, 0);
+ }
+
+ /**
+ * Get a default SSL wrapped TServerSocket bound to the specified port
+ *
+ * @param port
+ * @param clientTimeout
+ * @return A SSL wrapped TServerSocket
+ * @throws TTransportException
+ */
+ public static TServerSocket getServerSocket(int port, int clientTimeout) throws TTransportException {
+ return getServerSocket(port, clientTimeout, false, null);
+ }
+
+ /**
+ * Get a default SSL wrapped TServerSocket bound to the specified port and interface
+ *
+ * @param port
+ * @param clientTimeout
+ * @param ifAddress
+ * @return A SSL wrapped TServerSocket
+ * @throws TTransportException
+ */
+ public static TServerSocket getServerSocket(int port, int clientTimeout, boolean clientAuth, InetAddress ifAddress) throws TTransportException {
+ SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+ return createServer(factory, port, clientTimeout, clientAuth, ifAddress, null);
+ }
+
+ /**
+ * Get a configured SSL wrapped TServerSocket bound to the specified port and interface.
+ * Here the TSSLTransportParameters are used to set the values for the algorithms, keystore,
+ * truststore and other settings
+ *
+ * @param port
+ * @param clientTimeout
+ * @param ifAddress
+ * @param params
+ * @return A SSL wrapped TServerSocket
+ * @throws TTransportException
+ */
+ public static TServerSocket getServerSocket(int port, int clientTimeout, InetAddress ifAddress, TSSLTransportParameters params) throws TTransportException {
+ if (params == null || !(params.isKeyStoreSet || params.isTrustStoreSet)) {
+ throw new TTransportException("Either one of the KeyStore or TrustStore must be set for SSLTransportParameters");
+ }
+
+ SSLContext ctx = createSSLContext(params);
+ return createServer(ctx.getServerSocketFactory(), port, clientTimeout, params.clientAuth, ifAddress, params);
+ }
+
+ private static TServerSocket createServer(SSLServerSocketFactory factory, int port, int timeout, boolean clientAuth,
+ InetAddress ifAddress, TSSLTransportParameters params) throws TTransportException {
+ try {
+ SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(port, 100, ifAddress);
+ serverSocket.setSoTimeout(timeout);
+ serverSocket.setNeedClientAuth(clientAuth);
+ if (params != null && params.cipherSuites != null) {
+ serverSocket.setEnabledCipherSuites(params.cipherSuites);
+ }
+ return new TServerSocket(new TServerSocket.ServerSocketTransportArgs().
+ serverSocket(serverSocket).clientTimeout(timeout));
+ } catch (Exception e) {
+ throw new TTransportException("Could not bind to port " + port, e);
+ }
+ }
+
+ /**
+ * Get a default SSL wrapped TSocket connected to the specified host and port. All
+ * the client methods return a bound connection. So there is no need to call open() on the
+ * TTransport.
+ *
+ * @param host
+ * @param port
+ * @param timeout
+ * @return A SSL wrapped TSocket
+ * @throws TTransportException
+ */
+ public static TSocket getClientSocket(String host, int port, int timeout) throws TTransportException {
+ SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ return createClient(factory, host, port, timeout);
+ }
+
+ /**
+ * Get a default SSL wrapped TSocket connected to the specified host and port.
+ *
+ * @param host
+ * @param port
+ * @return A SSL wrapped TSocket
+ * @throws TTransportException
+ */
+ public static TSocket getClientSocket(String host, int port) throws TTransportException {
+ return getClientSocket(host, port, 0);
+ }
+
+ /**
+ * Get a custom configured SSL wrapped TSocket. The SSL settings are obtained from the
+ * passed in TSSLTransportParameters.
+ *
+ * @param host
+ * @param port
+ * @param timeout
+ * @param params
+ * @return A SSL wrapped TSocket
+ * @throws TTransportException
+ */
+ public static TSocket getClientSocket(String host, int port, int timeout, TSSLTransportParameters params) throws TTransportException {
+ if (params == null || !(params.isKeyStoreSet || params.isTrustStoreSet)) {
+ throw new TTransportException("Either one of the KeyStore or TrustStore must be set for SSLTransportParameters");
+ }
+
+ SSLContext ctx = createSSLContext(params);
+ return createClient(ctx.getSocketFactory(), host, port, timeout);
+ }
+
+ private static SSLContext createSSLContext(TSSLTransportParameters params) throws TTransportException {
+ SSLContext ctx;
+ InputStream in = null;
+ InputStream is = null;
+
+ try {
+ ctx = SSLContext.getInstance(params.protocol);
+ TrustManagerFactory tmf = null;
+ KeyManagerFactory kmf = null;
+
+ if (params.isTrustStoreSet) {
+ tmf = TrustManagerFactory.getInstance(params.trustManagerType);
+ KeyStore ts = KeyStore.getInstance(params.trustStoreType);
+ if (params.trustStoreStream != null) {
+ in = params.trustStoreStream;
+ } else {
+ in = getStoreAsStream(params.trustStore);
+ }
+ ts.load(in,
+ (params.trustPass != null ? params.trustPass.toCharArray() : null));
+ tmf.init(ts);
+ }
+
+ if (params.isKeyStoreSet) {
+ kmf = KeyManagerFactory.getInstance(params.keyManagerType);
+ KeyStore ks = KeyStore.getInstance(params.keyStoreType);
+ if (params.keyStoreStream != null) {
+ is = params.keyStoreStream;
+ } else {
+ is = getStoreAsStream(params.keyStore);
+ }
+ ks.load(is, params.keyPass.toCharArray());
+ kmf.init(ks, params.keyPass.toCharArray());
+ }
+
+ if (params.isKeyStoreSet && params.isTrustStoreSet) {
+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ }
+ else if (params.isKeyStoreSet) {
+ ctx.init(kmf.getKeyManagers(), null, null);
+ }
+ else {
+ ctx.init(null, tmf.getTrustManagers(), null);
+ }
+
+ } catch (Exception e) {
+ throw new TTransportException("Error creating the transport", e);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ LOGGER.warn("Unable to close stream", e);
+ }
+ }
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ LOGGER.warn("Unable to close stream", e);
+ }
+ }
+ }
+
+ return ctx;
+ }
+
+ private static InputStream getStoreAsStream(String store) throws IOException {
+ try {
+ return new FileInputStream(store);
+ } catch(FileNotFoundException e) {
+ }
+
+ InputStream storeStream = null;
+ try {
+ storeStream = new URL(store).openStream();
+ if (storeStream != null) {
+ return storeStream;
+ }
+ } catch(MalformedURLException e) {
+ }
+
+ storeStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(store);
+
+ if (storeStream != null) {
+ return storeStream;
+ } else {
+ throw new IOException("Could not load file: " + store);
+ }
+ }
+
+ private static TSocket createClient(SSLSocketFactory factory, String host, int port, int timeout) throws TTransportException {
+ try {
+ SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
+ socket.setSoTimeout(timeout);
+ return new TSocket(socket);
+ } catch (Exception e) {
+ throw new TTransportException("Could not connect to " + host + " on port " + port, e);
+ }
+ }
+
+
+ /**
+ * A Class to hold all the SSL parameters
+ */
+ public static class TSSLTransportParameters {
+ protected String protocol = "TLS";
+ protected String keyStore;
+ protected InputStream keyStoreStream;
+ protected String keyPass;
+ protected String keyManagerType = KeyManagerFactory.getDefaultAlgorithm();
+ protected String keyStoreType = "JKS";
+ protected String trustStore;
+ protected InputStream trustStoreStream;
+ protected String trustPass;
+ protected String trustManagerType = TrustManagerFactory.getDefaultAlgorithm();
+ protected String trustStoreType = "JKS";
+ protected String[] cipherSuites;
+ protected boolean clientAuth = false;
+ protected boolean isKeyStoreSet = false;
+ protected boolean isTrustStoreSet = false;
+
+ public TSSLTransportParameters() {}
+
+ /**
+ * Create parameters specifying the protocol and cipher suites
+ *
+ * @param protocol The specific protocol (TLS/SSL) can be specified with versions
+ * @param cipherSuites
+ */
+ public TSSLTransportParameters(String protocol, String[] cipherSuites) {
+ this(protocol, cipherSuites, false);
+ }
+
+ /**
+ * Create parameters specifying the protocol, cipher suites and if client authentication
+ * is required
+ *
+ * @param protocol The specific protocol (TLS/SSL) can be specified with versions
+ * @param cipherSuites
+ * @param clientAuth
+ */
+ public TSSLTransportParameters(String protocol, String[] cipherSuites, boolean clientAuth) {
+ if (protocol != null) {
+ this.protocol = protocol;
+ }
+ this.cipherSuites = cipherSuites != null ? Arrays.copyOf(cipherSuites, cipherSuites.length) : null;
+ this.clientAuth = clientAuth;
+ }
+
+ /**
+ * Set the keystore, password, certificate type and the store type
+ *
+ * @param keyStore Location of the Keystore on disk
+ * @param keyPass Keystore password
+ * @param keyManagerType The default is X509
+ * @param keyStoreType The default is JKS
+ */
+ public void setKeyStore(String keyStore, String keyPass, String keyManagerType, String keyStoreType) {
+ this.keyStore = keyStore;
+ this.keyPass = keyPass;
+ if (keyManagerType != null) {
+ this.keyManagerType = keyManagerType;
+ }
+ if (keyStoreType != null) {
+ this.keyStoreType = keyStoreType;
+ }
+ isKeyStoreSet = true;
+ }
+
+ /**
+ * Set the keystore, password, certificate type and the store type
+ *
+ * @param keyStoreStream Keystore content input stream
+ * @param keyPass Keystore password
+ * @param keyManagerType The default is X509
+ * @param keyStoreType The default is JKS
+ */
+ public void setKeyStore(InputStream keyStoreStream, String keyPass, String keyManagerType, String keyStoreType) {
+ this.keyStoreStream = keyStoreStream;
+ setKeyStore("", keyPass, keyManagerType, keyStoreType);
+ }
+
+ /**
+ * Set the keystore and password
+ *
+ * @param keyStore Location of the Keystore on disk
+ * @param keyPass Keystore password
+ */
+ public void setKeyStore(String keyStore, String keyPass) {
+ setKeyStore(keyStore, keyPass, null, null);
+ }
+
+ /**
+ * Set the keystore and password
+ *
+ * @param keyStoreStream Keystore content input stream
+ * @param keyPass Keystore password
+ */
+ public void setKeyStore(InputStream keyStoreStream, String keyPass) {
+ setKeyStore(keyStoreStream, keyPass, null, null);
+ }
+
+ /**
+ * Set the truststore, password, certificate type and the store type
+ *
+ * @param trustStore Location of the Truststore on disk
+ * @param trustPass Truststore password
+ * @param trustManagerType The default is X509
+ * @param trustStoreType The default is JKS
+ */
+ public void setTrustStore(String trustStore, String trustPass, String trustManagerType, String trustStoreType) {
+ this.trustStore = trustStore;
+ this.trustPass = trustPass;
+ if (trustManagerType != null) {
+ this.trustManagerType = trustManagerType;
+ }
+ if (trustStoreType != null) {
+ this.trustStoreType = trustStoreType;
+ }
+ isTrustStoreSet = true;
+ }
+
+ /**
+ * Set the truststore, password, certificate type and the store type
+ *
+ * @param trustStoreStream Truststore content input stream
+ * @param trustPass Truststore password
+ * @param trustManagerType The default is X509
+ * @param trustStoreType The default is JKS
+ */
+ public void setTrustStore(InputStream trustStoreStream, String trustPass, String trustManagerType, String trustStoreType) {
+ this.trustStoreStream = trustStoreStream;
+ setTrustStore("", trustPass, trustManagerType, trustStoreType);
+ }
+
+ /**
+ * Set the truststore and password
+ *
+ * @param trustStore Location of the Truststore on disk
+ * @param trustPass Truststore password
+ */
+ public void setTrustStore(String trustStore, String trustPass) {
+ setTrustStore(trustStore, trustPass, null, null);
+ }
+
+ /**
+ * Set the truststore and password
+ *
+ * @param trustStoreStream Truststore content input stream
+ * @param trustPass Truststore password
+ */
+ public void setTrustStore(InputStream trustStoreStream, String trustPass) {
+ setTrustStore(trustStoreStream, trustPass, null, null);
+ }
+
+ /**
+ * Set if client authentication is required
+ *
+ * @param clientAuth
+ */
+ public void requireClientAuth(boolean clientAuth) {
+ this.clientAuth = clientAuth;
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java
new file mode 100644
index 000000000..4b1ca0a94
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java
@@ -0,0 +1,108 @@
+/*
+ * 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.thrift.transport;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Wraps another Thrift <code>TTransport</code>, but performs SASL client
+ * negotiation on the call to <code>open()</code>. This class will wrap ensuing
+ * communication over it, if a SASL QOP is negotiated with the other party.
+ */
+public class TSaslClientTransport extends TSaslTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TSaslClientTransport.class);
+
+ /**
+ * The name of the mechanism this client supports.
+ */
+ private final String mechanism;
+
+ /**
+ * Uses the given <code>SaslClient</code>.
+ *
+ * @param saslClient
+ * The <code>SaslClient</code> to use for the subsequent SASL
+ * negotiation.
+ * @param transport
+ * Transport underlying this one.
+ */
+ public TSaslClientTransport(SaslClient saslClient, TTransport transport) {
+ super(saslClient, transport);
+ mechanism = saslClient.getMechanismName();
+ }
+
+ /**
+ * Creates a <code>SaslClient</code> using the given SASL-specific parameters.
+ * See the Java documentation for <code>Sasl.createSaslClient</code> for the
+ * details of the parameters.
+ *
+ * @param transport
+ * The underlying Thrift transport.
+ * @throws SaslException
+ */
+ public TSaslClientTransport(String mechanism, String authorizationId, String protocol,
+ String serverName, Map<String, String> props, CallbackHandler cbh, TTransport transport)
+ throws SaslException {
+ super(Sasl.createSaslClient(new String[] { mechanism }, authorizationId, protocol, serverName,
+ props, cbh), transport);
+ this.mechanism = mechanism;
+ }
+
+
+ @Override
+ protected SaslRole getRole() {
+ return SaslRole.CLIENT;
+ }
+
+ /**
+ * Performs the client side of the initial portion of the Thrift SASL
+ * protocol. Generates and sends the initial response to the server, including
+ * which mechanism this client wants to use.
+ */
+ @Override
+ protected void handleSaslStartMessage() throws TTransportException, SaslException {
+ SaslClient saslClient = getSaslClient();
+
+ byte[] initialResponse = new byte[0];
+ if (saslClient.hasInitialResponse())
+ initialResponse = saslClient.evaluateChallenge(initialResponse);
+
+ LOGGER.debug("Sending mechanism name {} and initial response of length {}", mechanism,
+ initialResponse.length);
+
+ byte[] mechanismBytes = mechanism.getBytes(StandardCharsets.UTF_8);
+ sendSaslMessage(NegotiationStatus.START,
+ mechanismBytes);
+ // Send initial response
+ sendSaslMessage(saslClient.isComplete() ? NegotiationStatus.COMPLETE : NegotiationStatus.OK,
+ initialResponse);
+ underlyingTransport.flush();
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java
new file mode 100644
index 000000000..39b81ca43
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java
@@ -0,0 +1,230 @@
+/*
+ * 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.thrift.transport;
+
+import java.lang.ref.WeakReference;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Wraps another Thrift <code>TTransport</code>, but performs SASL server
+ * negotiation on the call to <code>open()</code>. This class will wrap ensuing
+ * communication over it, if a SASL QOP is negotiated with the other party.
+ */
+public class TSaslServerTransport extends TSaslTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TSaslServerTransport.class);
+
+ /**
+ * Mapping from SASL mechanism name -> all the parameters required to
+ * instantiate a SASL server.
+ */
+ private Map<String, TSaslServerDefinition> serverDefinitionMap = new HashMap<String, TSaslServerDefinition>();
+
+ /**
+ * Contains all the parameters used to define a SASL server implementation.
+ */
+ private static class TSaslServerDefinition {
+ public String mechanism;
+ public String protocol;
+ public String serverName;
+ public Map<String, String> props;
+ public CallbackHandler cbh;
+
+ public TSaslServerDefinition(String mechanism, String protocol, String serverName,
+ Map<String, String> props, CallbackHandler cbh) {
+ this.mechanism = mechanism;
+ this.protocol = protocol;
+ this.serverName = serverName;
+ this.props = props;
+ this.cbh = cbh;
+ }
+ }
+
+ /**
+ * Uses the given underlying transport. Assumes that addServerDefinition is
+ * called later.
+ *
+ * @param transport
+ * Transport underlying this one.
+ */
+ public TSaslServerTransport(TTransport transport) {
+ super(transport);
+ }
+
+ /**
+ * Creates a <code>SaslServer</code> using the given SASL-specific parameters.
+ * See the Java documentation for <code>Sasl.createSaslServer</code> for the
+ * details of the parameters.
+ *
+ * @param transport
+ * The underlying Thrift transport.
+ */
+ public TSaslServerTransport(String mechanism, String protocol, String serverName,
+ Map<String, String> props, CallbackHandler cbh, TTransport transport) {
+ super(transport);
+ addServerDefinition(mechanism, protocol, serverName, props, cbh);
+ }
+
+ private TSaslServerTransport(Map<String, TSaslServerDefinition> serverDefinitionMap, TTransport transport) {
+ super(transport);
+ this.serverDefinitionMap.putAll(serverDefinitionMap);
+ }
+
+ /**
+ * Add a supported server definition to this transport. See the Java
+ * documentation for <code>Sasl.createSaslServer</code> for the details of the
+ * parameters.
+ */
+ public void addServerDefinition(String mechanism, String protocol, String serverName,
+ Map<String, String> props, CallbackHandler cbh) {
+ serverDefinitionMap.put(mechanism, new TSaslServerDefinition(mechanism, protocol, serverName,
+ props, cbh));
+ }
+
+ @Override
+ protected SaslRole getRole() {
+ return SaslRole.SERVER;
+ }
+
+ /**
+ * Performs the server side of the initial portion of the Thrift SASL protocol.
+ * Receives the initial response from the client, creates a SASL server using
+ * the mechanism requested by the client (if this server supports it), and
+ * sends the first challenge back to the client.
+ */
+ @Override
+ protected void handleSaslStartMessage() throws TTransportException, SaslException {
+ SaslResponse message = receiveSaslMessage();
+
+ LOGGER.debug("Received start message with status {}", message.status);
+ if (message.status != NegotiationStatus.START) {
+ throw sendAndThrowMessage(NegotiationStatus.ERROR, "Expecting START status, received " + message.status);
+ }
+
+ // Get the mechanism name.
+ String mechanismName = new String(message.payload, StandardCharsets.UTF_8);
+ TSaslServerDefinition serverDefinition = serverDefinitionMap.get(mechanismName);
+ LOGGER.debug("Received mechanism name '{}'", mechanismName);
+
+ if (serverDefinition == null) {
+ throw sendAndThrowMessage(NegotiationStatus.BAD, "Unsupported mechanism type " + mechanismName);
+ }
+ SaslServer saslServer = Sasl.createSaslServer(serverDefinition.mechanism,
+ serverDefinition.protocol, serverDefinition.serverName, serverDefinition.props,
+ serverDefinition.cbh);
+ setSaslServer(saslServer);
+ }
+
+ /**
+ * <code>TTransportFactory</code> to create
+ * <code>TSaslServerTransports</code>. Ensures that a given
+ * underlying <code>TTransport</code> instance receives the same
+ * <code>TSaslServerTransport</code>. This is kind of an awful hack to work
+ * around the fact that Thrift is designed assuming that
+ * <code>TTransport</code> instances are stateless, and thus the existing
+ * <code>TServers</code> use different <code>TTransport</code> instances for
+ * input and output.
+ */
+ public static class Factory extends TTransportFactory {
+
+ /**
+ * This is the implementation of the awful hack described above.
+ * <code>WeakHashMap</code> is used to ensure that we don't leak memory.
+ */
+ private static Map<TTransport, WeakReference<TSaslServerTransport>> transportMap =
+ Collections.synchronizedMap(new WeakHashMap<TTransport, WeakReference<TSaslServerTransport>>());
+
+ /**
+ * Mapping from SASL mechanism name -> all the parameters required to
+ * instantiate a SASL server.
+ */
+ private Map<String, TSaslServerDefinition> serverDefinitionMap = new HashMap<String, TSaslServerDefinition>();
+
+ /**
+ * Create a new Factory. Assumes that <code>addServerDefinition</code> will
+ * be called later.
+ */
+ public Factory() {
+ super();
+ }
+
+ /**
+ * Create a new <code>Factory</code>, initially with the single server
+ * definition given. You may still call <code>addServerDefinition</code>
+ * later. See the Java documentation for <code>Sasl.createSaslServer</code>
+ * for the details of the parameters.
+ */
+ public Factory(String mechanism, String protocol, String serverName,
+ Map<String, String> props, CallbackHandler cbh) {
+ super();
+ addServerDefinition(mechanism, protocol, serverName, props, cbh);
+ }
+
+ /**
+ * Add a supported server definition to the transports created by this
+ * factory. See the Java documentation for
+ * <code>Sasl.createSaslServer</code> for the details of the parameters.
+ */
+ public void addServerDefinition(String mechanism, String protocol, String serverName,
+ Map<String, String> props, CallbackHandler cbh) {
+ serverDefinitionMap.put(mechanism, new TSaslServerDefinition(mechanism, protocol, serverName,
+ props, cbh));
+ }
+
+ /**
+ * Get a new <code>TSaslServerTransport</code> instance, or reuse the
+ * existing one if a <code>TSaslServerTransport</code> has already been
+ * created before using the given <code>TTransport</code> as an underlying
+ * transport. This ensures that a given underlying transport instance
+ * receives the same <code>TSaslServerTransport</code>.
+ */
+ @Override
+ public TTransport getTransport(TTransport base) {
+ WeakReference<TSaslServerTransport> ret = transportMap.get(base);
+ if (ret == null || ret.get() == null) {
+ LOGGER.debug("transport map does not contain key", base);
+ ret = new WeakReference<TSaslServerTransport>(new TSaslServerTransport(serverDefinitionMap, base));
+ try {
+ ret.get().open();
+ } catch (TTransportException e) {
+ LOGGER.debug("failed to open server transport", e);
+ throw new RuntimeException(e);
+ }
+ transportMap.put(base, ret); // No need for putIfAbsent().
+ // Concurrent calls to getTransport() will pass in different TTransports.
+ } else {
+ LOGGER.debug("transport map does contain key {}", base);
+ }
+ return ret.get();
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslTransport.java
new file mode 100644
index 000000000..4a453b68f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSaslTransport.java
@@ -0,0 +1,575 @@
+/*
+ * 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.thrift.transport;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.thrift.EncodingUtils;
+import org.apache.thrift.TByteArrayOutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A superclass for SASL client/server thrift transports. A subclass need only
+ * implement the <code>open</code> method.
+ */
+abstract class TSaslTransport extends TTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TSaslTransport.class);
+
+ protected static final int DEFAULT_MAX_LENGTH = 0x7FFFFFFF;
+
+ protected static final int MECHANISM_NAME_BYTES = 1;
+ protected static final int STATUS_BYTES = 1;
+ protected static final int PAYLOAD_LENGTH_BYTES = 4;
+
+ protected static enum SaslRole {
+ SERVER, CLIENT;
+ }
+
+ /**
+ * Status bytes used during the initial Thrift SASL handshake.
+ */
+ protected static enum NegotiationStatus {
+ START((byte)0x01),
+ OK((byte)0x02),
+ BAD((byte)0x03),
+ ERROR((byte)0x04),
+ COMPLETE((byte)0x05);
+
+ private final byte value;
+
+ private static final Map<Byte, NegotiationStatus> reverseMap =
+ new HashMap<Byte, NegotiationStatus>();
+ static {
+ for (NegotiationStatus s : NegotiationStatus.class.getEnumConstants()) {
+ reverseMap.put(s.getValue(), s);
+ }
+ }
+
+ private NegotiationStatus(byte val) {
+ this.value = val;
+ }
+
+ public byte getValue() {
+ return value;
+ }
+
+ public static NegotiationStatus byValue(byte val) {
+ return reverseMap.get(val);
+ }
+ }
+
+ /**
+ * Transport underlying this one.
+ */
+ protected TTransport underlyingTransport;
+
+ /**
+ * Either a SASL client or a SASL server.
+ */
+ private SaslParticipant sasl;
+
+ /**
+ * Whether or not we should wrap/unwrap reads/writes. Determined by whether or
+ * not a QOP is negotiated during the SASL handshake.
+ */
+ private boolean shouldWrap = false;
+
+ /**
+ * Buffer for input.
+ */
+ private TMemoryInputTransport readBuffer = new TMemoryInputTransport();
+
+ /**
+ * Buffer for output.
+ */
+ private final TByteArrayOutputStream writeBuffer = new TByteArrayOutputStream(1024);
+
+ /**
+ * Create a TSaslTransport. It's assumed that setSaslServer will be called
+ * later to initialize the SASL endpoint underlying this transport.
+ *
+ * @param underlyingTransport
+ * The thrift transport which this transport is wrapping.
+ */
+ protected TSaslTransport(TTransport underlyingTransport) {
+ this.underlyingTransport = underlyingTransport;
+ }
+
+ /**
+ * Create a TSaslTransport which acts as a client.
+ *
+ * @param saslClient
+ * The <code>SaslClient</code> which this transport will use for SASL
+ * negotiation.
+ * @param underlyingTransport
+ * The thrift transport which this transport is wrapping.
+ */
+ protected TSaslTransport(SaslClient saslClient, TTransport underlyingTransport) {
+ sasl = new SaslParticipant(saslClient);
+ this.underlyingTransport = underlyingTransport;
+ }
+
+ protected void setSaslServer(SaslServer saslServer) {
+ sasl = new SaslParticipant(saslServer);
+ }
+
+ // Used to read the status byte and payload length.
+ private final byte[] messageHeader = new byte[STATUS_BYTES + PAYLOAD_LENGTH_BYTES];
+
+ /**
+ * Send a complete Thrift SASL message.
+ *
+ * @param status
+ * The status to send.
+ * @param payload
+ * The data to send as the payload of this message.
+ * @throws TTransportException
+ */
+ protected void sendSaslMessage(NegotiationStatus status, byte[] payload) throws TTransportException {
+ if (payload == null)
+ payload = new byte[0];
+
+ messageHeader[0] = status.getValue();
+ EncodingUtils.encodeBigEndian(payload.length, messageHeader, STATUS_BYTES);
+
+ LOGGER.debug("{}: Writing message with status {} and payload length {}",
+ getRole(), status, payload.length);
+
+ underlyingTransport.write(messageHeader);
+ underlyingTransport.write(payload);
+ underlyingTransport.flush();
+ }
+
+ /**
+ * Read a complete Thrift SASL message.
+ *
+ * @return The SASL status and payload from this message.
+ * @throws TTransportException
+ * Thrown if there is a failure reading from the underlying
+ * transport, or if a status code of BAD or ERROR is encountered.
+ */
+ protected SaslResponse receiveSaslMessage() throws TTransportException {
+ underlyingTransport.readAll(messageHeader, 0, messageHeader.length);
+
+ byte statusByte = messageHeader[0];
+
+ NegotiationStatus status = NegotiationStatus.byValue(statusByte);
+ if (status == null) {
+ throw sendAndThrowMessage(NegotiationStatus.ERROR, "Invalid status " + statusByte);
+ }
+
+ int payloadBytes = EncodingUtils.decodeBigEndian(messageHeader, STATUS_BYTES);
+ if (payloadBytes < 0 || payloadBytes > 104857600 /* 100 MB */) {
+ throw sendAndThrowMessage(
+ NegotiationStatus.ERROR, "Invalid payload header length: " + payloadBytes);
+ }
+
+ byte[] payload = new byte[payloadBytes];
+ underlyingTransport.readAll(payload, 0, payload.length);
+
+ if (status == NegotiationStatus.BAD || status == NegotiationStatus.ERROR) {
+ String remoteMessage = new String(payload, StandardCharsets.UTF_8);
+ throw new TTransportException("Peer indicated failure: " + remoteMessage);
+ }
+ LOGGER.debug("{}: Received message with status {} and payload length {}",
+ getRole(), status, payload.length);
+ return new SaslResponse(status, payload);
+ }
+
+ /**
+ * Send a Thrift SASL message with the given status (usually BAD or ERROR) and
+ * string message, and then throw a TTransportException with the given
+ * message.
+ *
+ * @param status
+ * The Thrift SASL status code to send. Usually BAD or ERROR.
+ * @param message
+ * The optional message to send to the other side.
+ * @throws TTransportException
+ * Always thrown with the message provided.
+ * @return always throws TTransportException but declares return type to allow
+ * throw sendAndThrowMessage(...) to inform compiler control flow
+ */
+ protected TTransportException sendAndThrowMessage(NegotiationStatus status, String message) throws TTransportException {
+ try {
+ sendSaslMessage(status, message.getBytes(StandardCharsets.UTF_8));
+ } catch (Exception e) {
+ LOGGER.warn("Could not send failure response", e);
+ message += "\nAlso, could not send response: " + e.toString();
+ }
+ throw new TTransportException(message);
+ }
+
+ /**
+ * Implemented by subclasses to start the Thrift SASL handshake process. When
+ * this method completes, the <code>SaslParticipant</code> in this class is
+ * assumed to be initialized.
+ *
+ * @throws TTransportException
+ * @throws SaslException
+ */
+ abstract protected void handleSaslStartMessage() throws TTransportException, SaslException;
+
+ protected abstract SaslRole getRole();
+
+ /**
+ * Opens the underlying transport if it's not already open and then performs
+ * SASL negotiation. If a QOP is negotiated during this SASL handshake, it used
+ * for all communication on this transport after this call is complete.
+ */
+ @Override
+ public void open() throws TTransportException {
+ /*
+ * readSaslHeader is used to tag whether the SASL header has been read properly.
+ * If there is a problem in reading the header, there might not be any
+ * data in the stream, possibly a TCP health check from load balancer.
+ */
+ boolean readSaslHeader = false;
+
+ LOGGER.debug("opening transport {}", this);
+ if (sasl != null && sasl.isComplete())
+ throw new TTransportException("SASL transport already open");
+
+ if (!underlyingTransport.isOpen())
+ underlyingTransport.open();
+
+ try {
+ // Negotiate a SASL mechanism. The client also sends its
+ // initial response, or an empty one.
+ handleSaslStartMessage();
+ readSaslHeader = true;
+ LOGGER.debug("{}: Start message handled", getRole());
+
+ SaslResponse message = null;
+ while (!sasl.isComplete()) {
+ message = receiveSaslMessage();
+ if (message.status != NegotiationStatus.COMPLETE &&
+ message.status != NegotiationStatus.OK) {
+ throw new TTransportException("Expected COMPLETE or OK, got " + message.status);
+ }
+
+ byte[] challenge = sasl.evaluateChallengeOrResponse(message.payload);
+
+ // If we are the client, and the server indicates COMPLETE, we don't need to
+ // send back any further response.
+ if (message.status == NegotiationStatus.COMPLETE &&
+ getRole() == SaslRole.CLIENT) {
+ LOGGER.debug("{}: All done!", getRole());
+ continue;
+ }
+
+ sendSaslMessage(sasl.isComplete() ? NegotiationStatus.COMPLETE : NegotiationStatus.OK,
+ challenge);
+ }
+ LOGGER.debug("{}: Main negotiation loop complete", getRole());
+
+ // If we're the client, and we're complete, but the server isn't
+ // complete yet, we need to wait for its response. This will occur
+ // with ANONYMOUS auth, for example, where we send an initial response
+ // and are immediately complete.
+ if (getRole() == SaslRole.CLIENT &&
+ (message == null || message.status == NegotiationStatus.OK)) {
+ LOGGER.debug("{}: SASL Client receiving last message", getRole());
+ message = receiveSaslMessage();
+ if (message.status != NegotiationStatus.COMPLETE) {
+ throw new TTransportException(
+ "Expected SASL COMPLETE, but got " + message.status);
+ }
+ }
+ } catch (SaslException e) {
+ try {
+ LOGGER.error("SASL negotiation failure", e);
+ throw sendAndThrowMessage(NegotiationStatus.BAD, e.getMessage());
+ } finally {
+ underlyingTransport.close();
+ }
+ } catch (TTransportException e) {
+ // If there is no-data or no-sasl header in the stream,
+ // log the failure, and clean up the underlying transport.
+ if (!readSaslHeader && e.getType() == TTransportException.END_OF_FILE) {
+ underlyingTransport.close();
+ LOGGER.debug("No data or no sasl data in the stream during negotiation");
+ }
+ throw e;
+ }
+
+ String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
+ if (qop != null && !qop.equalsIgnoreCase("auth"))
+ shouldWrap = true;
+ }
+
+ /**
+ * Get the underlying <code>SaslClient</code>.
+ *
+ * @return The <code>SaslClient</code>, or <code>null</code> if this transport
+ * is backed by a <code>SaslServer</code>.
+ */
+ public SaslClient getSaslClient() {
+ return sasl.saslClient;
+ }
+
+ /**
+ * Get the underlying transport that Sasl is using.
+ * @return The <code>TTransport</code> transport
+ */
+ public TTransport getUnderlyingTransport() {
+ return underlyingTransport;
+ }
+
+ /**
+ * Get the underlying <code>SaslServer</code>.
+ *
+ * @return The <code>SaslServer</code>, or <code>null</code> if this transport
+ * is backed by a <code>SaslClient</code>.
+ */
+ public SaslServer getSaslServer() {
+ return sasl.saslServer;
+ }
+
+ /**
+ * Read a 4-byte word from the underlying transport and interpret it as an
+ * integer.
+ *
+ * @return The length prefix of the next SASL message to read.
+ * @throws TTransportException
+ * Thrown if reading from the underlying transport fails.
+ */
+ protected int readLength() throws TTransportException {
+ byte[] lenBuf = new byte[4];
+ underlyingTransport.readAll(lenBuf, 0, lenBuf.length);
+ return EncodingUtils.decodeBigEndian(lenBuf);
+ }
+
+ /**
+ * Write the given integer as 4 bytes to the underlying transport.
+ *
+ * @param length
+ * The length prefix of the next SASL message to write.
+ * @throws TTransportException
+ * Thrown if writing to the underlying transport fails.
+ */
+ protected void writeLength(int length) throws TTransportException {
+ byte[] lenBuf = new byte[4];
+ TFramedTransport.encodeFrameSize(length, lenBuf);
+ underlyingTransport.write(lenBuf);
+ }
+
+ // Below is the SASL implementation of the TTransport interface.
+
+ /**
+ * Closes the underlying transport and disposes of the SASL implementation
+ * underlying this transport.
+ */
+ @Override
+ public void close() {
+ underlyingTransport.close();
+ try {
+ sasl.dispose();
+ } catch (SaslException e) {
+ // Not much we can do here.
+ }
+ }
+
+ /**
+ * True if the underlying transport is open and the SASL handshake is
+ * complete.
+ */
+ @Override
+ public boolean isOpen() {
+ return underlyingTransport.isOpen() && sasl != null && sasl.isComplete();
+ }
+
+ /**
+ * Read from the underlying transport. Unwraps the contents if a QOP was
+ * negotiated during the SASL handshake.
+ */
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ if (!isOpen())
+ throw new TTransportException("SASL authentication not complete");
+
+ int got = readBuffer.read(buf, off, len);
+ if (got > 0) {
+ return got;
+ }
+
+ // Read another frame of data
+ try {
+ readFrame();
+ } catch (SaslException e) {
+ throw new TTransportException(e);
+ } catch (TTransportException transportException) {
+ // If there is no-data or no-sasl header in the stream, log the failure, and rethrow.
+ if (transportException.getType() == TTransportException.END_OF_FILE) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("No data or no sasl data in the stream during negotiation");
+ }
+ }
+ throw transportException;
+ }
+
+ return readBuffer.read(buf, off, len);
+ }
+
+ /**
+ * Read a single frame of data from the underlying transport, unwrapping if
+ * necessary.
+ *
+ * @throws TTransportException
+ * Thrown if there's an error reading from the underlying transport.
+ * @throws SaslException
+ * Thrown if there's an error unwrapping the data.
+ */
+ private void readFrame() throws TTransportException, SaslException {
+ int dataLength = readLength();
+
+ if (dataLength < 0)
+ throw new TTransportException("Read a negative frame size (" + dataLength + ")!");
+
+ byte[] buff = new byte[dataLength];
+ LOGGER.debug("{}: reading data length: {}", getRole(), dataLength);
+ underlyingTransport.readAll(buff, 0, dataLength);
+ if (shouldWrap) {
+ buff = sasl.unwrap(buff, 0, buff.length);
+ LOGGER.debug("data length after unwrap: {}", buff.length);
+ }
+ readBuffer.reset(buff);
+ }
+
+ /**
+ * Write to the underlying transport.
+ */
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ if (!isOpen())
+ throw new TTransportException("SASL authentication not complete");
+
+ writeBuffer.write(buf, off, len);
+ }
+
+ /**
+ * Flushes to the underlying transport. Wraps the contents if a QOP was
+ * negotiated during the SASL handshake.
+ */
+ @Override
+ public void flush() throws TTransportException {
+ byte[] buf = writeBuffer.get();
+ int dataLength = writeBuffer.len();
+ writeBuffer.reset();
+
+ if (shouldWrap) {
+ LOGGER.debug("data length before wrap: {}", dataLength);
+ try {
+ buf = sasl.wrap(buf, 0, dataLength);
+ } catch (SaslException e) {
+ throw new TTransportException(e);
+ }
+ dataLength = buf.length;
+ }
+ LOGGER.debug("writing data length: {}", dataLength);
+ writeLength(dataLength);
+ underlyingTransport.write(buf, 0, dataLength);
+ underlyingTransport.flush();
+ }
+
+ /**
+ * Used exclusively by readSaslMessage to return both a status and data.
+ */
+ protected static class SaslResponse {
+ public NegotiationStatus status;
+ public byte[] payload;
+
+ public SaslResponse(NegotiationStatus status, byte[] payload) {
+ this.status = status;
+ this.payload = payload;
+ }
+ }
+
+ /**
+ * Used to abstract over the <code>SaslServer</code> and
+ * <code>SaslClient</code> classes, which share a lot of their interface, but
+ * unfortunately don't share a common superclass.
+ */
+ private static class SaslParticipant {
+ // One of these will always be null.
+ public SaslServer saslServer;
+ public SaslClient saslClient;
+
+ public SaslParticipant(SaslServer saslServer) {
+ this.saslServer = saslServer;
+ }
+
+ public SaslParticipant(SaslClient saslClient) {
+ this.saslClient = saslClient;
+ }
+
+ public byte[] evaluateChallengeOrResponse(byte[] challengeOrResponse) throws SaslException {
+ if (saslClient != null) {
+ return saslClient.evaluateChallenge(challengeOrResponse);
+ } else {
+ return saslServer.evaluateResponse(challengeOrResponse);
+ }
+ }
+
+ public boolean isComplete() {
+ if (saslClient != null)
+ return saslClient.isComplete();
+ else
+ return saslServer.isComplete();
+ }
+
+ public void dispose() throws SaslException {
+ if (saslClient != null)
+ saslClient.dispose();
+ else
+ saslServer.dispose();
+ }
+
+ public byte[] unwrap(byte[] buf, int off, int len) throws SaslException {
+ if (saslClient != null)
+ return saslClient.unwrap(buf, off, len);
+ else
+ return saslServer.unwrap(buf, off, len);
+ }
+
+ public byte[] wrap(byte[] buf, int off, int len) throws SaslException {
+ if (saslClient != null)
+ return saslClient.wrap(buf, off, len);
+ else
+ return saslServer.wrap(buf, off, len);
+ }
+
+ public Object getNegotiatedProperty(String propName) {
+ if (saslClient != null)
+ return saslClient.getNegotiatedProperty(propName);
+ else
+ return saslServer.getNegotiatedProperty(propName);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSeekableFile.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSeekableFile.java
new file mode 100644
index 000000000..e02d36f6c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSeekableFile.java
@@ -0,0 +1,33 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+public interface TSeekableFile {
+
+ public InputStream getInputStream() throws IOException;
+ public OutputStream getOutputStream() throws IOException;
+ public void close() throws IOException;
+ public long length() throws IOException;
+ public void seek(long pos) throws IOException;
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerSocket.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerSocket.java
new file mode 100644
index 000000000..79f7b7f49
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerSocket.java
@@ -0,0 +1,158 @@
+/*
+ * 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.thrift.transport;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+/**
+ * Wrapper around ServerSocket for Thrift.
+ *
+ */
+public class TServerSocket extends TServerTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TServerSocket.class.getName());
+
+ /**
+ * Underlying ServerSocket object
+ */
+ private ServerSocket serverSocket_ = null;
+
+ /**
+ * Timeout for client sockets from accept
+ */
+ private int clientTimeout_ = 0;
+
+ public static class ServerSocketTransportArgs extends AbstractServerTransportArgs<ServerSocketTransportArgs> {
+ ServerSocket serverSocket;
+
+ public ServerSocketTransportArgs serverSocket(ServerSocket serverSocket) {
+ this.serverSocket = serverSocket;
+ return this;
+ }
+ }
+
+ /**
+ * Creates a server socket from underlying socket object
+ */
+ public TServerSocket(ServerSocket serverSocket) throws TTransportException {
+ this(serverSocket, 0);
+ }
+
+ /**
+ * Creates a server socket from underlying socket object
+ */
+ public TServerSocket(ServerSocket serverSocket, int clientTimeout) throws TTransportException {
+ this(new ServerSocketTransportArgs().serverSocket(serverSocket).clientTimeout(clientTimeout));
+ }
+
+ /**
+ * Creates just a port listening server socket
+ */
+ public TServerSocket(int port) throws TTransportException {
+ this(port, 0);
+ }
+
+ /**
+ * Creates just a port listening server socket
+ */
+ public TServerSocket(int port, int clientTimeout) throws TTransportException {
+ this(new InetSocketAddress(port), clientTimeout);
+ }
+
+ public TServerSocket(InetSocketAddress bindAddr) throws TTransportException {
+ this(bindAddr, 0);
+ }
+
+ public TServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
+ this(new ServerSocketTransportArgs().bindAddr(bindAddr).clientTimeout(clientTimeout));
+ }
+
+ public TServerSocket(ServerSocketTransportArgs args) throws TTransportException {
+ clientTimeout_ = args.clientTimeout;
+ if (args.serverSocket != null) {
+ this.serverSocket_ = args.serverSocket;
+ return;
+ }
+ try {
+ // Make server socket
+ serverSocket_ = new ServerSocket();
+ // Prevent 2MSL delay problem on server restarts
+ serverSocket_.setReuseAddress(true);
+ // Bind to listening port
+ serverSocket_.bind(args.bindAddr, args.backlog);
+ } catch (IOException ioe) {
+ close();
+ throw new TTransportException("Could not create ServerSocket on address " + args.bindAddr.toString() + ".", ioe);
+ }
+ }
+
+ public void listen() throws TTransportException {
+ // Make sure to block on accept
+ if (serverSocket_ != null) {
+ try {
+ serverSocket_.setSoTimeout(0);
+ } catch (SocketException sx) {
+ LOGGER.error("Could not set socket timeout.", sx);
+ }
+ }
+ }
+
+ protected TSocket acceptImpl() throws TTransportException {
+ if (serverSocket_ == null) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "No underlying server socket.");
+ }
+ try {
+ Socket result = serverSocket_.accept();
+ TSocket result2 = new TSocket(result);
+ result2.setTimeout(clientTimeout_);
+ return result2;
+ } catch (IOException iox) {
+ throw new TTransportException(iox);
+ }
+ }
+
+ public void close() {
+ if (serverSocket_ != null) {
+ try {
+ serverSocket_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("Could not close server socket.", iox);
+ }
+ serverSocket_ = null;
+ }
+ }
+
+ public void interrupt() {
+ // The thread-safeness of this is dubious, but Java documentation suggests
+ // that it is safe to do this from a different thread context
+ close();
+ }
+
+ public ServerSocket getServerSocket() {
+ return serverSocket_;
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerTransport.java
new file mode 100644
index 000000000..424e4faaa
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TServerTransport.java
@@ -0,0 +1,80 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.Closeable;
+import java.net.InetSocketAddress;
+
+/**
+ * Server transport. Object which provides client transports.
+ *
+ */
+public abstract class TServerTransport implements Closeable {
+
+ public static abstract class AbstractServerTransportArgs<T extends AbstractServerTransportArgs<T>> {
+ int backlog = 0; // A value of 0 means the default value will be used (currently set at 50)
+ int clientTimeout = 0;
+ InetSocketAddress bindAddr;
+
+ public T backlog(int backlog) {
+ this.backlog = backlog;
+ return (T) this;
+ }
+
+ public T clientTimeout(int clientTimeout) {
+ this.clientTimeout = clientTimeout;
+ return (T) this;
+ }
+
+ public T port(int port) {
+ this.bindAddr = new InetSocketAddress(port);
+ return (T) this;
+ }
+
+ public T bindAddr(InetSocketAddress bindAddr) {
+ this.bindAddr = bindAddr;
+ return (T) this;
+ }
+ }
+
+ public abstract void listen() throws TTransportException;
+
+ public final TTransport accept() throws TTransportException {
+ TTransport transport = acceptImpl();
+ if (transport == null) {
+ throw new TTransportException("accept() may not return NULL");
+ }
+ return transport;
+ }
+
+ public abstract void close();
+
+ protected abstract TTransport acceptImpl() throws TTransportException;
+
+ /**
+ * Optional method implementation. This signals to the server transport
+ * that it should break out of any accept() or listen() that it is currently
+ * blocked on. This method, if implemented, MUST be thread safe, as it may
+ * be called from a different thread context than the other TServerTransport
+ * methods.
+ */
+ public void interrupt() {}
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java
new file mode 100644
index 000000000..42102d9e8
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java
@@ -0,0 +1,216 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+
+/**
+ * Basic file support for the TTransport interface
+ */
+public final class TSimpleFileTransport extends TTransport {
+
+ private RandomAccessFile file = null;
+ private boolean readable;
+ private boolean writable;
+ private String path_;
+
+
+ /**
+ * Create a transport backed by a simple file
+ *
+ * @param path the path to the file to open/create
+ * @param read true to support read operations
+ * @param write true to support write operations
+ * @param openFile true to open the file on construction
+ * @throws TTransportException if file open fails
+ */
+ public TSimpleFileTransport(String path, boolean read,
+ boolean write, boolean openFile)
+ throws TTransportException {
+ if (path.length() <= 0) {
+ throw new TTransportException("No path specified");
+ }
+ if (!read && !write) {
+ throw new TTransportException("Neither READ nor WRITE specified");
+ }
+ readable = read;
+ writable = write;
+ path_ = path;
+ if (openFile) {
+ open();
+ }
+ }
+
+ /**
+ * Create a transport backed by a simple file
+ * Implicitly opens file to conform to C++ behavior.
+ *
+ * @param path the path to the file to open/create
+ * @param read true to support read operations
+ * @param write true to support write operations
+ * @throws TTransportException if file open fails
+ */
+ public TSimpleFileTransport(String path, boolean read, boolean write)
+ throws TTransportException {
+ this(path, read, write, true);
+ }
+
+ /**
+ * Create a transport backed by a simple read only disk file (implicitly opens
+ * file)
+ *
+ * @param path the path to the file to open/create
+ * @throws TTransportException if file open fails
+ */
+ public TSimpleFileTransport(String path) throws TTransportException {
+ this(path, true, false, true);
+ }
+
+ /**
+ * Test file status
+ *
+ * @return true if open, otherwise false
+ */
+ @Override
+ public boolean isOpen() {
+ return (file != null);
+ }
+
+ /**
+ * Open file if not previously opened.
+ *
+ * @throws TTransportException if open fails
+ */
+ @Override
+ public void open() throws TTransportException {
+ if (file == null){
+ try {
+ String access = "r"; //RandomAccessFile objects must be readable
+ if (writable) {
+ access += "w";
+ }
+ file = new RandomAccessFile(path_, access);
+ } catch (IOException ioe) {
+ file = null;
+ throw new TTransportException(ioe.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Close file, subsequent read/write activity will throw exceptions
+ */
+ @Override
+ public void close() {
+ if (file != null) {
+ try {
+ file.close();
+ } catch (Exception e) {
+ //Nothing to do
+ }
+ file = null;
+ }
+ }
+
+ /**
+ * Read up to len many bytes into buf at offset
+ *
+ * @param buf houses bytes read
+ * @param off offset into buff to begin writing to
+ * @param len maximum number of bytes to read
+ * @return number of bytes actually read
+ * @throws TTransportException on read failure
+ */
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ if (!readable) {
+ throw new TTransportException("Read operation on write only file");
+ }
+ int iBytesRead = 0;
+ try {
+ iBytesRead = file.read(buf, off, len);
+ } catch (IOException ioe) {
+ file = null;
+ throw new TTransportException(ioe.getMessage());
+ }
+ return iBytesRead;
+ }
+
+ /**
+ * Write len many bytes from buff starting at offset
+ *
+ * @param buf buffer containing bytes to write
+ * @param off offset into buffer to begin writing from
+ * @param len number of bytes to write
+ * @throws TTransportException on write failure
+ */
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ try {
+ file.write(buf, off, len);
+ } catch (IOException ioe) {
+ file = null;
+ throw new TTransportException(ioe.getMessage());
+ }
+ }
+
+ /**
+ * Move file pointer to specified offset, new read/write calls will act here
+ *
+ * @param offset bytes from beginning of file to move pointer to
+ * @throws TTransportException is seek fails
+ */
+ public void seek(long offset) throws TTransportException {
+ try {
+ file.seek(offset);
+ } catch (IOException ex) {
+ throw new TTransportException(ex.getMessage());
+ }
+ }
+
+ /**
+ * Return the length of the file in bytes
+ *
+ * @return length of the file in bytes
+ * @throws TTransportException if file access fails
+ */
+ public long length() throws TTransportException {
+ try {
+ return file.length();
+ } catch (IOException ex) {
+ throw new TTransportException(ex.getMessage());
+ }
+ }
+
+ /**
+ * Return current file pointer position in bytes from beginning of file
+ *
+ * @return file pointer position
+ * @throws TTransportException if file access fails
+ */
+ public long getFilePointer() throws TTransportException {
+ try {
+ return file.getFilePointer();
+ } catch (IOException ex) {
+ throw new TTransportException(ex.getMessage());
+ }
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSocket.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSocket.java
new file mode 100644
index 000000000..b20b32b78
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TSocket.java
@@ -0,0 +1,248 @@
+/*
+ * 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.thrift.transport;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+
+/**
+ * Socket implementation of the TTransport interface. To be commented soon!
+ *
+ */
+public class TSocket extends TIOStreamTransport {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TSocket.class.getName());
+
+ /**
+ * Wrapped Socket object
+ */
+ private Socket socket_;
+
+ /**
+ * Remote host
+ */
+ private String host_;
+
+ /**
+ * Remote port
+ */
+ private int port_;
+
+ /**
+ * Socket timeout - read timeout on the socket
+ */
+ private int socketTimeout_;
+
+ /**
+ * Connection timeout
+ */
+ private int connectTimeout_;
+
+ /**
+ * Constructor that takes an already created socket.
+ *
+ * @param socket Already created socket object
+ * @throws TTransportException if there is an error setting up the streams
+ */
+ public TSocket(Socket socket) throws TTransportException {
+ socket_ = socket;
+ try {
+ socket_.setSoLinger(false, 0);
+ socket_.setTcpNoDelay(true);
+ socket_.setKeepAlive(true);
+ } catch (SocketException sx) {
+ LOGGER.warn("Could not configure socket.", sx);
+ }
+
+ if (isOpen()) {
+ try {
+ inputStream_ = new BufferedInputStream(socket_.getInputStream());
+ outputStream_ = new BufferedOutputStream(socket_.getOutputStream());
+ } catch (IOException iox) {
+ close();
+ throw new TTransportException(TTransportException.NOT_OPEN, iox);
+ }
+ }
+ }
+
+ /**
+ * Creates a new unconnected socket that will connect to the given host
+ * on the given port.
+ *
+ * @param host Remote host
+ * @param port Remote port
+ */
+ public TSocket(String host, int port) {
+ this(host, port, 0);
+ }
+
+ /**
+ * Creates a new unconnected socket that will connect to the given host
+ * on the given port.
+ *
+ * @param host Remote host
+ * @param port Remote port
+ * @param timeout Socket timeout and connection timeout
+ */
+ public TSocket(String host, int port, int timeout) {
+ this(host, port, timeout, timeout);
+ }
+
+ /**
+ * Creates a new unconnected socket that will connect to the given host
+ * on the given port, with a specific connection timeout and a
+ * specific socket timeout.
+ *
+ * @param host Remote host
+ * @param port Remote port
+ * @param socketTimeout Socket timeout
+ * @param connectTimeout Connection timeout
+ */
+ public TSocket(String host, int port, int socketTimeout, int connectTimeout) {
+ host_ = host;
+ port_ = port;
+ socketTimeout_ = socketTimeout;
+ connectTimeout_ = connectTimeout;
+ initSocket();
+ }
+
+ /**
+ * Initializes the socket object
+ */
+ private void initSocket() {
+ socket_ = new Socket();
+ try {
+ socket_.setSoLinger(false, 0);
+ socket_.setTcpNoDelay(true);
+ socket_.setKeepAlive(true);
+ socket_.setSoTimeout(socketTimeout_);
+ } catch (SocketException sx) {
+ LOGGER.error("Could not configure socket.", sx);
+ }
+ }
+
+ /**
+ * Sets the socket timeout and connection timeout.
+ *
+ * @param timeout Milliseconds timeout
+ */
+ public void setTimeout(int timeout) {
+ this.setConnectTimeout(timeout);
+ this.setSocketTimeout(timeout);
+ }
+
+ /**
+ * Sets the time after which the connection attempt will time out
+ *
+ * @param timeout Milliseconds timeout
+ */
+ public void setConnectTimeout(int timeout) {
+ connectTimeout_ = timeout;
+ }
+
+ /**
+ * Sets the socket timeout
+ *
+ * @param timeout Milliseconds timeout
+ */
+ public void setSocketTimeout(int timeout) {
+ socketTimeout_ = timeout;
+ try {
+ socket_.setSoTimeout(timeout);
+ } catch (SocketException sx) {
+ LOGGER.warn("Could not set socket timeout.", sx);
+ }
+ }
+
+ /**
+ * Returns a reference to the underlying socket.
+ */
+ public Socket getSocket() {
+ if (socket_ == null) {
+ initSocket();
+ }
+ return socket_;
+ }
+
+ /**
+ * Checks whether the socket is connected.
+ */
+ public boolean isOpen() {
+ if (socket_ == null) {
+ return false;
+ }
+ return socket_.isConnected();
+ }
+
+ /**
+ * Connects the socket, creating a new socket object if necessary.
+ */
+ public void open() throws TTransportException {
+ if (isOpen()) {
+ throw new TTransportException(TTransportException.ALREADY_OPEN, "Socket already connected.");
+ }
+
+ if (host_ == null || host_.length() == 0) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open null host.");
+ }
+ if (port_ <= 0 || port_ > 65535) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Invalid port " + port_);
+ }
+
+ if (socket_ == null) {
+ initSocket();
+ }
+
+ try {
+ socket_.connect(new InetSocketAddress(host_, port_), connectTimeout_);
+ inputStream_ = new BufferedInputStream(socket_.getInputStream());
+ outputStream_ = new BufferedOutputStream(socket_.getOutputStream());
+ } catch (IOException iox) {
+ close();
+ throw new TTransportException(TTransportException.NOT_OPEN, iox);
+ }
+ }
+
+ /**
+ * Closes the socket.
+ */
+ public void close() {
+ // Close the underlying streams
+ super.close();
+
+ // Close the socket
+ if (socket_ != null) {
+ try {
+ socket_.close();
+ } catch (IOException iox) {
+ LOGGER.warn("Could not close socket.", iox);
+ }
+ socket_ = null;
+ }
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TStandardFile.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TStandardFile.java
new file mode 100644
index 000000000..7a33af8ee
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TStandardFile.java
@@ -0,0 +1,60 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+public class TStandardFile implements TSeekableFile {
+
+ protected String path_ = null;
+ protected RandomAccessFile inputFile_ = null;
+
+ public TStandardFile(String path) throws IOException {
+ path_ = path;
+ inputFile_ = new RandomAccessFile(path_, "r");
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return new FileInputStream(inputFile_.getFD());
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return new FileOutputStream(path_);
+ }
+
+ public void close() throws IOException {
+ if(inputFile_ != null) {
+ inputFile_.close();
+ }
+ }
+
+ public long length() throws IOException {
+ return inputFile_.length();
+ }
+
+ public void seek(long pos) throws IOException {
+ inputFile_.seek(pos);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransport.java
new file mode 100644
index 000000000..73ad730ce
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransport.java
@@ -0,0 +1,163 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.Closeable;
+
+/**
+ * Generic class that encapsulates the I/O layer. This is basically a thin
+ * wrapper around the combined functionality of Java input/output streams.
+ *
+ */
+public abstract class TTransport implements Closeable {
+
+ /**
+ * Queries whether the transport is open.
+ *
+ * @return True if the transport is open.
+ */
+ public abstract boolean isOpen();
+
+ /**
+ * Is there more data to be read?
+ *
+ * @return True if the remote side is still alive and feeding us
+ */
+ public boolean peek() {
+ return isOpen();
+ }
+
+ /**
+ * Opens the transport for reading/writing.
+ *
+ * @throws TTransportException if the transport could not be opened
+ */
+ public abstract void open()
+ throws TTransportException;
+
+ /**
+ * Closes the transport.
+ */
+ public abstract void close();
+
+ /**
+ * Reads up to len bytes into buffer buf, starting at offset off.
+ *
+ * @param buf Array to read into
+ * @param off Index to start reading at
+ * @param len Maximum number of bytes to read
+ * @return The number of bytes actually read
+ * @throws TTransportException if there was an error reading data
+ */
+ public abstract int read(byte[] buf, int off, int len)
+ throws TTransportException;
+
+ /**
+ * Guarantees that all of len bytes are actually read off the transport.
+ *
+ * @param buf Array to read into
+ * @param off Index to start reading at
+ * @param len Maximum number of bytes to read
+ * @return The number of bytes actually read, which must be equal to len
+ * @throws TTransportException if there was an error reading data
+ */
+ public int readAll(byte[] buf, int off, int len)
+ throws TTransportException {
+ int got = 0;
+ int ret = 0;
+ while (got < len) {
+ ret = read(buf, off+got, len-got);
+ if (ret <= 0) {
+ throw new TTransportException(
+ "Cannot read. Remote side has closed. Tried to read "
+ + len
+ + " bytes, but only got "
+ + got
+ + " bytes. (This is often indicative of an internal error on the server side. Please check your server logs.)");
+ }
+ got += ret;
+ }
+ return got;
+ }
+
+ /**
+ * Writes the buffer to the output
+ *
+ * @param buf The output data buffer
+ * @throws TTransportException if an error occurs writing data
+ */
+ public void write(byte[] buf) throws TTransportException {
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * Writes up to len bytes from the buffer.
+ *
+ * @param buf The output data buffer
+ * @param off The offset to start writing from
+ * @param len The number of bytes to write
+ * @throws TTransportException if there was an error writing data
+ */
+ public abstract void write(byte[] buf, int off, int len)
+ throws TTransportException;
+
+ /**
+ * Flush any pending data out of a transport buffer.
+ *
+ * @throws TTransportException if there was an error writing out data.
+ */
+ public void flush()
+ throws TTransportException {}
+
+ /**
+ * Access the protocol's underlying buffer directly. If this is not a
+ * buffered transport, return null.
+ * @return protocol's Underlying buffer
+ */
+ public byte[] getBuffer() {
+ return null;
+ }
+
+ /**
+ * Return the index within the underlying buffer that specifies the next spot
+ * that should be read from.
+ * @return index within the underlying buffer that specifies the next spot
+ * that should be read from
+ */
+ public int getBufferPosition() {
+ return 0;
+ }
+
+ /**
+ * Get the number of bytes remaining in the underlying buffer. Returns -1 if
+ * this is a non-buffered transport.
+ * @return the number of bytes remaining in the underlying buffer. <br> Returns -1 if
+ * this is a non-buffered transport.
+ */
+ public int getBytesRemainingInBuffer() {
+ return -1;
+ }
+
+ /**
+ * Consume len bytes from the underlying buffer.
+ * @param len
+ */
+ public void consumeBuffer(int len) {}
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportException.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportException.java
new file mode 100644
index 000000000..b886bc269
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportException.java
@@ -0,0 +1,81 @@
+/*
+ * 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.thrift.transport;
+
+import org.apache.thrift.TException;
+
+/**
+ * Transport exceptions.
+ *
+ */
+public class TTransportException extends TException {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final int UNKNOWN = 0;
+ public static final int NOT_OPEN = 1;
+ public static final int ALREADY_OPEN = 2;
+ public static final int TIMED_OUT = 3;
+ public static final int END_OF_FILE = 4;
+ public static final int CORRUPTED_DATA = 5;
+
+ protected int type_ = UNKNOWN;
+
+ public TTransportException() {
+ super();
+ }
+
+ public TTransportException(int type) {
+ super();
+ type_ = type;
+ }
+
+ public TTransportException(int type, String message) {
+ super(message);
+ type_ = type;
+ }
+
+ public TTransportException(String message) {
+ super(message);
+ }
+
+ public TTransportException(int type, Throwable cause) {
+ super(cause);
+ type_ = type;
+ }
+
+ public TTransportException(Throwable cause) {
+ super(cause);
+ }
+
+ public TTransportException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TTransportException(int type, String message, Throwable cause) {
+ super(message, cause);
+ type_ = type;
+ }
+
+ public int getType() {
+ return type_;
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportFactory.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportFactory.java
new file mode 100644
index 000000000..3e71630ae
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TTransportFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.thrift.transport;
+
+/**
+ * Factory class used to create wrapped instance of Transports.
+ * This is used primarily in servers, which get Transports from
+ * a ServerTransport and then may want to mutate them (i.e. create
+ * a BufferedTransport from the underlying base transport)
+ *
+ */
+public class TTransportFactory {
+
+ /**
+ * Return a wrapped instance of the base Transport.
+ *
+ * @param trans The base transport
+ * @return Wrapped Transport
+ */
+ public TTransport getTransport(TTransport trans) {
+ return trans;
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TZlibTransport.java b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TZlibTransport.java
new file mode 100644
index 000000000..e755aa532
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/transport/TZlibTransport.java
@@ -0,0 +1,148 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * TZlibTransport deflates on write and inflates on read.
+ */
+public class TZlibTransport extends TIOStreamTransport {
+
+ private TTransport transport_ = null;
+
+ public static class Factory extends TTransportFactory {
+ public Factory() {
+ }
+
+ @Override
+ public TTransport getTransport(TTransport base) {
+ return new TZlibTransport(base);
+ }
+ }
+
+ /**
+ * Constructs a new TZlibTransport instance.
+ * @param transport the underlying transport to read from and write to
+ */
+ public TZlibTransport(TTransport transport) {
+ this(transport, Deflater.BEST_COMPRESSION);
+ }
+
+ /**
+ * Constructs a new TZlibTransport instance.
+ * @param transport the underlying transport to read from and write to
+ * @param compressionLevel 0 for no compression, 9 for maximum compression
+ */
+ public TZlibTransport(TTransport transport, int compressionLevel) {
+ transport_ = transport;
+ inputStream_ = new InflaterInputStream(new TTransportInputStream(transport_), new Inflater());
+ outputStream_ = new DeflaterOutputStream(new TTransportOutputStream(transport_), new Deflater(compressionLevel, false), true);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return transport_.isOpen();
+ }
+
+ @Override
+ public void open() throws TTransportException {
+ transport_.open();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ if (transport_.isOpen()) {
+ transport_.close();
+ }
+ }
+}
+
+class TTransportInputStream extends InputStream {
+
+ private TTransport transport = null;
+
+ public TTransportInputStream(TTransport transport) {
+ this.transport = transport;
+ }
+
+ @Override
+ public int read() throws IOException {
+ try {
+ byte[] buf = new byte[1];
+ transport.read(buf, 0, 1);
+ return buf[0];
+ } catch (TTransportException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public int read(byte b[], int off, int len) throws IOException {
+ try {
+ return transport.read(b, off, len);
+ } catch (TTransportException e) {
+ throw new IOException(e);
+ }
+ }
+}
+
+class TTransportOutputStream extends OutputStream {
+
+ private TTransport transport = null;
+
+ public TTransportOutputStream(TTransport transport) {
+ this.transport = transport;
+ }
+
+ @Override
+ public void write(final int b) throws IOException {
+ try {
+ transport.write(new byte[]{(byte) b});
+ } catch (TTransportException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) throws IOException {
+ try {
+ transport.write(b, off, len);
+ } catch (TTransportException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ transport.flush();
+ } catch (TTransportException e) {
+ throw new IOException(e);
+ }
+ }
+}
+
diff --git a/src/jaegertracing/thrift/lib/java/test/.keystore b/src/jaegertracing/thrift/lib/java/test/.keystore
new file mode 100644
index 000000000..4dd66ac07
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/.keystore
Binary files differ
diff --git a/src/jaegertracing/thrift/lib/java/test/.truststore b/src/jaegertracing/thrift/lib/java/test/.truststore
new file mode 100644
index 000000000..26fbd195f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/.truststore
Binary files differ
diff --git a/src/jaegertracing/thrift/lib/java/test/log4j.properties b/src/jaegertracing/thrift/lib/java/test/log4j.properties
new file mode 100644
index 000000000..ab9bebafe
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/log4j.properties
@@ -0,0 +1,6 @@
+# log4j configuration used during build and unit tests
+log4j.rootLogger=debug,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/Fixtures.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/Fixtures.java
new file mode 100644
index 000000000..61f40a590
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/Fixtures.java
@@ -0,0 +1,340 @@
+/*
+ * 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.thrift;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import thrift.test.Bonk;
+import thrift.test.CompactProtoTestStruct;
+import thrift.test.HolyMoley;
+import thrift.test.Nesting;
+import thrift.test.OneOfEach;
+
+public class Fixtures {
+ public static final OneOfEach oneOfEach;
+ public static final Nesting nesting;
+ public static final HolyMoley holyMoley;
+ public static final CompactProtoTestStruct compactProtoTestStruct;
+
+ // These byte arrays are serialized versions of the above structs.
+ // They were serialized in binary protocol using thrift 0.6.x and are used to
+ // test backwards compatibility with respect to the standard scheme.
+ public static final byte[] persistentBytesOneOfEach = new byte[] { (byte) 0x02, (byte) 0x00,
+ (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x00, (byte) 0x02,
+ (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x03, (byte) 0xD6,
+ (byte) 0x06, (byte) 0x00, (byte) 0x04, (byte) 0x69, (byte) 0x78,
+ (byte) 0x08, (byte) 0x00, (byte) 0x05, (byte) 0x01, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x0A, (byte) 0x00, (byte) 0x06,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x65,
+ (byte) 0xA0, (byte) 0xBC, (byte) 0x00, (byte) 0x04, (byte) 0x00,
+ (byte) 0x07, (byte) 0x40, (byte) 0x09, (byte) 0x21, (byte) 0xFB,
+ (byte) 0x54, (byte) 0x44, (byte) 0x2D, (byte) 0x18, (byte) 0x0B,
+ (byte) 0x00, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x0D, (byte) 0x4A, (byte) 0x53, (byte) 0x4F, (byte) 0x4E,
+ (byte) 0x20, (byte) 0x54, (byte) 0x48, (byte) 0x49, (byte) 0x53,
+ (byte) 0x21, (byte) 0x20, (byte) 0x22, (byte) 0x01, (byte) 0x0B,
+ (byte) 0x00, (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x2E, (byte) 0xD3, (byte) 0x80, (byte) 0xE2, (byte) 0x85,
+ (byte) 0xAE, (byte) 0xCE, (byte) 0x9D, (byte) 0x20, (byte) 0xD0,
+ (byte) 0x9D, (byte) 0xCE, (byte) 0xBF, (byte) 0xE2, (byte) 0x85,
+ (byte) 0xBF, (byte) 0xD0, (byte) 0xBE, (byte) 0xC9, (byte) 0xA1,
+ (byte) 0xD0, (byte) 0xB3, (byte) 0xD0, (byte) 0xB0, (byte) 0xCF,
+ (byte) 0x81, (byte) 0xE2, (byte) 0x84, (byte) 0x8E, (byte) 0x20,
+ (byte) 0xCE, (byte) 0x91, (byte) 0x74, (byte) 0x74, (byte) 0xCE,
+ (byte) 0xB1, (byte) 0xE2, (byte) 0x85, (byte) 0xBD, (byte) 0xCE,
+ (byte) 0xBA, (byte) 0xEF, (byte) 0xBF, (byte) 0xBD, (byte) 0xE2,
+ (byte) 0x80, (byte) 0xBC, (byte) 0x02, (byte) 0x00, (byte) 0x0A,
+ (byte) 0x00, (byte) 0x0B, (byte) 0x00, (byte) 0x0B, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x62, (byte) 0x61,
+ (byte) 0x73, (byte) 0x65, (byte) 0x36, (byte) 0x34, (byte) 0x0F,
+ (byte) 0x00, (byte) 0x0C, (byte) 0x03, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x03, (byte) 0x01, (byte) 0x02, (byte) 0x03,
+ (byte) 0x0F, (byte) 0x00, (byte) 0x0D, (byte) 0x06, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x03, (byte) 0x0F,
+ (byte) 0x00, (byte) 0x0E, (byte) 0x0A, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x03, (byte) 0x00 };
+ public static final byte[] persistentBytesNesting = new byte[] { (byte) 0x0C, (byte) 0x00,
+ (byte) 0x01, (byte) 0x08, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0x00, (byte) 0x7A, (byte) 0x69, (byte) 0x0B, (byte) 0x00,
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x13,
+ (byte) 0x49, (byte) 0x20, (byte) 0x61, (byte) 0x6D, (byte) 0x20,
+ (byte) 0x61, (byte) 0x20, (byte) 0x62, (byte) 0x6F, (byte) 0x6E,
+ (byte) 0x6B, (byte) 0x2E, (byte) 0x2E, (byte) 0x2E, (byte) 0x20,
+ (byte) 0x78, (byte) 0x6F, (byte) 0x72, (byte) 0x21, (byte) 0x00,
+ (byte) 0x0C, (byte) 0x00, (byte) 0x02, (byte) 0x02, (byte) 0x00,
+ (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x00, (byte) 0x02,
+ (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x03, (byte) 0xD6,
+ (byte) 0x06, (byte) 0x00, (byte) 0x04, (byte) 0x69, (byte) 0x78,
+ (byte) 0x08, (byte) 0x00, (byte) 0x05, (byte) 0x01, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x0A, (byte) 0x00, (byte) 0x06,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x65,
+ (byte) 0xA0, (byte) 0xBC, (byte) 0x00, (byte) 0x04, (byte) 0x00,
+ (byte) 0x07, (byte) 0x40, (byte) 0x09, (byte) 0x21, (byte) 0xFB,
+ (byte) 0x54, (byte) 0x44, (byte) 0x2D, (byte) 0x18, (byte) 0x0B,
+ (byte) 0x00, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x0D, (byte) 0x4A, (byte) 0x53, (byte) 0x4F, (byte) 0x4E,
+ (byte) 0x20, (byte) 0x54, (byte) 0x48, (byte) 0x49, (byte) 0x53,
+ (byte) 0x21, (byte) 0x20, (byte) 0x22, (byte) 0x01, (byte) 0x0B,
+ (byte) 0x00, (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x2E, (byte) 0xD3, (byte) 0x80, (byte) 0xE2, (byte) 0x85,
+ (byte) 0xAE, (byte) 0xCE, (byte) 0x9D, (byte) 0x20, (byte) 0xD0,
+ (byte) 0x9D, (byte) 0xCE, (byte) 0xBF, (byte) 0xE2, (byte) 0x85,
+ (byte) 0xBF, (byte) 0xD0, (byte) 0xBE, (byte) 0xC9, (byte) 0xA1,
+ (byte) 0xD0, (byte) 0xB3, (byte) 0xD0, (byte) 0xB0, (byte) 0xCF,
+ (byte) 0x81, (byte) 0xE2, (byte) 0x84, (byte) 0x8E, (byte) 0x20,
+ (byte) 0xCE, (byte) 0x91, (byte) 0x74, (byte) 0x74, (byte) 0xCE,
+ (byte) 0xB1, (byte) 0xE2, (byte) 0x85, (byte) 0xBD, (byte) 0xCE,
+ (byte) 0xBA, (byte) 0xEF, (byte) 0xBF, (byte) 0xBD, (byte) 0xE2,
+ (byte) 0x80, (byte) 0xBC, (byte) 0x02, (byte) 0x00, (byte) 0x0A,
+ (byte) 0x00, (byte) 0x0B, (byte) 0x00, (byte) 0x0B, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x62, (byte) 0x61,
+ (byte) 0x73, (byte) 0x65, (byte) 0x36, (byte) 0x34, (byte) 0x0F,
+ (byte) 0x00, (byte) 0x0C, (byte) 0x03, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x03, (byte) 0x01, (byte) 0x02, (byte) 0x03,
+ (byte) 0x0F, (byte) 0x00, (byte) 0x0D, (byte) 0x06, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x03, (byte) 0x0F,
+ (byte) 0x00, (byte) 0x0E, (byte) 0x0A, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x03, (byte) 0x00, (byte) 0x00 };
+ public static final byte[] persistentBytesHolyMoley = new byte[] { (byte) 0x0F, (byte) 0x00,
+ (byte) 0x01, (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x02, (byte) 0x02, (byte) 0x00, (byte) 0x01, (byte) 0x01,
+ (byte) 0x02, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x03,
+ (byte) 0x00, (byte) 0x03, (byte) 0x23, (byte) 0x06, (byte) 0x00,
+ (byte) 0x04, (byte) 0x69, (byte) 0x78, (byte) 0x08, (byte) 0x00,
+ (byte) 0x05, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x0A, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x65, (byte) 0xA0, (byte) 0xBC,
+ (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0x40,
+ (byte) 0x09, (byte) 0x21, (byte) 0xFB, (byte) 0x54, (byte) 0x44,
+ (byte) 0x2D, (byte) 0x18, (byte) 0x0B, (byte) 0x00, (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0D, (byte) 0x4A,
+ (byte) 0x53, (byte) 0x4F, (byte) 0x4E, (byte) 0x20, (byte) 0x54,
+ (byte) 0x48, (byte) 0x49, (byte) 0x53, (byte) 0x21, (byte) 0x20,
+ (byte) 0x22, (byte) 0x01, (byte) 0x0B, (byte) 0x00, (byte) 0x09,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x2E, (byte) 0xD3,
+ (byte) 0x80, (byte) 0xE2, (byte) 0x85, (byte) 0xAE, (byte) 0xCE,
+ (byte) 0x9D, (byte) 0x20, (byte) 0xD0, (byte) 0x9D, (byte) 0xCE,
+ (byte) 0xBF, (byte) 0xE2, (byte) 0x85, (byte) 0xBF, (byte) 0xD0,
+ (byte) 0xBE, (byte) 0xC9, (byte) 0xA1, (byte) 0xD0, (byte) 0xB3,
+ (byte) 0xD0, (byte) 0xB0, (byte) 0xCF, (byte) 0x81, (byte) 0xE2,
+ (byte) 0x84, (byte) 0x8E, (byte) 0x20, (byte) 0xCE, (byte) 0x91,
+ (byte) 0x74, (byte) 0x74, (byte) 0xCE, (byte) 0xB1, (byte) 0xE2,
+ (byte) 0x85, (byte) 0xBD, (byte) 0xCE, (byte) 0xBA, (byte) 0xEF,
+ (byte) 0xBF, (byte) 0xBD, (byte) 0xE2, (byte) 0x80, (byte) 0xBC,
+ (byte) 0x02, (byte) 0x00, (byte) 0x0A, (byte) 0x00, (byte) 0x0B,
+ (byte) 0x00, (byte) 0x0B, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x06, (byte) 0x62, (byte) 0x61, (byte) 0x73, (byte) 0x65,
+ (byte) 0x36, (byte) 0x34, (byte) 0x0F, (byte) 0x00, (byte) 0x0C,
+ (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
+ (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x0F, (byte) 0x00,
+ (byte) 0x0D, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x03, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x02,
+ (byte) 0x00, (byte) 0x03, (byte) 0x0F, (byte) 0x00, (byte) 0x0E,
+ (byte) 0x0A, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00,
+ (byte) 0x02, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x02,
+ (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x03, (byte) 0x00,
+ (byte) 0x03, (byte) 0xD6, (byte) 0x06, (byte) 0x00, (byte) 0x04,
+ (byte) 0x69, (byte) 0x78, (byte) 0x08, (byte) 0x00, (byte) 0x05,
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0A,
+ (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x01, (byte) 0x65, (byte) 0xA0, (byte) 0xBC, (byte) 0x00,
+ (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0x40, (byte) 0x09,
+ (byte) 0x21, (byte) 0xFB, (byte) 0x54, (byte) 0x44, (byte) 0x2D,
+ (byte) 0x18, (byte) 0x0B, (byte) 0x00, (byte) 0x08, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x0D, (byte) 0x4A, (byte) 0x53,
+ (byte) 0x4F, (byte) 0x4E, (byte) 0x20, (byte) 0x54, (byte) 0x48,
+ (byte) 0x49, (byte) 0x53, (byte) 0x21, (byte) 0x20, (byte) 0x22,
+ (byte) 0x01, (byte) 0x0B, (byte) 0x00, (byte) 0x09, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x2E, (byte) 0xD3, (byte) 0x80,
+ (byte) 0xE2, (byte) 0x85, (byte) 0xAE, (byte) 0xCE, (byte) 0x9D,
+ (byte) 0x20, (byte) 0xD0, (byte) 0x9D, (byte) 0xCE, (byte) 0xBF,
+ (byte) 0xE2, (byte) 0x85, (byte) 0xBF, (byte) 0xD0, (byte) 0xBE,
+ (byte) 0xC9, (byte) 0xA1, (byte) 0xD0, (byte) 0xB3, (byte) 0xD0,
+ (byte) 0xB0, (byte) 0xCF, (byte) 0x81, (byte) 0xE2, (byte) 0x84,
+ (byte) 0x8E, (byte) 0x20, (byte) 0xCE, (byte) 0x91, (byte) 0x74,
+ (byte) 0x74, (byte) 0xCE, (byte) 0xB1, (byte) 0xE2, (byte) 0x85,
+ (byte) 0xBD, (byte) 0xCE, (byte) 0xBA, (byte) 0xEF, (byte) 0xBF,
+ (byte) 0xBD, (byte) 0xE2, (byte) 0x80, (byte) 0xBC, (byte) 0x02,
+ (byte) 0x00, (byte) 0x0A, (byte) 0x00, (byte) 0x0B, (byte) 0x00,
+ (byte) 0x0B, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
+ (byte) 0x62, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x36,
+ (byte) 0x34, (byte) 0x0F, (byte) 0x00, (byte) 0x0C, (byte) 0x03,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x01,
+ (byte) 0x02, (byte) 0x03, (byte) 0x0F, (byte) 0x00, (byte) 0x0D,
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x00,
+ (byte) 0x03, (byte) 0x0F, (byte) 0x00, (byte) 0x0E, (byte) 0x0A,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x0E,
+ (byte) 0x00, (byte) 0x02, (byte) 0x0F, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x03, (byte) 0x0B, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x0B, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x0F, (byte) 0x74, (byte) 0x68, (byte) 0x65, (byte) 0x6E,
+ (byte) 0x20, (byte) 0x61, (byte) 0x20, (byte) 0x6F, (byte) 0x6E,
+ (byte) 0x65, (byte) 0x2C, (byte) 0x20, (byte) 0x74, (byte) 0x77,
+ (byte) 0x6F, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
+ (byte) 0x74, (byte) 0x68, (byte) 0x72, (byte) 0x65, (byte) 0x65,
+ (byte) 0x21, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
+ (byte) 0x46, (byte) 0x4F, (byte) 0x55, (byte) 0x52, (byte) 0x21,
+ (byte) 0x21, (byte) 0x0B, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x09,
+ (byte) 0x61, (byte) 0x6E, (byte) 0x64, (byte) 0x20, (byte) 0x61,
+ (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x09, (byte) 0x61, (byte) 0x6E,
+ (byte) 0x64, (byte) 0x20, (byte) 0x61, (byte) 0x20, (byte) 0x74,
+ (byte) 0x77, (byte) 0x6F, (byte) 0x0D, (byte) 0x00, (byte) 0x03,
+ (byte) 0x0B, (byte) 0x0F, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
+ (byte) 0x74, (byte) 0x77, (byte) 0x6F, (byte) 0x0C, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x08, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
+ (byte) 0x0B, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x05, (byte) 0x57, (byte) 0x61, (byte) 0x69,
+ (byte) 0x74, (byte) 0x2E, (byte) 0x00, (byte) 0x08, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+ (byte) 0x0B, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x05, (byte) 0x57, (byte) 0x68, (byte) 0x61,
+ (byte) 0x74, (byte) 0x3F, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x05, (byte) 0x74, (byte) 0x68, (byte) 0x72,
+ (byte) 0x65, (byte) 0x65, (byte) 0x0C, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x04, (byte) 0x7A, (byte) 0x65, (byte) 0x72, (byte) 0x6F,
+ (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00 };
+
+ private static final byte[] kUnicodeBytes = { (byte) 0xd3, (byte) 0x80,
+ (byte) 0xe2, (byte) 0x85, (byte) 0xae, (byte) 0xce, (byte) 0x9d,
+ (byte) 0x20, (byte) 0xd0, (byte) 0x9d, (byte) 0xce, (byte) 0xbf,
+ (byte) 0xe2, (byte) 0x85, (byte) 0xbf, (byte) 0xd0, (byte) 0xbe,
+ (byte) 0xc9, (byte) 0xa1, (byte) 0xd0, (byte) 0xb3, (byte) 0xd0,
+ (byte) 0xb0, (byte) 0xcf, (byte) 0x81, (byte) 0xe2, (byte) 0x84,
+ (byte) 0x8e, (byte) 0x20, (byte) 0xce, (byte) 0x91, (byte) 0x74,
+ (byte) 0x74, (byte) 0xce, (byte) 0xb1, (byte) 0xe2, (byte) 0x85,
+ (byte) 0xbd, (byte) 0xce, (byte) 0xba, (byte) 0x83, (byte) 0xe2,
+ (byte) 0x80, (byte) 0xbc };
+
+ static {
+ try {
+ oneOfEach = new OneOfEach();
+ oneOfEach.setIm_true(true);
+ oneOfEach.setIm_false(false);
+ oneOfEach.setA_bite((byte) 0xd6);
+ oneOfEach.setInteger16((short) 27000);
+ oneOfEach.setInteger32(1 << 24);
+ oneOfEach.setInteger64((long) 6000 * 1000 * 1000);
+ oneOfEach.setDouble_precision(Math.PI);
+ oneOfEach.setSome_characters("JSON THIS! \"\1");
+ oneOfEach.setZomg_unicode(new String(kUnicodeBytes, StandardCharsets.UTF_8));
+ oneOfEach.setBase64(ByteBuffer.wrap("base64".getBytes()));
+ // byte, i16, and i64 lists are populated by default constructor
+
+ Bonk bonk = new Bonk();
+ bonk.setType(31337);
+ bonk.setMessage("I am a bonk... xor!");
+ nesting = new Nesting(bonk, oneOfEach);
+
+ holyMoley = new HolyMoley();
+ List<OneOfEach> big = new ArrayList<OneOfEach>();
+ big.add(new OneOfEach(oneOfEach));
+ big.add(nesting.my_ooe);
+ holyMoley.setBig(big);
+ holyMoley.getBig().get(0).setA_bite((byte) 0x22);
+ holyMoley.getBig().get(0).setA_bite((byte) 0x23);
+
+ holyMoley.setContain(new HashSet<List<String>>());
+ ArrayList<String> stage1 = new ArrayList<String>(2);
+ stage1.add("and a one");
+ stage1.add("and a two");
+ holyMoley.getContain().add(stage1);
+ stage1 = new ArrayList<String>(3);
+ stage1.add("then a one, two");
+ stage1.add("three!");
+ stage1.add("FOUR!!");
+ holyMoley.getContain().add(stage1);
+ stage1 = new ArrayList<String>(0);
+ holyMoley.getContain().add(stage1);
+
+ ArrayList<Bonk> stage2 = new ArrayList<Bonk>();
+ holyMoley.setBonks(new HashMap<String, List<Bonk>>());
+ // one empty
+ holyMoley.getBonks().put("zero", stage2);
+
+ // one with two
+ stage2 = new ArrayList<Bonk>();
+ Bonk b = new Bonk();
+ b.setType(1);
+ b.setMessage("Wait.");
+ stage2.add(b);
+ b = new Bonk();
+ b.setType(2);
+ b.setMessage("What?");
+ stage2.add(b);
+ holyMoley.getBonks().put("two", stage2);
+
+ // one with three
+ stage2 = new ArrayList<Bonk>();
+ b = new Bonk();
+ b.setType(3);
+ b.setMessage("quoth");
+ b = new Bonk();
+ b.setType(4);
+ b.setMessage("the raven");
+ b = new Bonk();
+ b.setType(5);
+ b.setMessage("nevermore");
+ holyMoley.getBonks().put("three", stage2);
+
+ // superhuge compact proto test struct
+ compactProtoTestStruct = new CompactProtoTestStruct(
+ thrift.test.DebugProtoTestConstants.COMPACT_TEST);
+ compactProtoTestStruct.setA_binary(ByteBuffer.wrap(new byte[] { 0, 1, 2,
+ 3, 4, 5, 6, 7, 8 }));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestDeepCopy.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestDeepCopy.java
new file mode 100644
index 000000000..acafaef10
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestDeepCopy.java
@@ -0,0 +1,34 @@
+package org.apache.thrift;
+
+import junit.framework.TestCase;
+import thrift.test.DeepCopyBar;
+import thrift.test.DeepCopyFoo;
+
+public class TestDeepCopy extends TestCase {
+
+ public void testDeepCopy() throws Exception {
+ final DeepCopyFoo foo = new DeepCopyFoo();
+
+ foo.addToL(new DeepCopyBar());
+ foo.addToS(new DeepCopyBar());
+ foo.putToM("test 3", new DeepCopyBar());
+
+ foo.addToLi(new thrift.test.Object());
+ foo.addToSi(new thrift.test.Object());
+ foo.putToMi("test 3", new thrift.test.Object());
+
+ foo.setBar(new DeepCopyBar());
+
+ final DeepCopyFoo deepCopyFoo = foo.deepCopy();
+
+ assertNotSame(foo.getBar(), deepCopyFoo.getBar());
+
+ assertNotSame(foo.getL().get(0), deepCopyFoo.getL().get(0));
+ assertNotSame(foo.getS().toArray(new DeepCopyBar[0])[0], deepCopyFoo.getS().toArray(new DeepCopyBar[0])[0]);
+ assertNotSame(foo.getM().get("test 3"), deepCopyFoo.getM().get("test 3"));
+
+ assertNotSame(foo.getLi().get(0), deepCopyFoo.getLi().get(0));
+ assertNotSame(foo.getSi().toArray(new thrift.test.Object[0])[0], deepCopyFoo.getSi().toArray(new thrift.test.Object[0])[0]);
+ assertNotSame(foo.getMi().get("test 3"), deepCopyFoo.getMi().get("test 3"));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestEnumContainers.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestEnumContainers.java
new file mode 100644
index 000000000..683246ba6
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestEnumContainers.java
@@ -0,0 +1,81 @@
+/*
+ * 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.thrift;
+
+import junit.framework.TestCase;
+import thrift.test.enumcontainers.EnumContainersTestConstants;
+import thrift.test.enumcontainers.GodBean;
+import thrift.test.enumcontainers.GreekGodGoddess;
+
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+
+public class TestEnumContainers extends TestCase {
+
+ public void testEnumContainers() throws Exception {
+ final GodBean b1 = new GodBean();
+ b1.addToGoddess(GreekGodGoddess.HERA);
+ b1.getGoddess().add(GreekGodGoddess.APHRODITE);
+ b1.putToPower(GreekGodGoddess.ZEUS, 1000);
+ b1.getPower().put(GreekGodGoddess.HERA, 333);
+ b1.putToByAlias("Mr. Z", GreekGodGoddess.ZEUS);
+ b1.addToImages("Baths of Aphrodite 01.jpeg");
+
+ final GodBean b2 = new GodBean(b1);
+
+ final GodBean b3 = new GodBean();
+ {
+ final TSerializer serializer = new TSerializer();
+ final TDeserializer deserializer = new TDeserializer();
+
+ final byte[] bytes = serializer.serialize(b1);
+ deserializer.deserialize(b3, bytes);
+ }
+
+ assertTrue(b1.getGoddess() != b2.getGoddess());
+ assertTrue(b1.getPower() != b2.getPower());
+
+ assertTrue(b1.getGoddess() != b3.getGoddess());
+ assertTrue(b1.getPower() != b3.getPower());
+
+ for (GodBean each : new GodBean[]{b1, b2, b3}) {
+ assertTrue(each.getGoddess().contains(GreekGodGoddess.HERA));
+ assertFalse(each.getGoddess().contains(GreekGodGoddess.POSEIDON));
+ assertTrue(each.getGoddess() instanceof EnumSet);
+
+ assertEquals(Integer.valueOf(1000), each.getPower().get(GreekGodGoddess.ZEUS));
+ assertEquals(Integer.valueOf(333), each.getPower().get(GreekGodGoddess.HERA));
+ assertTrue(each.getPower() instanceof EnumMap);
+
+ assertTrue(each.getByAlias() instanceof HashMap);
+ assertTrue(each.getImages() instanceof HashSet);
+ }
+ }
+
+ public void testEnumConstants() {
+ assertEquals("lightning bolt", EnumContainersTestConstants.ATTRIBUTES.get(GreekGodGoddess.ZEUS));
+ assertTrue(EnumContainersTestConstants.ATTRIBUTES instanceof EnumMap);
+
+ assertTrue(EnumContainersTestConstants.BEAUTY.contains(GreekGodGoddess.APHRODITE));
+ assertTrue(EnumContainersTestConstants.BEAUTY instanceof EnumSet);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestFullCamel.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestFullCamel.java
new file mode 100644
index 000000000..fc9889890
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestFullCamel.java
@@ -0,0 +1,59 @@
+/*
+ * 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.thrift;
+
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TType;
+
+import thrift.test.fullcamel.OneOfEachZZ;
+import thrift.test.fullcamel.UnderscoreSrv;
+
+// Sanity check for the code generated by 'fullcamel'.
+//
+public class TestFullCamel extends TestCase {
+
+ public void testCamelCaseSyntax() throws Exception {
+ TSerializer binarySerializer = new TSerializer(new TBinaryProtocol.Factory());
+ TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
+
+ OneOfEachZZ obj = new OneOfEachZZ();
+ obj.setABite((byte) 0xae);
+ obj.setImFalse(true);
+ byte[] serBytes = binarySerializer.serialize(obj);
+ binaryDeserializer.deserialize(obj, serBytes);
+ assertTrue( obj.getABite() == (byte) 0xae );
+ assertTrue( obj.isImFalse() == true );
+ }
+
+ public void testCamelCaseRpcMethods() throws Exception {
+ final UnderscoreSrv.Iface srv = new UnderscoreSrv.Iface() {
+ @Override
+ public long someRpcCall(String message) {
+ return 1l;
+ }
+ };
+ assertTrue(1l == srv.someRpcCall("test"));
+ }
+}
+
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java
new file mode 100644
index 000000000..85e7966bf
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java
@@ -0,0 +1,85 @@
+/*
+ * 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.thrift;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TMessageType;
+import org.apache.thrift.protocol.TProtocol;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestMultiplexedProcessor {
+ private TMultiplexedProcessor mp;
+ private TProtocol iprot;
+ private TProtocol oprot;
+
+ @Before
+ public void setUp() throws Exception {
+ mp = new TMultiplexedProcessor();
+ iprot = mock(TProtocol.class);
+ oprot = mock(TProtocol.class);
+ }
+
+ @Test(expected = TException.class)
+ public void testWrongMessageType() throws TException {
+ when (iprot.readMessageBegin()).thenReturn(new TMessage("service:func", TMessageType.REPLY, 42));
+ mp.process(iprot, oprot);
+ }
+
+ @Test(expected = TException.class)
+ public void testNoSuchService() throws TException {
+ when(iprot.readMessageBegin()).thenReturn(new TMessage("service:func", TMessageType.CALL, 42));
+
+ mp.process(iprot, oprot);
+ }
+
+ static class StubProcessor implements TProcessor {
+ @Override
+ public void process(TProtocol in, TProtocol out) throws TException {
+ TMessage msg = in.readMessageBegin();
+ if (!"func".equals(msg.name) || msg.type!=TMessageType.CALL || msg.seqid!=42) {
+ throw new TException("incorrect parameters");
+ }
+ out.writeMessageBegin(new TMessage("func", TMessageType.REPLY, 42));
+ }
+ }
+
+ @Test
+ public void testExistingService() throws TException {
+ when(iprot.readMessageBegin()).thenReturn(new TMessage("service:func", TMessageType.CALL, 42));
+ mp.registerProcessor("service", new StubProcessor());
+ mp.process(iprot, oprot);
+ verify(oprot).writeMessageBegin(any(TMessage.class));
+ }
+
+ @Test
+ public void testDefaultService() throws TException {
+ when(iprot.readMessageBegin()).thenReturn(new TMessage("func", TMessageType.CALL, 42));
+ mp.registerDefault(new StubProcessor());
+ mp.process(iprot, oprot);
+ verify(oprot).writeMessageBegin(any(TMessage.class));
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionType.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionType.java
new file mode 100644
index 000000000..f70285ffa
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionType.java
@@ -0,0 +1,66 @@
+/*
+ * 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.thrift;
+
+import junit.framework.TestCase;
+import org.apache.thrift.Option;
+
+// Tests and documents behavior for the "Option<T>" type
+public class TestOptionType extends TestCase {
+ public void testSome() throws Exception {
+ String name = "Chuck Norris";
+ Option<String> option = Option.fromNullable(name);
+
+ assertTrue(option instanceof Option.Some);
+ assertTrue(option.isDefined());
+ assertEquals("Some(Chuck Norris)", option.toString());
+ assertEquals(option.or("default value"), "Chuck Norris");
+ assertEquals(option.get(),"Chuck Norris");
+ }
+
+ public void testNone() throws Exception {
+ String name = null;
+ Option<String> option = Option.fromNullable(name);
+
+ assertTrue(option instanceof Option.None);
+ assertFalse(option.isDefined());
+ assertEquals("None", option.toString());
+ assertEquals(option.or("default value"), "default value");
+ // Expect exception
+ try {
+ Object value = option.get();
+ fail("Expected IllegalStateException, got no exception");
+ } catch (IllegalStateException ex) {
+
+ } catch(Exception ex) {
+ fail("Expected IllegalStateException, got some other exception: "+ex.toString());
+ }
+ }
+
+ public void testMakeSome() throws Exception {
+ Option<String> some = Option.some("wee");
+ assertTrue(some instanceof Option.Some);
+ }
+
+ public void testMakeNone() throws Exception {
+ Option<Integer> none = Option.none();
+ assertTrue(none instanceof Option.None);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionals.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionals.java
new file mode 100644
index 000000000..d1591ee2c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestOptionals.java
@@ -0,0 +1,88 @@
+/*
+ * 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.thrift;
+
+import junit.framework.TestCase;
+
+import thrift.test.Opt4;
+import thrift.test.Opt30;
+import thrift.test.Opt64;
+import thrift.test.Opt80;
+
+// Exercises the isSet methods using structs from from ManyOptionals.thrift
+public class TestOptionals extends TestCase {
+ public void testEncodingUtils() throws Exception {
+ assertEquals((short)0x8, EncodingUtils.setBit((short)0, 3, true));
+ assertEquals((short)0, EncodingUtils.setBit((short)0x8, 3, false));
+ assertEquals(true, EncodingUtils.testBit((short)0x8, 3));
+ assertEquals(false, EncodingUtils.testBit((short)0x8, 4));
+
+ assertEquals((short)Short.MIN_VALUE, EncodingUtils.setBit((short)0, 15, true));
+ assertEquals((short)0, EncodingUtils.setBit((short)Short.MIN_VALUE, 15, false));
+ assertEquals(true, EncodingUtils.testBit(Short.MIN_VALUE, 15));
+ assertEquals(false, EncodingUtils.testBit(Short.MIN_VALUE, 14));
+ }
+
+ public void testOpt4() throws Exception {
+ Opt4 x = new Opt4();
+ assertEquals(false, x.isSetDef1());
+ x.setDef1(3);
+ assertEquals(true, x.isSetDef1());
+ assertEquals(false, x.isSetDef2());
+
+ Opt4 copy = new Opt4(x);
+ assertEquals(true, copy.isSetDef1());
+ copy.unsetDef1();
+ assertEquals(false, copy.isSetDef1());
+ assertEquals(true, x.isSetDef1());
+ }
+
+ public void testOpt30() throws Exception {
+ Opt30 x = new Opt30();
+ assertEquals(false, x.isSetDef1());
+ x.setDef1(3);
+ assertEquals(true, x.isSetDef1());
+ assertEquals(false, x.isSetDef2());
+ }
+
+ public void testOpt64() throws Exception {
+ Opt64 x = new Opt64();
+ assertEquals(false, x.isSetDef1());
+ x.setDef1(3);
+ assertEquals(true, x.isSetDef1());
+ assertEquals(false, x.isSetDef2());
+ x.setDef64(22);
+ assertEquals(true, x.isSetDef64());
+ assertEquals(false, x.isSetDef63());
+ }
+
+ public void testOpt80() throws Exception {
+ Opt80 x = new Opt80();
+ assertEquals(false, x.isSetDef1());
+ x.setDef1(3);
+ assertEquals(true, x.isSetDef1());
+ assertEquals(false, x.isSetDef2());
+
+ Opt80 copy = new Opt80(x);
+ copy.unsetDef1();
+ assertEquals(false, copy.isSetDef1());
+ assertEquals(true, x.isSetDef1());
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestRenderedDoubleConstants.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestRenderedDoubleConstants.java
new file mode 100644
index 000000000..d691fe356
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestRenderedDoubleConstants.java
@@ -0,0 +1,179 @@
+/*
+ * 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.thrift;
+
+import java.util.List;
+import junit.framework.TestCase;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import thrift.test.DoubleConstantsTestConstants;
+
+public class TestRenderedDoubleConstants extends TestCase {
+ private static final double EPSILON = 0.0000001;
+ private static final String ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST =
+ "failed to verify a double constant generated by Thrift (expected = %f, got = %f)";
+ private static final String ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_LIST_TEST =
+ "failed to verify a list item by Thrift (expected = %f, got = %f)";
+ private static final String ASSERTION_MESSAGE_FOR_TYPE_CHECKS =
+ "the rendered variable with name %s is not of double type";
+
+ // to make sure lists containing doubles are generated correctly
+ public void testRenderedDoubleList() throws Exception {
+ final double[] EXPECTED_LIST =
+ {1d,-100d,100d,9223372036854775807d,-9223372036854775807d,3.14159265359,1000000.1,-1000000.1,1.7e+308,
+ -1.7e+308,9223372036854775816.43,-9223372036854775816.43};
+ assertEquals(EXPECTED_LIST.length, DoubleConstantsTestConstants.DOUBLE_LIST_TEST.size());
+ for (int i = 0; i < EXPECTED_LIST.length; ++i) {
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_LIST_TEST,
+ EXPECTED_LIST[i],
+ DoubleConstantsTestConstants.DOUBLE_LIST_TEST.get(i)),
+ EXPECTED_LIST[i], DoubleConstantsTestConstants.DOUBLE_LIST_TEST.get(i), EPSILON);
+ }
+ }
+
+ // to make sure the variables inside Thrift files are generated correctly
+ public void testRenderedDoubleConstants() throws Exception {
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1.0;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100.0;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807.0;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807.0;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308;
+ final double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43;
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, EPSILON);
+ assertEquals(
+ String.format(
+ ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+ EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST),
+ EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE,
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST, EPSILON);
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST));
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST));
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST));
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST));
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST));
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST));
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST));
+ //assertTrue(
+ // String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST"),
+ // Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST));
+ assertTrue(
+ String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST"),
+ Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST));
+ //assertTrue(
+ // String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST"),
+ // Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST));
+ assertTrue(
+ String.format(
+ ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST"),
+ Double.class.isInstance(
+ DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestReuse.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestReuse.java
new file mode 100644
index 000000000..b44abd0d2
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestReuse.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.thrift;
+
+import java.util.HashSet;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+
+import thrift.test.Reuse;
+
+// Tests reusing objects for deserialization.
+//
+public class TestReuse extends TestStruct {
+
+ public void testReuseObject() throws Exception {
+ TSerializer binarySerializer = new TSerializer(new TBinaryProtocol.Factory());
+ TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
+
+ Reuse ru1 = new Reuse();
+ HashSet<String> hs1 = new HashSet<String>();
+ byte[] serBytes;
+ String st1 = new String("string1");
+ String st2 = new String("string2");
+
+ ru1.setVal1(11);
+ ru1.setVal2(hs1);
+ ru1.addToVal2(st1);
+
+ serBytes = binarySerializer.serialize(ru1);
+
+ // update hash set after serialization
+ hs1.add(st2);
+
+ binaryDeserializer.deserialize(ru1, serBytes);
+
+ assertTrue( ru1.getVal2() == hs1 );
+ assertTrue( hs1.size() == 2 );
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestStruct.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestStruct.java
new file mode 100644
index 000000000..3379ed120
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestStruct.java
@@ -0,0 +1,396 @@
+/*
+ * 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.thrift;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.meta_data.FieldMetaData;
+import org.apache.thrift.meta_data.ListMetaData;
+import org.apache.thrift.meta_data.MapMetaData;
+import org.apache.thrift.meta_data.SetMetaData;
+import org.apache.thrift.meta_data.StructMetaData;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TType;
+
+import thrift.test.Bonk;
+import thrift.test.CrazyNesting;
+import thrift.test.HolyMoley;
+import thrift.test.Insanity;
+import thrift.test.JavaTestHelper;
+import thrift.test.Nesting;
+import thrift.test.Numberz;
+import thrift.test.OneOfEach;
+import thrift.test.StructA;
+import thrift.test.StructB;
+import thrift.test.Xtruct;
+
+public class TestStruct extends TestCase {
+ public void testIdentity() throws Exception {
+ TSerializer binarySerializer = new TSerializer(new TBinaryProtocol.Factory());
+ TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
+
+ OneOfEach ooe = Fixtures.oneOfEach;
+
+ Nesting n = new Nesting();
+ n.my_ooe = ooe;
+ n.my_ooe.integer16 = 16;
+ n.my_ooe.integer32 = 32;
+ n.my_ooe.integer64 = 64;
+ n.my_ooe.double_precision = (Math.sqrt(5)+1)/2;
+ n.my_ooe.some_characters = ":R (me going \"rrrr\")";
+ n.my_ooe.zomg_unicode = "\u04c0\u216e\u039d\u0020\u041d\u03bf\u217f"+
+ "\u043e\u0261\u0433\u0430\u03c1\u210e\u0020"+
+ "\u0391\u0074\u0074\u03b1\u217d\u03ba\u01c3"+
+ "\u203c";
+ n.my_bonk = Fixtures.nesting.my_bonk;
+
+ HolyMoley hm = Fixtures.holyMoley;
+
+ OneOfEach ooe2 = new OneOfEach();
+ binaryDeserializer.deserialize(
+ ooe2,
+ binarySerializer.serialize(ooe));
+
+ assertEquals(ooe, ooe2);
+ assertEquals(ooe.hashCode(), ooe2.hashCode());
+
+
+ Nesting n2 = new Nesting();
+ binaryDeserializer.deserialize(
+ n2,
+ binarySerializer.serialize(n));
+
+ assertEquals(n, n2);
+ assertEquals(n.hashCode(), n2.hashCode());
+
+ HolyMoley hm2 = new HolyMoley();
+ binaryDeserializer.deserialize(
+ hm2,
+ binarySerializer.serialize(hm));
+
+ assertEquals(hm, hm2);
+ assertEquals(hm.hashCode(), hm2.hashCode());
+ }
+
+ public void testDeepCopy() throws Exception {
+ TSerializer binarySerializer = new TSerializer(new TBinaryProtocol.Factory());
+ TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
+
+ HolyMoley hm = Fixtures.holyMoley;
+
+ byte[] binaryCopy = binarySerializer.serialize(hm);
+ HolyMoley hmCopy = new HolyMoley();
+ binaryDeserializer.deserialize(hmCopy, binaryCopy);
+ HolyMoley hmCopy2 = new HolyMoley(hm);
+
+ assertEquals(hm, hmCopy);
+ assertEquals(hmCopy, hmCopy2);
+
+ // change binary value in original object
+ hm.big.get(0).base64.array()[0]++;
+ // make sure the change didn't propagate to the copied object
+ assertFalse(hm.equals(hmCopy2));
+ hm.big.get(0).base64.array()[0]--; // undo change
+
+ hmCopy2.bonks.get("two").get(1).message = "What else?";
+
+ assertFalse(hm.equals(hmCopy2));
+ }
+
+ public void testCompareTo() throws Exception {
+ Bonk bonk1 = new Bonk();
+ Bonk bonk2 = new Bonk();
+
+ // Compare empty thrift objects.
+ assertEquals(0, bonk1.compareTo(bonk2));
+
+ bonk1.setMessage("m");
+
+ // Compare one thrift object with a filled in field and another without it.
+ assertTrue(bonk1.compareTo(bonk2) > 0);
+ assertTrue(bonk2.compareTo(bonk1) < 0);
+
+ // Compare both have filled-in fields.
+ bonk2.setMessage("z");
+ assertTrue(bonk1.compareTo(bonk2) < 0);
+ assertTrue(bonk2.compareTo(bonk1) > 0);
+
+ // Compare bonk1 has a field filled in that bonk2 doesn't.
+ bonk1.setType(123);
+ assertTrue(bonk1.compareTo(bonk2) > 0);
+ assertTrue(bonk2.compareTo(bonk1) < 0);
+
+ // Compare bonk1 and bonk2 equal.
+ bonk2.setType(123);
+ bonk2.setMessage("m");
+ assertEquals(0, bonk1.compareTo(bonk2));
+ }
+
+ public void testCompareToWithDataStructures() {
+ Insanity insanity1 = new Insanity();
+ Insanity insanity2 = new Insanity();
+
+ // Both empty.
+ expectEquals(insanity1, insanity2);
+
+ insanity1.setUserMap(new HashMap<Numberz, Long>());
+ // insanity1.map = {}, insanity2.map = null
+ expectGreaterThan(insanity1, insanity2);
+
+ // insanity1.map = {2:1}, insanity2.map = null
+ insanity1.getUserMap().put(Numberz.TWO, 1l);
+ expectGreaterThan(insanity1, insanity2);
+
+ // insanity1.map = {2:1}, insanity2.map = {}
+ insanity2.setUserMap(new HashMap<Numberz, Long>());
+ expectGreaterThan(insanity1, insanity2);
+
+ // insanity1.map = {2:1}, insanity2.map = {2:2}
+ insanity2.getUserMap().put(Numberz.TWO, 2l);
+ expectLessThan(insanity1, insanity2);
+
+ // insanity1.map = {2:1, 3:5}, insanity2.map = {2:2}
+ insanity1.getUserMap().put(Numberz.THREE, 5l);
+ expectGreaterThan(insanity1, insanity2);
+
+ // insanity1.map = {2:1, 3:5}, insanity2.map = {2:1, 4:5}
+ insanity2.getUserMap().put(Numberz.TWO, 1l);
+ insanity2.getUserMap().put(Numberz.FIVE, 5l);
+ expectLessThan(insanity1, insanity2);
+ }
+
+ private void expectLessThan(Insanity insanity1, Insanity insanity2) {
+ int compareTo = insanity1.compareTo(insanity2);
+ assertTrue(insanity1 + " should be less than " + insanity2 + ", but is: " + compareTo, compareTo < 0);
+ }
+
+ private void expectGreaterThan(Insanity insanity1, Insanity insanity2) {
+ int compareTo = insanity1.compareTo(insanity2);
+ assertTrue(insanity1 + " should be greater than " + insanity2 + ", but is: " + compareTo, compareTo > 0);
+ }
+
+ private void expectEquals(Insanity insanity1, Insanity insanity2) {
+ int compareTo = insanity1.compareTo(insanity2);
+ assertEquals(insanity1 + " should be equal to " + insanity2 + ", but is: " + compareTo, 0, compareTo);
+ }
+
+ public void testMetaData() throws Exception {
+ Map<CrazyNesting._Fields, FieldMetaData> mdMap = CrazyNesting.metaDataMap;
+
+ // Check for struct fields existence
+ assertEquals(4, mdMap.size());
+ assertTrue(mdMap.containsKey(CrazyNesting._Fields.SET_FIELD));
+ assertTrue(mdMap.containsKey(CrazyNesting._Fields.LIST_FIELD));
+ assertTrue(mdMap.containsKey(CrazyNesting._Fields.STRING_FIELD));
+ assertTrue(mdMap.containsKey(CrazyNesting._Fields.BINARY_FIELD));
+
+ // Check for struct fields contents
+ assertEquals("string_field", mdMap.get(CrazyNesting._Fields.STRING_FIELD).fieldName);
+ assertEquals("list_field", mdMap.get(CrazyNesting._Fields.LIST_FIELD).fieldName);
+ assertEquals("set_field", mdMap.get(CrazyNesting._Fields.SET_FIELD).fieldName);
+ assertEquals("binary_field", mdMap.get(CrazyNesting._Fields.BINARY_FIELD).fieldName);
+
+ assertEquals(TFieldRequirementType.DEFAULT, mdMap.get(CrazyNesting._Fields.STRING_FIELD).requirementType);
+ assertEquals(TFieldRequirementType.REQUIRED, mdMap.get(CrazyNesting._Fields.LIST_FIELD).requirementType);
+ assertEquals(TFieldRequirementType.OPTIONAL, mdMap.get(CrazyNesting._Fields.SET_FIELD).requirementType);
+
+ assertEquals(TType.STRING, mdMap.get(CrazyNesting._Fields.STRING_FIELD).valueMetaData.type);
+ assertFalse(mdMap.get(CrazyNesting._Fields.STRING_FIELD).valueMetaData.isBinary());
+ assertEquals(TType.LIST, mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData.type);
+ assertEquals(TType.SET, mdMap.get(CrazyNesting._Fields.SET_FIELD).valueMetaData.type);
+ assertEquals(TType.STRING, mdMap.get(CrazyNesting._Fields.BINARY_FIELD).valueMetaData.type);
+ assertTrue(mdMap.get(CrazyNesting._Fields.BINARY_FIELD).valueMetaData.isBinary());
+
+ // Check nested structures
+ assertTrue(mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData.isContainer());
+
+ assertFalse(mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData.isStruct());
+
+ assertEquals(TType.STRUCT, ((MapMetaData)((ListMetaData)((SetMetaData)((MapMetaData)((MapMetaData)((ListMetaData)mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData).elemMetaData).valueMetaData).valueMetaData).elemMetaData).elemMetaData).keyMetaData.type);
+
+ assertEquals(Insanity.class, ((StructMetaData)((MapMetaData)((ListMetaData)((SetMetaData)((MapMetaData)((MapMetaData)((ListMetaData)mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData).elemMetaData).valueMetaData).valueMetaData).elemMetaData).elemMetaData).keyMetaData).structClass);
+
+ // Check that FieldMetaData contains a map with metadata for all generated struct classes
+ assertNotNull(FieldMetaData.getStructMetaDataMap(CrazyNesting.class));
+ assertNotNull(FieldMetaData.getStructMetaDataMap(Insanity.class));
+ assertNotNull(FieldMetaData.getStructMetaDataMap(Xtruct.class));
+
+ assertEquals(CrazyNesting.metaDataMap, FieldMetaData.getStructMetaDataMap(CrazyNesting.class));
+ assertEquals(Insanity.metaDataMap, FieldMetaData.getStructMetaDataMap(Insanity.class));
+
+ for (Map.Entry<? extends TFieldIdEnum, FieldMetaData> mdEntry : mdMap.entrySet()) {
+ assertEquals(mdEntry.getKey(), CrazyNesting._Fields.findByName(mdEntry.getValue().fieldName));
+ }
+
+ MapMetaData vmd = (MapMetaData)Insanity.metaDataMap.get(Insanity._Fields.USER_MAP).valueMetaData;
+ assertTrue(vmd.valueMetaData.isTypedef());
+ assertFalse(vmd.keyMetaData.isTypedef());
+ }
+
+ public void testToString() throws Exception {
+ JavaTestHelper object = new JavaTestHelper();
+ object.req_int = 0;
+ object.req_obj = "";
+
+ object.req_bin = ByteBuffer.wrap(new byte[] {
+ 0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15,
+ 16, -17, 18, -19, 20, -21, 22, -23, 24, -25, 26, -27, 28, -29,
+ 30, -31, 32, -33, 34, -35, 36, -37, 38, -39, 40, -41, 42, -43, 44,
+ -45, 46, -47, 48, -49, 50, -51, 52, -53, 54, -55, 56, -57, 58, -59,
+ 60, -61, 62, -63, 64, -65, 66, -67, 68, -69, 70, -71, 72, -73, 74,
+ -75, 76, -77, 78, -79, 80, -81, 82, -83, 84, -85, 86, -87, 88, -89,
+ 90, -91, 92, -93, 94, -95, 96, -97, 98, -99, 100, -101, 102, -103,
+ 104, -105, 106, -107, 108, -109, 110, -111, 112, -113, 114, -115,
+ 116, -117, 118, -119, 120, -121, 122, -123, 124, -125, 126, -127,
+ });
+
+ assertEquals("JavaTestHelper(req_int:0, req_obj:, req_bin:"+
+ "00 FF 02 FD 04 FB 06 F9 08 F7 0A F5 0C F3 0E F1 10 EF 12 ED 14 "+
+ "EB 16 E9 18 E7 1A E5 1C E3 1E E1 20 DF 22 DD 24 DB 26 D9 28 D7 "+
+ "2A D5 2C D3 2E D1 30 CF 32 CD 34 CB 36 C9 38 C7 3A C5 3C C3 3E "+
+ "C1 40 BF 42 BD 44 BB 46 B9 48 B7 4A B5 4C B3 4E B1 50 AF 52 AD "+
+ "54 AB 56 A9 58 A7 5A A5 5C A3 5E A1 60 9F 62 9D 64 9B 66 99 68 "+
+ "97 6A 95 6C 93 6E 91 70 8F 72 8D 74 8B 76 89 78 87 7A 85 7C 83 "+
+ "7E 81)",
+ object.toString());
+
+ object.req_bin = ByteBuffer.wrap(new byte[] {
+ 0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15,
+ 16, -17, 18, -19, 20, -21, 22, -23, 24, -25, 26, -27, 28, -29,
+ 30, -31, 32, -33, 34, -35, 36, -37, 38, -39, 40, -41, 42, -43, 44,
+ -45, 46, -47, 48, -49, 50, -51, 52, -53, 54, -55, 56, -57, 58, -59,
+ 60, -61, 62, -63, 64, -65, 66, -67, 68, -69, 70, -71, 72, -73, 74,
+ -75, 76, -77, 78, -79, 80, -81, 82, -83, 84, -85, 86, -87, 88, -89,
+ 90, -91, 92, -93, 94, -95, 96, -97, 98, -99, 100, -101, 102, -103,
+ 104, -105, 106, -107, 108, -109, 110, -111, 112, -113, 114, -115,
+ 116, -117, 118, -119, 120, -121, 122, -123, 124, -125, 126, -127,
+ 0,
+ });
+
+ assertEquals("JavaTestHelper(req_int:0, req_obj:, req_bin:"+
+ "00 FF 02 FD 04 FB 06 F9 08 F7 0A F5 0C F3 0E F1 10 EF 12 ED 14 "+
+ "EB 16 E9 18 E7 1A E5 1C E3 1E E1 20 DF 22 DD 24 DB 26 D9 28 D7 "+
+ "2A D5 2C D3 2E D1 30 CF 32 CD 34 CB 36 C9 38 C7 3A C5 3C C3 3E "+
+ "C1 40 BF 42 BD 44 BB 46 B9 48 B7 4A B5 4C B3 4E B1 50 AF 52 AD "+
+ "54 AB 56 A9 58 A7 5A A5 5C A3 5E A1 60 9F 62 9D 64 9B 66 99 68 "+
+ "97 6A 95 6C 93 6E 91 70 8F 72 8D 74 8B 76 89 78 87 7A 85 7C 83 "+
+ "7E 81...)",
+ object.toString());
+
+ object.req_bin = ByteBuffer.wrap(new byte[] {});
+ object.setOpt_binIsSet(true);
+
+ assertEquals("JavaTestHelper(req_int:0, req_obj:, req_bin:)",
+ object.toString());
+ }
+
+ private static void assertArrayEquals(byte[] expected, byte[] actual) {
+ if (!java.util.Arrays.equals(expected, actual)) {
+ fail("Expected byte array did not match actual.");
+ }
+ }
+
+ public void testBytesBufferFeatures() throws Exception {
+
+ final String testString = "testBytesBufferFeatures";
+ final JavaTestHelper o = new JavaTestHelper();
+
+ o.setReq_bin((ByteBuffer)null);
+ assertNull(o.getReq_bin());
+
+ o.setReq_bin(ByteBuffer.wrap(testString.getBytes()));
+ assertArrayEquals(testString.getBytes(), o.getReq_bin());
+
+ o.setReq_bin((byte[])null);
+ assertNull(o.getReq_bin());
+
+ o.setReq_bin(testString.getBytes());
+ assertArrayEquals(testString.getBytes(), o.getReq_bin());
+
+ o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, null);
+ assertNull(o.getReq_bin());
+
+ o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, testString.getBytes());
+ assertArrayEquals(testString.getBytes(), o.getReq_bin());
+
+ o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, null);
+ assertNull(o.getReq_bin());
+
+ o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, ByteBuffer.wrap(testString.getBytes()));
+ assertArrayEquals(testString.getBytes(), o.getReq_bin());
+ }
+
+ public void testJavaSerializable() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+
+ OneOfEach ooe = Fixtures.oneOfEach;
+
+ // Serialize ooe the Java way...
+ oos.writeObject(ooe);
+ byte[] serialized = baos.toByteArray();
+
+ // Attempt to deserialize it
+ ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ OneOfEach ooe2 = (OneOfEach) ois.readObject();
+
+ assertEquals(ooe, ooe2);
+ }
+
+ public void testSubStructValidation() throws Exception {
+ StructA valid = new StructA("valid");
+ StructA invalid = new StructA();
+
+ StructB b = new StructB();
+ try {
+ b.validate();
+ fail();
+ } catch (TException e) {
+ // expected
+ }
+
+ b = new StructB().setAb(valid);
+ b.validate();
+
+ b = new StructB().setAb(invalid);
+ try {
+ b.validate();
+ fail();
+ } catch (TException e) {
+ // expected
+ }
+
+ b = new StructB().setAb(valid).setAa(invalid);
+ try {
+ b.validate();
+ fail();
+ } catch (TException e) {
+ // expected
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTBaseHelper.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTBaseHelper.java
new file mode 100644
index 000000000..8b0855525
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTBaseHelper.java
@@ -0,0 +1,209 @@
+/*
+ * 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.thrift;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+public class TestTBaseHelper extends TestCase {
+ public void testByteArrayComparison() {
+ assertTrue(TBaseHelper.compareTo(new byte[]{'a','b'}, new byte[]{'a','c'}) < 0);
+ }
+
+ public void testSets() {
+ Set<String> a = new HashSet<String>();
+ Set<String> b = new HashSet<String>();
+
+ assertTrue(TBaseHelper.compareTo(a, b) == 0);
+
+ a.add("test");
+
+ assertTrue(TBaseHelper.compareTo(a, b) > 0);
+
+ b.add("test");
+
+ assertTrue(TBaseHelper.compareTo(a, b) == 0);
+
+ b.add("aardvark");
+
+ assertTrue(TBaseHelper.compareTo(a, b) < 0);
+
+ a.add("test2");
+
+ assertTrue(TBaseHelper.compareTo(a, b) > 0);
+ }
+
+ public void testNestedStructures() {
+ Set<List<String>> a = new HashSet<List<String>>();
+ Set<List<String>> b = new HashSet<List<String>>();
+
+ a.add(Arrays.asList(new String[] {"a","b"}));
+ b.add(Arrays.asList(new String[] {"a","b", "c"}));
+ a.add(Arrays.asList(new String[] {"a","b"}));
+ b.add(Arrays.asList(new String[] {"a","b", "c"}));
+
+ assertTrue(TBaseHelper.compareTo(a, b) < 0);
+ }
+
+ public void testMapsInSets() {
+ Set<Map<String, Long>> a = new HashSet<Map<String, Long>>();
+ Set<Map<String, Long>> b = new HashSet<Map<String, Long>>();
+
+ assertTrue(TBaseHelper.compareTo(a, b) == 0);
+
+ Map<String, Long> innerA = new HashMap<String, Long>();
+ Map<String, Long> innerB = new HashMap<String, Long>();
+ a.add(innerA);
+ b.add(innerB);
+
+ innerA.put("a", 1l);
+ innerB.put("a", 2l);
+
+ assertTrue(TBaseHelper.compareTo(a, b) < 0);
+ }
+
+ public void testByteArraysInMaps() {
+ Map<byte[], Long> a = new HashMap<byte[], Long>();
+ Map<byte[], Long> b = new HashMap<byte[], Long>();
+
+ assertTrue(TBaseHelper.compareTo(a, b) == 0);
+
+ a.put(new byte[]{'a','b'}, 1000L);
+ b.put(new byte[]{'a','b'}, 1000L);
+ a.put(new byte[]{'a','b', 'd'}, 1000L);
+ b.put(new byte[]{'a','b', 'a'}, 1000L);
+ assertTrue(TBaseHelper.compareTo(a, b) > 0);
+ }
+
+ public void testMapsWithNulls() {
+ Map<String, String> a = new HashMap<String, String>();
+ Map<String, String> b = new HashMap<String, String>();
+ a.put("a", null);
+ a.put("b", null);
+ b.put("a", null);
+ b.put("b", null);
+
+ assertTrue(TBaseHelper.compareTo(a, b) == 0);
+ }
+
+ public void testMapKeyComparison() {
+ Map<String, String> a = new HashMap<String, String>();
+ Map<String, String> b = new HashMap<String, String>();
+ a.put("a", "a");
+ b.put("b", "a");
+
+ assertTrue(TBaseHelper.compareTo(a, b) < 0);
+ }
+
+ public void testMapValueComparison() {
+ Map<String, String> a = new HashMap<String, String>();
+ Map<String, String> b = new HashMap<String, String>();
+ a.put("a", "b");
+ b.put("a", "a");
+
+ assertTrue(TBaseHelper.compareTo(a, b) > 0);
+ }
+
+ public void testByteArraysInSets() {
+ Set<byte[]> a = new HashSet<byte[]>();
+ Set<byte[]> b = new HashSet<byte[]>();
+
+ if (TBaseHelper.compareTo(a, b) != 0)
+ throw new RuntimeException("Set compare failed:" + a + " vs. " + b);
+
+ a.add(new byte[]{'a','b'});
+ b.add(new byte[]{'a','b'});
+ a.add(new byte[]{'a','b', 'd'});
+ b.add(new byte[]{'a','b', 'a'});
+ assertTrue(TBaseHelper.compareTo(a, b) > 0);
+ }
+
+ public void testByteBufferToByteArray() throws Exception {
+ byte[] b1 = {10,9,8,7,6,5,4,3,2,1,0};
+ byte[] b2 = TBaseHelper.byteBufferToByteArray(ByteBuffer.wrap(b1));
+ assertEquals("b1 and b2 should be the exact same array (identity) due to fast path", b1, b2);
+
+ byte[] b3 = TBaseHelper.byteBufferToByteArray(ByteBuffer.wrap(b1, 1, 3));
+ assertEquals(3, b3.length);
+ assertEquals(ByteBuffer.wrap(b1, 1, 3), ByteBuffer.wrap(b3));
+ }
+
+ public void testRightSize() throws Exception {
+ assertNull(TBaseHelper.rightSize(null));
+ }
+
+ public void testByteBufferToString() {
+ byte[] array = new byte[]{1, 2, 3};
+ ByteBuffer bb = ByteBuffer.wrap(array, 1, 2);
+ StringBuilder sb = new StringBuilder();
+ TBaseHelper.toString(bb, sb);
+ assertEquals("02 03", sb.toString());
+ bb = ByteBuffer.wrap(array, 0, array.length);
+ bb.position(1);
+ bb = bb.slice();
+ assertEquals(1, bb.arrayOffset());
+ assertEquals(0, bb.position());
+ assertEquals(2, bb.limit());
+ sb = new StringBuilder();
+ TBaseHelper.toString(bb, sb);
+ assertEquals("02 03", sb.toString());
+ }
+
+ public void testCopyBinaryWithByteBuffer() throws Exception {
+ byte[] bytes = new byte[]{0, 1, 2, 3, 4, 5};
+ ByteBuffer b = ByteBuffer.wrap(bytes);
+ ByteBuffer bCopy = TBaseHelper.copyBinary(b);
+ assertEquals(b, bCopy);
+ assertEquals(0, b.position());
+
+ b = ByteBuffer.allocateDirect(6);
+ b.put(bytes);
+ b.position(0);
+ bCopy = TBaseHelper.copyBinary(b);
+ assertEquals(6, b.remaining());
+ assertEquals(0, b.position());
+ assertEquals(b, bCopy);
+
+ b.mark();
+ b.get();
+ bCopy = TBaseHelper.copyBinary(b);
+ assertEquals(ByteBuffer.wrap(bytes, 1, 5), bCopy);
+ assertEquals(1, b.position());
+ b.reset();
+ assertEquals(0, b.position());
+
+ assertNull(TBaseHelper.copyBinary((ByteBuffer)null));
+ }
+
+ public void testCopyBinaryWithByteArray() throws Exception {
+ byte[] bytes = new byte[]{0, 1, 2, 3, 4, 5};
+ byte[] copy = TBaseHelper.copyBinary(bytes);
+ assertEquals(ByteBuffer.wrap(bytes), ByteBuffer.wrap(copy));
+ assertNotSame(bytes, copy);
+
+ assertNull(TBaseHelper.copyBinary((byte[])null));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTDeserializer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTDeserializer.java
new file mode 100644
index 000000000..a4a353d6c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTDeserializer.java
@@ -0,0 +1,126 @@
+/*
+ * 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.thrift;
+
+import java.nio.ByteBuffer;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+
+import thrift.test.Backwards;
+import thrift.test.OneOfEach;
+import thrift.test.PrimitiveThenStruct;
+import thrift.test.StructWithAUnion;
+import thrift.test.TestUnion;
+
+public class TestTDeserializer extends TestCase {
+
+ private static final TProtocolFactory[] PROTOCOLS = new TProtocolFactory[] {
+ new TBinaryProtocol.Factory(),
+ new TCompactProtocol.Factory(),
+ new TJSONProtocol.Factory()
+ };
+
+ public void testPartialDeserialize() throws Exception {
+ //Root:StructWithAUnion
+ // 1:Union
+ // 1.3:OneOfEach
+ OneOfEach level3OneOfEach = Fixtures.oneOfEach;
+ TestUnion level2TestUnion = new TestUnion(TestUnion._Fields.STRUCT_FIELD, level3OneOfEach);
+ StructWithAUnion level1SWU = new StructWithAUnion(level2TestUnion);
+
+ Backwards bw = new Backwards(2, 1);
+ PrimitiveThenStruct pts = new PrimitiveThenStruct(12345, 67890, bw);
+
+ for (TProtocolFactory factory : PROTOCOLS) {
+
+ //Level 2 test
+ testPartialDeserialize(factory, level1SWU, new TestUnion(), level2TestUnion, StructWithAUnion._Fields.TEST_UNION);
+
+ //Level 3 on 3rd field test
+ testPartialDeserialize(factory, level1SWU, new OneOfEach(), level3OneOfEach, StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD);
+
+ //Test early termination when traversed path Field.id exceeds the one being searched for
+ testPartialDeserialize(factory, level1SWU, new OneOfEach(), new OneOfEach(), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.I32_FIELD);
+
+ //Test that readStructBegin isn't called on primitive
+ testPartialDeserialize(factory, pts, new Backwards(), bw, PrimitiveThenStruct._Fields.BW);
+
+ //Test primitive types
+ TDeserializer deserializer = new TDeserializer(factory);
+
+ Boolean expectedBool = level3OneOfEach.isIm_true();
+ Boolean resultBool = deserializer.partialDeserializeBool(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.IM_TRUE);
+ assertEquals(expectedBool, resultBool);
+
+ Byte expectedByte = level3OneOfEach.getA_bite();
+ Byte resultByte = deserializer.partialDeserializeByte(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.A_BITE);
+ assertEquals(expectedByte, resultByte);
+
+ Double expectedDouble = level3OneOfEach.getDouble_precision();
+ Double resultDouble = deserializer.partialDeserializeDouble(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.DOUBLE_PRECISION);
+ assertEquals(expectedDouble, resultDouble);
+
+ Short expectedI16 = level3OneOfEach.getInteger16();
+ Short resultI16 = deserializer.partialDeserializeI16(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.INTEGER16);
+ assertEquals(expectedI16, resultI16);
+
+ Integer expectedI32 = level3OneOfEach.getInteger32();
+ Integer resultI32 = deserializer.partialDeserializeI32(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.INTEGER32);
+ assertEquals(expectedI32, resultI32);
+
+ Long expectedI64 = level3OneOfEach.getInteger64();
+ Long resultI64= deserializer.partialDeserializeI64(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.INTEGER64);
+ assertEquals(expectedI64, resultI64);
+
+ String expectedString = level3OneOfEach.getSome_characters();
+ String resultString = deserializer.partialDeserializeString(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.SOME_CHARACTERS);
+ assertEquals(expectedString, resultString);
+
+ byte[] expectedBinary = level3OneOfEach.getBase64();
+ ByteBuffer resultBinary = deserializer.partialDeserializeByteArray(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION, TestUnion._Fields.STRUCT_FIELD, OneOfEach._Fields.BASE64);
+ assertEquals(expectedBinary.length, resultBinary.limit() - resultBinary.position() - resultBinary.arrayOffset());
+ assertEquals(ByteBuffer.wrap(expectedBinary), resultBinary);
+
+ // Test field id in Union
+ short id = deserializer.partialDeserializeSetFieldIdInUnion(serialize(level1SWU, factory), StructWithAUnion._Fields.TEST_UNION);
+ assertEquals(level2TestUnion.getSetField().getThriftFieldId(), id);
+ }
+ }
+
+ public static void testPartialDeserialize(TProtocolFactory protocolFactory, TBase input, TBase output, TBase expected, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
+ byte[] record = serialize(input, protocolFactory);
+ TDeserializer deserializer = new TDeserializer(protocolFactory);
+ for (int i = 0; i < 2; i++) {
+ TBase outputCopy = output.deepCopy();
+ deserializer.partialDeserialize(outputCopy, record, fieldIdPathFirst, fieldIdPathRest);
+ assertEquals("on attempt " + i + ", with " + protocolFactory.toString()
+ + ", expected " + expected + " but got " + outputCopy,
+ expected, outputCopy);
+ }
+ }
+
+ private static byte[] serialize(TBase input, TProtocolFactory protocolFactory) throws TException{
+ return new TSerializer(protocolFactory).serialize(input);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTEnumHelper.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTEnumHelper.java
new file mode 100644
index 000000000..e2cca4039
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTEnumHelper.java
@@ -0,0 +1,41 @@
+/*
+ * 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.thrift;
+
+import thrift.test.Numberz;
+
+import junit.framework.TestCase;
+
+public class TestTEnumHelper extends TestCase {
+
+ public void testGetByValue_ValidValues() {
+ for (Numberz n: Numberz.values()) {
+ int value = n.getValue();
+ assertEquals(n, TEnumHelper.getByValue(Numberz.class, value));
+ }
+ }
+
+ public void testGetByValue_InvalidValue() {
+ assertEquals(null, TEnumHelper.getByValue(Numberz.class, 0));
+ }
+
+ public void testGetByValue_InvalidClass() {
+ assertEquals(null, TEnumHelper.getByValue(TEnum.class, 0));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTUnion.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTUnion.java
new file mode 100644
index 000000000..f1e6f0e1f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestTUnion.java
@@ -0,0 +1,268 @@
+/*
+ * 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.thrift;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TTupleProtocol;
+import org.apache.thrift.transport.TMemoryBuffer;
+
+import thrift.test.ComparableUnion;
+import thrift.test.Empty;
+import thrift.test.RandomStuff;
+import thrift.test.SomeEnum;
+import thrift.test.StructWithAUnion;
+import thrift.test.TestUnion;
+import thrift.test.TestUnionMinusStringField;
+
+public class TestTUnion extends TestCase {
+
+ public void testBasic() throws Exception {
+ TestUnion union = new TestUnion();
+
+ assertFalse(union.isSet());
+ assertFalse(union.isSetI32_field());
+ assertNull(union.getFieldValue());
+
+ union = new TestUnion(TestUnion._Fields.I32_FIELD, 25);
+
+ assertEquals(Integer.valueOf(25), union.getFieldValue());
+
+ assertEquals(Integer.valueOf(25), union.getFieldValue(TestUnion._Fields.I32_FIELD));
+
+ assertTrue(union.isSetI32_field());
+
+ try {
+ union.getFieldValue(TestUnion._Fields.STRING_FIELD);
+ fail("should have thrown an exception");
+ } catch (IllegalArgumentException e) {
+ // cool!
+ }
+
+ union = new TestUnion();
+
+ // should not throw an exception here
+ union.hashCode();
+
+ union.setI32_field(1);
+ assertEquals(1, union.getI32_field());
+ union.hashCode();
+
+ assertFalse(union.isSetString_field());
+
+ try {
+ union.getString_field();
+ fail("should have thrown an exception");
+ } catch (Exception e) {
+ // sweet
+ }
+
+ union = TestUnion.i32_field(1);
+
+ assertFalse(union.equals((TestUnion)null));
+
+ union = TestUnion.enum_field(SomeEnum.ONE);
+ union.hashCode();
+
+ union = new TestUnion();
+ // should not throw an exception
+ union.toString();
+ }
+
+ public void testCompareTo() throws Exception {
+ ComparableUnion cu = ComparableUnion.string_field("a");
+ ComparableUnion cu2 = ComparableUnion.string_field("b");
+
+ assertTrue(cu.compareTo(cu) == 0);
+ assertTrue(cu2.compareTo(cu2) == 0);
+
+ assertTrue(cu.compareTo(cu2) < 0);
+ assertTrue(cu2.compareTo(cu) > 0);
+
+ cu2 = ComparableUnion.binary_field(ByteBuffer.wrap(new byte[]{2}));
+
+ assertTrue(cu.compareTo(cu2) < 0);
+ assertTrue(cu2.compareTo(cu) > 0);
+
+ cu = ComparableUnion.binary_field(ByteBuffer.wrap(new byte[]{1}));
+
+ assertTrue(cu.compareTo(cu2) < 0);
+ assertTrue(cu2.compareTo(cu) > 0);
+
+ TestUnion union1 = new TestUnion(TestUnion._Fields.STRUCT_LIST, new ArrayList<RandomStuff>());
+ TestUnion union2 = new TestUnion(TestUnion._Fields.STRUCT_LIST, new ArrayList<RandomStuff>());
+ assertTrue(union1.compareTo(union2) == 0);
+
+ TestUnion union3 = new TestUnion(TestUnion._Fields.I32_SET, new HashSet<Integer>());
+ Set<Integer> i32_set = new HashSet<Integer>();
+ i32_set.add(1);
+ TestUnion union4 = new TestUnion(TestUnion._Fields.I32_SET, i32_set);
+ assertTrue(union3.compareTo(union4) < 0);
+
+ Map<Integer, Integer> i32_map = new HashMap<Integer, Integer>();
+ i32_map.put(1,1);
+ TestUnion union5 = new TestUnion(TestUnion._Fields.I32_MAP, i32_map);
+ TestUnion union6 = new TestUnion(TestUnion._Fields.I32_MAP, new HashMap<Integer, Integer>());
+ assertTrue(union5.compareTo(union6) > 0);
+ }
+
+ public void testEquality() throws Exception {
+ TestUnion union = new TestUnion(TestUnion._Fields.I32_FIELD, 25);
+
+ TestUnion otherUnion = new TestUnion(TestUnion._Fields.STRING_FIELD, "blah!!!");
+
+ assertFalse(union.equals(otherUnion));
+
+ otherUnion = new TestUnion(TestUnion._Fields.I32_FIELD, 400);
+
+ assertFalse(union.equals(otherUnion));
+
+ otherUnion = new TestUnion(TestUnion._Fields.OTHER_I32_FIELD, 25);
+
+ assertFalse(union.equals(otherUnion));
+ }
+
+ public void testSerialization() throws Exception {
+ TestUnion union = new TestUnion(TestUnion._Fields.I32_FIELD, 25);
+ union.setI32_set(Collections.singleton(42));
+
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = new TBinaryProtocol(buf);
+
+ union.write(proto);
+
+ TestUnion u2 = new TestUnion();
+
+ u2.read(proto);
+
+ assertEquals(u2, union);
+
+ StructWithAUnion swau = new StructWithAUnion(u2);
+
+ buf = new TMemoryBuffer(0);
+ proto = new TBinaryProtocol(buf);
+
+ swau.write(proto);
+
+ StructWithAUnion swau2 = new StructWithAUnion();
+ assertFalse(swau2.equals(swau));
+ swau2.read(proto);
+ assertEquals(swau2, swau);
+
+ // this should NOT throw an exception.
+ buf = new TMemoryBuffer(0);
+ proto = new TBinaryProtocol(buf);
+
+ swau.write(proto);
+ new Empty().read(proto);
+ }
+
+ public void testTupleProtocolSerialization () throws Exception {
+ TestUnion union = new TestUnion(TestUnion._Fields.I32_FIELD, 25);
+ union.setI32_set(Collections.singleton(42));
+
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = new TTupleProtocol(buf);
+
+ union.write(proto);
+
+ TestUnion u2 = new TestUnion();
+
+ u2.read(proto);
+
+ assertEquals(u2, union);
+
+ StructWithAUnion swau = new StructWithAUnion(u2);
+
+ buf = new TMemoryBuffer(0);
+ proto = new TBinaryProtocol(buf);
+
+ swau.write(proto);
+
+ StructWithAUnion swau2 = new StructWithAUnion();
+ assertFalse(swau2.equals(swau));
+ swau2.read(proto);
+ assertEquals(swau2, swau);
+
+ // this should NOT throw an exception.
+ buf = new TMemoryBuffer(0);
+ proto = new TTupleProtocol(buf);
+
+ swau.write(proto);
+ new Empty().read(proto);
+ }
+
+ public void testSkip() throws Exception {
+ TestUnion tu = TestUnion.string_field("string");
+ byte[] tuSerialized = new TSerializer().serialize(tu);
+ TestUnionMinusStringField tums = new TestUnionMinusStringField();
+ new TDeserializer().deserialize(tums, tuSerialized);
+ assertNull(tums.getSetField());
+ assertNull(tums.getFieldValue());
+ }
+
+ public void testDeepCopy() throws Exception {
+ byte[] bytes = {1, 2, 3};
+ ByteBuffer value = ByteBuffer.wrap(bytes);
+ ComparableUnion cu = ComparableUnion.binary_field(value);
+ ComparableUnion copy = cu.deepCopy();
+ assertEquals(cu, copy);
+ assertNotSame(cu.bufferForBinary_field().array(), copy.bufferForBinary_field().array());
+ }
+
+ public void testToString() throws Exception {
+ byte[] bytes = {1, 2, 3};
+ ByteBuffer value = ByteBuffer.wrap(bytes);
+ ComparableUnion cu = ComparableUnion.binary_field(value);
+ String expectedString = "<ComparableUnion binary_field:01 02 03>";
+ assertEquals(expectedString, cu.toString());
+ }
+
+ public void testJavaSerializable() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+
+ TestUnion tu = TestUnion.string_field("string");
+
+ // Serialize tu the Java way...
+ oos.writeObject(tu);
+ byte[] serialized = baos.toByteArray();
+
+ // Attempt to deserialize it
+ ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ TestUnion tu2 = (TestUnion) ois.readObject();
+
+ assertEquals(tu, tu2);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestUnsafeBinaries.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestUnsafeBinaries.java
new file mode 100644
index 000000000..d1fc21368
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/TestUnsafeBinaries.java
@@ -0,0 +1,146 @@
+/*
+ * 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.thrift;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import thrift.test.SafeBytes;
+import thrift.test.UnsafeBytes;
+
+// test generating types with un-copied byte[]/ByteBuffer input/output
+//
+public class TestUnsafeBinaries extends TestStruct {
+
+ private static byte[] input() {
+ return new byte[]{1, 1};
+ }
+
+ //
+ // verify that the unsafe_binaries option modifies behavior
+ //
+
+ // constructor doesn't copy
+ public void testUnsafeConstructor() throws Exception {
+
+ byte[] input = input();
+ UnsafeBytes struct = new UnsafeBytes(ByteBuffer.wrap(input));
+
+ input[0] = 2;
+
+ assertTrue(Arrays.equals(
+ new byte[]{2, 1},
+ struct.getBytes())
+ );
+
+ }
+
+ // getter doesn't copy
+ // note: this behavior is the same with/without the flag, but if this default ever changes, the current behavior
+ // should be retained when using this flag
+ public void testUnsafeGetter(){
+ UnsafeBytes struct = new UnsafeBytes(ByteBuffer.wrap(input()));
+
+ byte[] val = struct.getBytes();
+ val[0] = 2;
+
+ assertTrue(Arrays.equals(
+ new byte[]{2, 1},
+ struct.getBytes())
+ );
+
+ }
+
+ // setter doesn't copy
+ public void testUnsafeSetter(){
+ UnsafeBytes struct = new UnsafeBytes();
+
+ byte[] val = input();
+ struct.setBytes(val);
+
+ val[0] = 2;
+
+ assertTrue(Arrays.equals(
+ new byte[]{2, 1},
+ struct.getBytes())
+ );
+
+ }
+
+ // buffer doens't copy
+ public void testUnsafeBufferFor(){
+ UnsafeBytes struct = new UnsafeBytes(ByteBuffer.wrap(input()));
+
+ ByteBuffer val = struct.bufferForBytes();
+ val.array()[0] = 2;
+
+ assertTrue(Arrays.equals(
+ new byte[]{2, 1},
+ struct.getBytes())
+ );
+
+ }
+
+ //
+ // verify that the default generator does not change behavior
+ //
+
+ public void testSafeConstructor() {
+
+ byte[] input = input();
+ SafeBytes struct = new SafeBytes(ByteBuffer.wrap(input));
+
+ input[0] = 2;
+
+ assertTrue(Arrays.equals(
+ new byte[]{1, 1},
+ struct.getBytes())
+ );
+
+ }
+
+ public void testSafeSetter() {
+
+ byte[] input = input();
+ SafeBytes struct = new SafeBytes(ByteBuffer.wrap(input));
+
+ input[0] = 2;
+
+ assertTrue(Arrays.equals(
+ new byte[]{1, 1},
+ struct.getBytes())
+ );
+
+ }
+
+ public void testSafeBufferFor(){
+ SafeBytes struct = new SafeBytes(ByteBuffer.wrap(input()));
+
+ ByteBuffer val = struct.bufferForBytes();
+ val.array()[0] = 2;
+
+ assertTrue(Arrays.equals(
+ new byte[]{1, 1},
+ struct.getBytes())
+ );
+
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClient.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClient.java
new file mode 100644
index 000000000..392ca22d4
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClient.java
@@ -0,0 +1,28 @@
+package org.apache.thrift.async;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.TException;
+
+import thrift.test.Srv;
+import thrift.test.Srv.AsyncClient;
+
+public class TestTAsyncClient extends TestCase {
+ public void testRaisesExceptionWhenUsedConcurrently() throws Exception {
+ TAsyncClientManager mockClientManager = new TAsyncClientManager() {
+ @Override
+ public void call(TAsyncMethodCall method) throws TException {
+ // do nothing
+ }
+ };
+
+ Srv.AsyncClient c = new AsyncClient(null, mockClientManager, null);
+ c.Janky(0, null);
+ try {
+ c.checkReady();
+ fail("should have hit an exception");
+ } catch (Exception e) {
+ // awesome
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java
new file mode 100644
index 000000000..c483cf24e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java
@@ -0,0 +1,378 @@
+/*
+ * 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.thrift.async;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.server.ServerTestBase;
+import org.apache.thrift.server.THsHaServer;
+import org.apache.thrift.server.THsHaServer.Args;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+import org.apache.thrift.transport.TNonblockingSocket;
+
+import thrift.test.CompactProtoTestStruct;
+import thrift.test.ExceptionWithAMap;
+import thrift.test.Srv;
+import thrift.test.Srv.Iface;
+
+public class TestTAsyncClientManager extends TestCase {
+
+ private THsHaServer server_;
+ private Thread serverThread_;
+ private TAsyncClientManager clientManager_;
+
+ public void setUp() throws Exception {
+ server_ = new THsHaServer(new Args(new TNonblockingServerSocket(
+ new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(ServerTestBase.PORT))).
+ processor(new Srv.Processor(new SrvHandler())));
+ serverThread_ = new Thread(new Runnable() {
+ public void run() {
+ server_.serve();
+ }
+ });
+ serverThread_.start();
+ clientManager_ = new TAsyncClientManager();
+ Thread.sleep(500);
+ }
+
+ public void tearDown() throws Exception {
+ server_.stop();
+ clientManager_.stop();
+ serverThread_.join();
+ }
+
+ public void testBasicCall() throws Exception {
+ Srv.AsyncClient client = getClient();
+ basicCall(client);
+ }
+
+ public void testBasicCallWithTimeout() throws Exception {
+ Srv.AsyncClient client = getClient();
+ client.setTimeout(5000);
+ basicCall(client);
+ }
+
+ private static abstract class ErrorCallTest<C extends TAsyncClient, R> {
+ final void runTest() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AtomicReference<Exception> error = new AtomicReference<Exception>();
+ C client = executeErroringCall(new AsyncMethodCallback<R>() {
+ @Override
+ public void onComplete(R response) {
+ latch.countDown();
+ }
+
+ @Override
+ public void onError(Exception exception) {
+ error.set(exception);
+ latch.countDown();
+ }
+ });
+ latch.await(2, TimeUnit.SECONDS);
+ assertTrue(client.hasError());
+ Exception exception = error.get();
+ assertNotNull(exception);
+ assertSame(exception, client.getError());
+ validateError(client, exception);
+ }
+
+ /**
+ * Executes a call that is expected to raise an exception.
+ *
+ * @param callback The testing callback that should be installed.
+ * @return The client the call was made against.
+ * @throws Exception if there was a problem setting up the client or making the call.
+ */
+ abstract C executeErroringCall(AsyncMethodCallback<R> callback) throws Exception;
+
+ /**
+ * Further validates the properties of the error raised in the remote call and the state of the
+ * client after that call.
+ *
+ * @param client The client returned from {@link #executeErroringCall(AsyncMethodCallback)}.
+ * @param error The exception raised by the remote call.
+ */
+ abstract void validateError(C client, Exception error);
+ }
+
+ public void testUnexpectedRemoteExceptionCall() throws Exception {
+ new ErrorCallTest<Srv.AsyncClient, Boolean>() {
+ @Override
+ Srv.AsyncClient executeErroringCall(AsyncMethodCallback<Boolean> callback) throws Exception {
+ Srv.AsyncClient client = getClient();
+ client.declaredExceptionMethod(false, callback);
+ return client;
+ }
+
+ @Override
+ void validateError(Srv.AsyncClient client, Exception error) {
+ assertFalse(client.hasTimeout());
+ assertTrue(error instanceof TException);
+ }
+ }.runTest();
+ }
+
+ public void testDeclaredRemoteExceptionCall() throws Exception {
+ new ErrorCallTest<Srv.AsyncClient, Boolean>() {
+ @Override
+ Srv.AsyncClient executeErroringCall(AsyncMethodCallback<Boolean> callback) throws Exception {
+ Srv.AsyncClient client = getClient();
+ client.declaredExceptionMethod(true, callback);
+ return client;
+ }
+
+ @Override
+ void validateError(Srv.AsyncClient client, Exception error) {
+ assertFalse(client.hasTimeout());
+ assertEquals(ExceptionWithAMap.class, error.getClass());
+ ExceptionWithAMap exceptionWithAMap = (ExceptionWithAMap) error;
+ assertEquals("blah", exceptionWithAMap.getBlah());
+ assertEquals(new HashMap<String, String>(), exceptionWithAMap.getMap_field());
+ }
+ }.runTest();
+ }
+
+ public void testTimeoutCall() throws Exception {
+ new ErrorCallTest<Srv.AsyncClient, Integer>() {
+ @Override
+ Srv.AsyncClient executeErroringCall(AsyncMethodCallback<Integer> callback) throws Exception {
+ Srv.AsyncClient client = getClient();
+ client.setTimeout(100);
+ client.primitiveMethod(callback);
+ return client;
+ }
+
+ @Override
+ void validateError(Srv.AsyncClient client, Exception error) {
+ assertTrue(client.hasTimeout());
+ assertTrue(error instanceof TimeoutException);
+ }
+ }.runTest();
+ }
+
+ public void testVoidCall() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AtomicBoolean returned = new AtomicBoolean(false);
+ Srv.AsyncClient client = getClient();
+ client.voidMethod(new FailureLessCallback<Void>() {
+ @Override
+ public void onComplete(Void response) {
+ returned.set(true);
+ latch.countDown();
+ }
+ });
+ latch.await(1, TimeUnit.SECONDS);
+ assertTrue(returned.get());
+ }
+
+ public void testOnewayCall() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AtomicBoolean returned = new AtomicBoolean(false);
+ Srv.AsyncClient client = getClient();
+ client.onewayMethod(new FailureLessCallback<Void>() {
+ @Override
+ public void onComplete(Void response) {
+ returned.set(true);
+ latch.countDown();
+ }
+ });
+ latch.await(1, TimeUnit.SECONDS);
+ assertTrue(returned.get());
+ }
+
+ public void testParallelCalls() throws Exception {
+ // make multiple calls with deserialization in the selector thread (repro Eric's issue)
+ int numThreads = 50;
+ int numCallsPerThread = 100;
+ List<JankyRunnable> runnables = new ArrayList<JankyRunnable>();
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = 0; i < numThreads; i++) {
+ JankyRunnable runnable = new JankyRunnable(numCallsPerThread);
+ Thread thread = new Thread(runnable);
+ thread.start();
+ threads.add(thread);
+ runnables.add(runnable);
+ }
+ for (Thread thread : threads) {
+ thread.join();
+ }
+ int numSuccesses = 0;
+ for (JankyRunnable runnable : runnables) {
+ numSuccesses += runnable.getNumSuccesses();
+ }
+ assertEquals(numThreads * numCallsPerThread, numSuccesses);
+ }
+
+ private Srv.AsyncClient getClient() throws IOException {
+ TNonblockingSocket clientSocket = new TNonblockingSocket(ServerTestBase.HOST, ServerTestBase.PORT);
+ return new Srv.AsyncClient(new TBinaryProtocol.Factory(), clientManager_, clientSocket);
+ }
+
+ private void basicCall(Srv.AsyncClient client) throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AtomicBoolean returned = new AtomicBoolean(false);
+ client.Janky(1, new FailureLessCallback<Integer>() {
+ @Override
+ public void onComplete(Integer response) {
+ assertEquals(3, response.intValue());
+ returned.set(true);
+ latch.countDown();
+ }
+
+ @Override
+ public void onError(Exception exception) {
+ try {
+ StringWriter sink = new StringWriter();
+ exception.printStackTrace(new PrintWriter(sink, true));
+ fail("unexpected onError with exception " + sink.toString());
+ } finally {
+ latch.countDown();
+ }
+ }
+ });
+ latch.await(100, TimeUnit.SECONDS);
+ assertTrue(returned.get());
+ }
+
+ public class SrvHandler implements Iface {
+ // Use this method for a standard call testing
+ @Override
+ public int Janky(int arg) throws TException {
+ assertEquals(1, arg);
+ return 3;
+ }
+
+ // Using this method for timeout testing - sleeps for 1 second before returning
+ @Override
+ public int primitiveMethod() throws TException {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return 0;
+ }
+
+ @Override
+ public void methodWithDefaultArgs(int something) throws TException { }
+
+ @Override
+ public CompactProtoTestStruct structMethod() throws TException {
+ return null;
+ }
+
+ @Override
+ public void voidMethod() throws TException {
+ }
+
+ @Override
+ public void onewayMethod() throws TException {
+ }
+
+ @Override
+ public boolean declaredExceptionMethod(boolean shouldThrowDeclared) throws TException {
+ if (shouldThrowDeclared) {
+ throw new ExceptionWithAMap("blah", new HashMap<String, String>());
+ } else {
+ throw new TException("Unexpected!");
+ }
+ }
+ }
+
+ private static abstract class FailureLessCallback<T> implements AsyncMethodCallback<T> {
+ @Override
+ public void onError(Exception exception) {
+ fail(exception);
+ }
+ }
+
+ private static void fail(Exception exception) {
+ StringWriter sink = new StringWriter();
+ exception.printStackTrace(new PrintWriter(sink, true));
+ fail("unexpected error " + sink.toString());
+ }
+
+ private class JankyRunnable implements Runnable {
+ private int numCalls_;
+ private int numSuccesses_ = 0;
+ private Srv.AsyncClient client_;
+
+ public JankyRunnable(int numCalls) throws Exception {
+ numCalls_ = numCalls;
+ client_ = getClient();
+ client_.setTimeout(20000);
+ }
+
+ public int getNumSuccesses() {
+ return numSuccesses_;
+ }
+
+ public void run() {
+ for (int i = 0; i < numCalls_ && !client_.hasError(); i++) {
+ final int iteration = i;
+ try {
+ // connect an async client
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AtomicBoolean returned = new AtomicBoolean(false);
+ client_.Janky(1, new AsyncMethodCallback<Integer>() {
+
+ @Override
+ public void onComplete(Integer result) {
+ assertEquals(3, result.intValue());
+ returned.set(true);
+ latch.countDown();
+ }
+
+ @Override
+ public void onError(Exception exception) {
+ try {
+ StringWriter sink = new StringWriter();
+ exception.printStackTrace(new PrintWriter(sink, true));
+ fail("unexpected onError on iteration " + iteration + ": " + sink.toString());
+ } finally {
+ latch.countDown();
+ }
+ }
+ });
+
+ boolean calledBack = latch.await(30, TimeUnit.SECONDS);
+ assertTrue("wasn't called back in time on iteration " + iteration, calledBack);
+ assertTrue("onComplete not called on iteration " + iteration, returned.get());
+ this.numSuccesses_++;
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/BenchmarkProtocols.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/BenchmarkProtocols.java
new file mode 100644
index 000000000..e88160759
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/BenchmarkProtocols.java
@@ -0,0 +1,88 @@
+package org.apache.thrift.protocol;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TMemoryBuffer;
+
+public class BenchmarkProtocols {
+
+ private static final Set<TProtocolFactory> FACTORIES = new LinkedHashSet<TProtocolFactory>(){{
+ add(new TTupleProtocol.Factory());
+ add(new TCompactProtocol.Factory());
+ add(new TBinaryProtocol.Factory());
+ }};
+
+ private static final int NUM_REPS = 100000;
+ private static final int NUM_TRIALS = 10;
+
+ public static void main(String[] args) throws TException {
+ Map<TProtocolFactory, List<Long>> timesByFactory = new HashMap<TProtocolFactory, List<Long>>();
+
+ for (int trial = 0; trial < NUM_TRIALS; trial++) {
+ for (int i = 0; i < 16; i++) {
+ System.gc();
+ }
+// TProtocol proto = factory.getProtocol(new TTransport() {
+// @Override
+// public void write(byte[] buf, int off, int len) throws TTransportException {
+// }
+//
+// @Override
+// public int read(byte[] buf, int off, int len) throws TTransportException {
+// return 0;
+// }
+//
+// @Override
+// public void open() throws TTransportException {
+// }
+//
+// @Override
+// public boolean isOpen() {
+// return true;
+// }
+//
+// @Override
+// public void close() {
+// }
+// });
+
+
+ for (TProtocolFactory factory : FACTORIES) {
+ if (timesByFactory.get(factory) == null) {
+ timesByFactory.put(factory, new ArrayList<Long>());
+ }
+
+ long start = System.currentTimeMillis();
+ for (int rep = 0; rep < NUM_REPS; rep++) {
+ TProtocol proto = factory.getProtocol(new TMemoryBuffer(128*1024));
+ Fixtures.compactProtoTestStruct.write(proto);
+ Fixtures.nesting.write(proto);
+ }
+ long end = System.currentTimeMillis();
+ timesByFactory.get(factory).add(end-start);
+ }
+ }
+
+ for (TProtocolFactory factory : FACTORIES) {
+ List<Long> times = timesByFactory.get(factory);
+// System.out.println("raw times pre-drop: " + times );
+ times.remove(Collections.max(times));
+ long total = 0;
+ for (long t : times) {
+ total += t;
+ }
+ Collections.sort(times);
+ System.out.println(factory.getClass().getName() + " average time: " + (total / times.size()) + "ms");
+ System.out.println("raw times: " + times);
+ }
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java
new file mode 100644
index 000000000..0386d8393
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java
@@ -0,0 +1,427 @@
+/*
+ * 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.thrift.protocol;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.TBase;
+import org.apache.thrift.TDeserializer;
+import org.apache.thrift.TException;
+import org.apache.thrift.TSerializer;
+import org.apache.thrift.transport.TMemoryBuffer;
+
+import thrift.test.CompactProtoTestStruct;
+import thrift.test.HolyMoley;
+import thrift.test.Nesting;
+import thrift.test.OneOfEach;
+import thrift.test.Srv;
+
+public abstract class ProtocolTestBase extends TestCase {
+
+ /** Does it make sense to call methods like writeI32 directly on your protocol? */
+ protected abstract boolean canBeUsedNaked();
+
+ /** The protocol factory for the protocol being tested. */
+ protected abstract TProtocolFactory getFactory();
+
+ public void testDouble() throws Exception {
+ if (canBeUsedNaked()) {
+ TMemoryBuffer buf = new TMemoryBuffer(1000);
+ TProtocol proto = getFactory().getProtocol(buf);
+ proto.writeDouble(123.456);
+ assertEquals(123.456, proto.readDouble());
+ }
+
+ internalTestStructField(new StructFieldTestCase(TType.DOUBLE, (short)15) {
+ @Override
+ public void readMethod(TProtocol proto) throws TException {
+ assertEquals(123.456, proto.readDouble());
+ }
+
+ @Override
+ public void writeMethod(TProtocol proto) throws TException {
+ proto.writeDouble(123.456);
+ }
+ });
+ }
+
+ public void testSerialization() throws Exception {
+ internalTestSerialization(OneOfEach.class, Fixtures.oneOfEach);
+ internalTestSerialization(Nesting.class, Fixtures.nesting);
+ internalTestSerialization(HolyMoley.class, Fixtures.holyMoley);
+ internalTestSerialization(CompactProtoTestStruct.class, Fixtures.compactProtoTestStruct);
+ }
+
+ public void testBinary() throws Exception {
+ for (byte[] b : Arrays.asList(new byte[0],
+ new byte[]{0,1,2,3,4,5,6,7,8,9,10},
+ new byte[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14},
+ new byte[]{0x5D},
+ new byte[]{(byte)0xD5,(byte)0x5D},
+ new byte[]{(byte)0xFF,(byte)0xD5,(byte)0x5D},
+ new byte[128])) {
+ if (canBeUsedNaked()) {
+ internalTestNakedBinary(b);
+ }
+ internalTestBinaryField(b);
+ }
+
+ if (canBeUsedNaked()) {
+ byte[] data = {1, 2, 3, 4, 5, 6};
+
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.get();
+ proto.writeBinary(bb.slice());
+ assertEquals(ByteBuffer.wrap(data, 1, 5), proto.readBinary());
+ }
+ }
+
+ public void testString() throws Exception {
+ for (String s : Arrays.asList("", "short", "borderlinetiny", "a bit longer than the smallest possible")) {
+ if (canBeUsedNaked()) {
+ internalTestNakedString(s);
+ }
+ internalTestStringField(s);
+ }
+ }
+
+ public void testLong() throws Exception {
+ if (canBeUsedNaked()) {
+ internalTestNakedI64(0);
+ }
+ internalTestI64Field(0);
+ for (int i = 0; i < 62; i++) {
+ if (canBeUsedNaked()) {
+ internalTestNakedI64(1L << i);
+ internalTestNakedI64(-(1L << i));
+ }
+ internalTestI64Field(1L << i);
+ internalTestI64Field(-(1L << i));
+ }
+ }
+
+ public void testInt() throws Exception {
+ for (int i : Arrays.asList(0, 1, 7, 150, 15000, 31337, 0xffff, 0xffffff, -1, -7, -150, -15000, -0xffff, -0xffffff)) {
+ if (canBeUsedNaked()) {
+ internalTestNakedI32(i);
+ }
+ internalTestI32Field(i);
+ }
+ }
+
+ public void testShort() throws Exception {
+ for (int s : Arrays.asList(0, 1, 7, 150, 15000, 0x7fff, -1, -7, -150, -15000, -0x7fff)) {
+ if (canBeUsedNaked()) {
+ internalTestNakedI16((short)s);
+ }
+ internalTestI16Field((short)s);
+ }
+ }
+
+ public void testByte() throws Exception {
+ if (canBeUsedNaked()) {
+ internalTestNakedByte();
+ }
+ for (int i = 0; i < 128; i++) {
+ internalTestByteField((byte)i);
+ internalTestByteField((byte)-i);
+ }
+ }
+
+ private void internalTestNakedByte() throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(1000);
+ TProtocol proto = getFactory().getProtocol(buf);
+ proto.writeByte((byte)123);
+ assertEquals((byte) 123, proto.readByte());
+ }
+
+ private void internalTestByteField(final byte b) throws Exception {
+ internalTestStructField(new StructFieldTestCase(TType.BYTE, (short)15) {
+ public void writeMethod(TProtocol proto) throws TException {
+ proto.writeByte(b);
+ }
+
+ public void readMethod(TProtocol proto) throws TException {
+ assertEquals((byte)b, proto.readByte());
+ }
+ });
+ }
+
+ private void internalTestNakedI16(short n) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+ proto.writeI16(n);
+ assertEquals(n, proto.readI16());
+ }
+
+ private void internalTestI16Field(final short n) throws Exception {
+ internalTestStructField(new StructFieldTestCase(TType.I16, (short)15) {
+ public void writeMethod(TProtocol proto) throws TException {
+ proto.writeI16(n);
+ }
+
+ public void readMethod(TProtocol proto) throws TException {
+ assertEquals(n, proto.readI16());
+ }
+ });
+ }
+
+ private void internalTestNakedI32(int n) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+ proto.writeI32(n);
+ assertEquals(n, proto.readI32());
+ }
+
+ private void internalTestI32Field(final int n) throws Exception {
+ internalTestStructField(new StructFieldTestCase(TType.I32, (short)15) {
+ public void writeMethod(TProtocol proto) throws TException {
+ proto.writeI32(n);
+ }
+
+ public void readMethod(TProtocol proto) throws TException {
+ assertEquals(n, proto.readI32());
+ }
+ });
+ }
+
+ private void internalTestNakedI64(long n) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+ proto.writeI64(n);
+ assertEquals(n, proto.readI64());
+ }
+
+ private void internalTestI64Field(final long n) throws Exception {
+ internalTestStructField(new StructFieldTestCase(TType.I64, (short)15) {
+ public void writeMethod(TProtocol proto) throws TException {
+ proto.writeI64(n);
+ }
+
+ public void readMethod(TProtocol proto) throws TException {
+ assertEquals(n, proto.readI64());
+ }
+ });
+ }
+
+ private void internalTestNakedString(String str) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+ proto.writeString(str);
+ assertEquals(str, proto.readString());
+ }
+
+ private void internalTestStringField(final String str) throws Exception {
+ internalTestStructField(new StructFieldTestCase(TType.STRING, (short)15) {
+ public void writeMethod(TProtocol proto) throws TException {
+ proto.writeString(str);
+ }
+
+ public void readMethod(TProtocol proto) throws TException {
+ assertEquals(str, proto.readString());
+ }
+ });
+ }
+
+ private void internalTestNakedBinary(byte[] data) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+ proto.writeBinary(ByteBuffer.wrap(data));
+ assertEquals(ByteBuffer.wrap(data), proto.readBinary());
+ }
+
+ private void internalTestBinaryField(final byte[] data) throws Exception {
+ internalTestStructField(new StructFieldTestCase(TType.STRING, (short)15) {
+ public void writeMethod(TProtocol proto) throws TException {
+ proto.writeBinary(ByteBuffer.wrap(data));
+ }
+
+ public void readMethod(TProtocol proto) throws TException {
+ assertEquals(ByteBuffer.wrap(data), proto.readBinary());
+ }
+ });
+ }
+
+ private <T extends TBase> void internalTestSerialization(Class<T> klass, T expected) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TBinaryProtocol binproto = new TBinaryProtocol(buf);
+
+ expected.write(binproto);
+
+ buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+
+ expected.write(proto);
+ System.out.println("Size in " + proto.getClass().getSimpleName() + ": " + buf.length());
+
+ T actual = klass.newInstance();
+ actual.read(proto);
+ assertEquals(expected, actual);
+ }
+
+ public void testMessage() throws Exception {
+ List<TMessage> msgs = Arrays.asList(new TMessage[]{
+ new TMessage("short message name", TMessageType.CALL, 0),
+ new TMessage("1", TMessageType.REPLY, 12345),
+ new TMessage("loooooooooooooooooooooooooooooooooong", TMessageType.EXCEPTION, 1 << 16),
+ new TMessage("Janky", TMessageType.CALL, 0),
+ });
+
+ for (TMessage msg : msgs) {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+ TMessage output = null;
+
+ proto.writeMessageBegin(msg);
+ proto.writeMessageEnd();
+
+ output = proto.readMessageBegin();
+
+ assertEquals(msg, output);
+ }
+ }
+
+ public void testServerRequest() throws Exception {
+ Srv.Iface handler = new Srv.Iface() {
+ public int Janky(int i32arg) throws TException {
+ return i32arg * 2;
+ }
+
+ public int primitiveMethod() throws TException {
+ return 0;
+ }
+
+ public CompactProtoTestStruct structMethod() throws TException {
+ return null;
+ }
+
+ public void voidMethod() throws TException {
+ }
+
+ public void methodWithDefaultArgs(int something) throws TException {
+ }
+
+ @Override
+ public void onewayMethod() throws TException {
+ }
+
+ @Override
+ public boolean declaredExceptionMethod(boolean shouldThrow) throws TException {
+ return shouldThrow;
+ }
+ };
+
+ Srv.Processor testProcessor = new Srv.Processor(handler);
+
+ TMemoryBuffer clientOutTrans = new TMemoryBuffer(0);
+ TProtocol clientOutProto = getFactory().getProtocol(clientOutTrans);
+ TMemoryBuffer clientInTrans = new TMemoryBuffer(0);
+ TProtocol clientInProto = getFactory().getProtocol(clientInTrans);
+
+ Srv.Client testClient = new Srv.Client(clientInProto, clientOutProto);
+
+ testClient.send_Janky(1);
+ // System.out.println(clientOutTrans.inspect());
+ testProcessor.process(clientOutProto, clientInProto);
+ // System.out.println(clientInTrans.inspect());
+ assertEquals(2, testClient.recv_Janky());
+ }
+
+ public void testTDeserializer() throws TException {
+ TSerializer ser = new TSerializer(getFactory());
+ byte[] bytes = ser.serialize(Fixtures.compactProtoTestStruct);
+
+ TDeserializer deser = new TDeserializer(getFactory());
+ CompactProtoTestStruct cpts = new CompactProtoTestStruct();
+ deser.deserialize(cpts, bytes);
+
+ assertEquals(Fixtures.compactProtoTestStruct, cpts);
+ }
+
+ //
+ // Helper methods
+ //
+
+ private void internalTestStructField(StructFieldTestCase testCase) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ TProtocol proto = getFactory().getProtocol(buf);
+
+ TField field = new TField("test_field", testCase.type_, testCase.id_);
+ proto.writeStructBegin(new TStruct("test_struct"));
+ proto.writeFieldBegin(field);
+ testCase.writeMethod(proto);
+ proto.writeFieldEnd();
+ proto.writeStructEnd();
+
+ proto.readStructBegin();
+ TField readField = proto.readFieldBegin();
+ assertEquals(testCase.id_, readField.id);
+ assertEquals(testCase.type_, readField.type);
+ testCase.readMethod(proto);
+ proto.readStructEnd();
+ }
+
+ private static abstract class StructFieldTestCase {
+ byte type_;
+ short id_;
+ public StructFieldTestCase(byte type, short id) {
+ type_ = type;
+ id_ = id;
+ }
+
+ public abstract void writeMethod(TProtocol proto) throws TException;
+ public abstract void readMethod(TProtocol proto) throws TException;
+ }
+
+ private static final int NUM_TRIALS = 5;
+ private static final int NUM_REPS = 10000;
+
+ protected void benchmark() throws Exception {
+ for (int trial = 0; trial < NUM_TRIALS; trial++) {
+ TSerializer ser = new TSerializer(getFactory());
+ byte[] serialized = null;
+ long serStart = System.currentTimeMillis();
+ for (int rep = 0; rep < NUM_REPS; rep++) {
+ serialized = ser.serialize(Fixtures.holyMoley);
+ }
+ long serEnd = System.currentTimeMillis();
+ long serElapsed = serEnd - serStart;
+ System.out.println("Ser:\t" + serElapsed + "ms\t"
+ + ((double)serElapsed / NUM_REPS) + "ms per serialization");
+
+ HolyMoley cpts = new HolyMoley();
+ TDeserializer deser = new TDeserializer(getFactory());
+ long deserStart = System.currentTimeMillis();
+ for (int rep = 0; rep < NUM_REPS; rep++) {
+ deser.deserialize(cpts, serialized);
+ }
+ long deserEnd = System.currentTimeMillis();
+ long deserElapsed = deserEnd - deserStart;
+ System.out.println("Des:\t" + deserElapsed + "ms\t"
+ + ((double)deserElapsed / NUM_REPS) + "ms per deserialization");
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestShortStack.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestShortStack.java
new file mode 100644
index 000000000..c8e78eee6
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestShortStack.java
@@ -0,0 +1,42 @@
+/*
+ * 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.thrift.protocol;
+
+import junit.framework.TestCase;
+
+public class TestShortStack extends TestCase {
+
+ public void testOps() throws Exception {
+ ShortStack s = new ShortStack(1);
+ s.push((short)10);
+ s.push((short)11);
+ s.push((short)12);
+ assertEquals((short)12, s.pop());
+ assertEquals((short)11, s.pop());
+ s.push((short)40);
+ assertEquals((short)40, s.pop());
+ assertEquals((short)10, s.pop());
+ try {
+ s.pop();
+ fail("should have thrown an exception!");
+ } catch (Exception e) {
+ // yay
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTCompactProtocol.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTCompactProtocol.java
new file mode 100644
index 000000000..b4c0888a4
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTCompactProtocol.java
@@ -0,0 +1,56 @@
+/*
+ * 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.thrift.protocol;
+
+import org.apache.thrift.TDeserializer;
+import org.apache.thrift.TException;
+
+import thrift.test.Bonk;
+
+public class TestTCompactProtocol extends ProtocolTestBase {
+ @Override
+ protected TProtocolFactory getFactory() {
+ return new TCompactProtocol.Factory();
+ }
+
+ @Override
+ protected boolean canBeUsedNaked() {
+ return true;
+ }
+
+ public void testOOMDenialOfService() throws Exception {
+ // Struct header, Integer.MAX_VALUE length, and only one real
+ // byte of data
+ byte [] bytes = {24, -1, -1, -1, -17, 49};
+ TDeserializer deser = new TDeserializer(new TCompactProtocol
+ .Factory(1000));
+ Bonk bonk = new Bonk();
+ try {
+ deser.deserialize(bonk, bytes);
+ } catch (TException e) {
+ // Ignore as we are only checking for OOM in the failure case
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+ new TestTCompactProtocol().benchmark();
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTField.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTField.java
new file mode 100644
index 000000000..f72c25972
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTField.java
@@ -0,0 +1,60 @@
+/*
+ * 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.thrift.protocol;
+
+import junit.framework.TestCase;
+import static org.junit.Assert.assertNotEquals;
+
+public abstract class TestTField extends TestCase {
+
+ public void testConstructor() {
+ TField uut = new TField();
+ assertEquals("", uut.name);
+ assertEquals(TType.STOP, uut.type);
+ assertEquals(0, uut.id);
+
+ uut = new TField("foo", TType.VOID, (short)42);
+ assertEquals("foo", uut.name);
+ assertEquals(TType.VOID, uut.type);
+ assertEquals(42, uut.id);
+ }
+
+ public void testEquality() {
+ TField uut1 = new TField();
+ TField uut2 = new TField();
+ assertEquals(uut1, uut2);
+ assertEquals(uut1.hashCode(), uut2.hashCode());
+
+ uut1 = new TField("foo", TType.I32, (short)1);
+ uut2 = new TField("foo", TType.I32, (short)2);
+ assertNotEquals(uut1, uut2);
+ assertNotEquals(uut1.hashCode(), uut2.hashCode());
+
+ uut1 = new TField("foo", TType.VOID, (short)1);
+ uut2 = new TField("foo", TType.I32, (short)1);
+ assertNotEquals(uut1, uut2);
+ assertNotEquals(uut1.hashCode(), uut2.hashCode());
+
+ uut1 = new TField("foo", TType.VOID, (short)5);
+ uut2 = new TField("bar", TType.I32, (short)5);
+ assertEquals(uut1, uut2); // name field is ignored
+ assertEquals(uut1.hashCode(), uut2.hashCode());
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java
new file mode 100644
index 000000000..c2ca1fa7a
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java
@@ -0,0 +1,48 @@
+/*
+ * 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.thrift.protocol;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.transport.TMemoryBuffer;
+
+public class TestTJSONProtocol extends ProtocolTestBase {
+ @Override
+ protected TProtocolFactory getFactory() {
+ return new TJSONProtocol.Factory();
+ }
+
+ @Override
+ protected boolean canBeUsedNaked() {
+ return false;
+ }
+
+ public void testEscapedUnicode() throws TException {
+ String jsonString = "\"hello unicode \\u0e01\\ud834\\udd1e world\"";
+ String expectedString = "hello unicode \u0e01\ud834\udd1e world";
+
+ TMemoryBuffer buffer = new TMemoryBuffer(1000);
+ TJSONProtocol protocol = new TJSONProtocol(buffer);
+ buffer.write(jsonString.getBytes(StandardCharsets.UTF_8));
+
+ assertEquals(expectedString, protocol.readString());
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java
new file mode 100644
index 000000000..89cf5366e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java
@@ -0,0 +1,83 @@
+/*
+ * 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.thrift.protocol;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.TSerializer;
+
+import thrift.test.GuessProtocolStruct;
+
+public class TestTProtocolUtil extends TestCase {
+
+ public void testGuessProtocolFactory_JSON() throws Exception {
+
+ byte[] data = "{foo}".getBytes();
+ TProtocolFactory factory = TProtocolUtil.guessProtocolFactory(data, new TCompactProtocol.Factory());
+ assertTrue(factory instanceof TJSONProtocol.Factory);
+
+ // Make sure data serialized with TCompact and which starts with '{'
+ // is not mistakenly guessed as serialized with JSON.
+
+ GuessProtocolStruct s = new GuessProtocolStruct();
+ s.putToMap_field("}","}");
+ byte[] ser = new TSerializer(new TCompactProtocol.Factory()).serialize(s);
+ factory = TProtocolUtil.guessProtocolFactory(ser, new TCompactProtocol.Factory());
+ assertFalse(factory instanceof TJSONProtocol.Factory);
+ }
+
+ public void testGuessProtocolFactory_Binary() throws Exception {
+ // Check that a last byte != 0 is correctly reported as Binary
+
+ byte[] buf = new byte[1];
+ for (int i = 1; i < 256; i++) {
+ buf[0] = (byte) i;
+ TProtocolFactory factory = TProtocolUtil.guessProtocolFactory(buf, new TCompactProtocol.Factory());
+ assertTrue(factory instanceof TBinaryProtocol.Factory);
+ }
+
+ // Check that a second byte set to 0 is reported as Binary
+ buf = new byte[2];
+ TProtocolFactory factory = TProtocolUtil.guessProtocolFactory(buf, new TCompactProtocol.Factory());
+ assertTrue(factory instanceof TBinaryProtocol.Factory);
+ }
+
+ public void testGuessProtocolFactory_Compact() throws Exception {
+ // Check that a first byte > 0x10 is reported as Compact
+ byte[] buf = new byte[3];
+ buf[0] = 0x11;
+ TProtocolFactory factory = TProtocolUtil.guessProtocolFactory(buf, new TBinaryProtocol.Factory());
+ assertTrue(factory instanceof TCompactProtocol.Factory);
+
+ // Check that second byte >= 0x80 is reported as Compact
+ buf[0] = 0;
+ for (int i = 0x80; i < 0x100; i++) {
+ buf[1] = (byte) i;
+ factory = TProtocolUtil.guessProtocolFactory(buf, new TBinaryProtocol.Factory());
+ assertTrue(factory instanceof TCompactProtocol.Factory);
+ }
+ }
+
+ public void testGuessProtocolFactory_Undecided() throws Exception {
+ byte[] buf = new byte[3];
+ buf[1] = 0x7e;
+ TProtocolFactory factory = TProtocolUtil.guessProtocolFactory(buf, new TSimpleJSONProtocol.Factory());
+ assertTrue(factory instanceof TSimpleJSONProtocol.Factory);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java
new file mode 100644
index 000000000..171a487ea
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java
@@ -0,0 +1,94 @@
+/*
+ * 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.thrift.protocol;
+
+import java.nio.charset.StandardCharsets;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TMemoryBuffer;
+
+import thrift.test.CompactProtoTestStruct;
+import thrift.test.HolyMoley;
+
+public class TestTSimpleJSONProtocol extends TestCase {
+ private TMemoryBuffer buf;
+ private TSimpleJSONProtocol proto;
+
+ @Override
+ protected void setUp() throws Exception {
+ buf = new TMemoryBuffer(1000);
+ proto = new TSimpleJSONProtocol(buf);
+ }
+
+ private String bufToString() {
+ return buf.toString(StandardCharsets.UTF_8);
+ }
+
+ public void testHolyMoley() throws TException {
+ final HolyMoley holyMoley = Fixtures.holyMoley.deepCopy();
+ // unset sets that produce inconsistent ordering between JDK7/8
+ holyMoley.unsetBonks();
+ holyMoley.unsetContain();
+ holyMoley.write(proto);
+ assertEquals("{\"big\":[{\"im_true\":1,\"im_false\":0,\"a_bite\":35,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]},{\"im_true\":1,\"im_false\":0,\"a_bite\":-42,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]}]}", bufToString());
+ }
+
+ public void testNesting() throws TException {
+ Fixtures.nesting.write(proto);
+ assertEquals("{\"my_bonk\":{\"type\":31337,\"message\":\"I am a bonk... xor!\"},\"my_ooe\":{\"im_true\":1,\"im_false\":0,\"a_bite\":-42,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]}}", bufToString());
+ }
+
+ public void testOneOfEach() throws TException {
+ Fixtures.oneOfEach.write(proto);
+ assertEquals("{\"im_true\":1,\"im_false\":0,\"a_bite\":-42,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]}", bufToString());
+ }
+
+ public void testSanePartsOfCompactProtoTestStruct() throws TException {
+ // unset all the maps with container keys
+ CompactProtoTestStruct struct = Fixtures.compactProtoTestStruct.deepCopy();
+ struct.unsetList_byte_map();
+ struct.unsetSet_byte_map();
+ struct.unsetMap_byte_map();
+ // unset sets and maps that produce inconsistent ordering between JDK7/8
+ struct.unsetByte_set();
+ struct.unsetI16_set();
+ struct.unsetI64_set();
+ struct.unsetDouble_set();
+ struct.unsetString_set();
+ struct.unsetI16_byte_map();
+ struct.unsetI32_byte_map();
+ struct.unsetI64_byte_map();
+ struct.unsetDouble_byte_map();
+ struct.unsetString_byte_map();
+ struct.write(proto);
+ assertEquals("{\"a_byte\":127,\"a_i16\":32000,\"a_i32\":1000000000,\"a_i64\":1099511627775,\"a_double\":5.6789,\"a_string\":\"my string\",\"a_binary\":\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\",\"true_field\":1,\"false_field\":0,\"empty_struct_field\":{},\"byte_list\":[-127,-1,0,1,127],\"i16_list\":[-1,0,1,32767],\"i32_list\":[-1,0,255,65535,16777215,2147483647],\"i64_list\":[-1,0,255,65535,16777215,4294967295,1099511627775,281474976710655,72057594037927935,9223372036854775807],\"double_list\":[0.1,0.2,0.3],\"string_list\":[\"first\",\"second\",\"third\"],\"boolean_list\":[1,1,1,0,0,0],\"struct_list\":[{},{}],\"i32_set\":[1,2,3],\"boolean_set\":[0,1],\"struct_set\":[{}],\"byte_byte_map\":{\"1\":2},\"boolean_byte_map\":{\"0\":0,\"1\":1},\"byte_i16_map\":{\"1\":1,\"2\":-1,\"3\":32767},\"byte_i32_map\":{\"1\":1,\"2\":-1,\"3\":2147483647},\"byte_i64_map\":{\"1\":1,\"2\":-1,\"3\":9223372036854775807},\"byte_double_map\":{\"1\":0.1,\"2\":-0.1,\"3\":1000000.1},\"byte_string_map\":{\"1\":\"\",\"2\":\"blah\",\"3\":\"loooooooooooooong string\"},\"byte_boolean_map\":{\"1\":1,\"2\":0},\"byte_map_map\":{\"0\":{},\"1\":{\"1\":1},\"2\":{\"1\":1,\"2\":2}},\"byte_set_map\":{\"0\":[],\"1\":[1],\"2\":[1,2]},\"byte_list_map\":{\"0\":[],\"1\":[1],\"2\":[1,2]},\"field500\":500,\"field5000\":5000,\"field20000\":20000}", bufToString());
+ }
+
+ public void testThrowsOnCollectionKeys() throws TException {
+ try {
+ Fixtures.compactProtoTestStruct.write(proto);
+ fail("this should throw a CollectionMapKeyException");
+ } catch (TSimpleJSONProtocol.CollectionMapKeyException e) {
+ //
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTTupleProtocol.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTTupleProtocol.java
new file mode 100644
index 000000000..b654db3f8
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/protocol/TestTTupleProtocol.java
@@ -0,0 +1,27 @@
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.TDeserializer;
+import org.apache.thrift.TSerializer;
+
+import thrift.test.TupleProtocolTestStruct;
+
+
+public class TestTTupleProtocol extends ProtocolTestBase {
+
+ @Override
+ protected boolean canBeUsedNaked() {
+ return false;
+ }
+
+ @Override
+ protected TProtocolFactory getFactory() {
+ return new TTupleProtocol.Factory();
+ }
+
+ public void testBitsetLengthIssue() throws Exception {
+ final TupleProtocolTestStruct t1 = new TupleProtocolTestStruct();
+ t1.setField1(0);
+ t1.setField2(12);
+ new TDeserializer(new TTupleProtocol.Factory()).deserialize(new TupleProtocolTestStruct(), new TSerializer(new TTupleProtocol.Factory()).serialize(t1));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/scheme/TestStandardScheme.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/scheme/TestStandardScheme.java
new file mode 100644
index 000000000..33f229e88
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/scheme/TestStandardScheme.java
@@ -0,0 +1,40 @@
+package org.apache.thrift.scheme;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.TBase;
+import org.apache.thrift.TDeserializer;
+import org.apache.thrift.TException;
+import org.apache.thrift.TSerializer;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TMemoryBuffer;
+import org.apache.thrift.transport.TTransport;
+
+import thrift.test.HolyMoley;
+import thrift.test.Nesting;
+import thrift.test.OneOfEach;
+
+public class TestStandardScheme extends TestCase {
+ TSerializer serializer = new TSerializer();
+ TDeserializer deserializer = new TDeserializer();
+
+ /**
+ * This tests whether the Standard Scheme properly reads structs serialized
+ * using an older version of thrift.
+ */
+ public void testPersistentStructs() throws TException {
+ readAndCompare(new OneOfEach(), Fixtures.oneOfEach, Fixtures.persistentBytesOneOfEach);
+ readAndCompare(new HolyMoley(), Fixtures.holyMoley, Fixtures.persistentBytesHolyMoley);
+ readAndCompare(new Nesting(), Fixtures.nesting, Fixtures.persistentBytesNesting);
+ }
+
+ public void readAndCompare(TBase struct, TBase fixture, byte[] inputBytes) throws TException {
+ TTransport trans = new TMemoryBuffer(0);
+ trans.write(inputBytes, 0, inputBytes.length);
+ TProtocol iprot = new TBinaryProtocol(trans);
+ struct.read(iprot);
+ assertEquals(fixture, struct);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/ServerTestBase.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/ServerTestBase.java
new file mode 100644
index 000000000..8348cbc3d
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/ServerTestBase.java
@@ -0,0 +1,715 @@
+/*
+ * 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.thrift.server;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import java.nio.ByteBuffer;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportFactory;
+import org.apache.thrift.transport.TFramedTransport.Factory;
+
+import thrift.test.Insanity;
+import thrift.test.Numberz;
+import thrift.test.ThriftTest;
+import thrift.test.Xception;
+import thrift.test.Xception2;
+import thrift.test.Xtruct;
+import thrift.test.Xtruct2;
+
+public abstract class ServerTestBase extends TestCase {
+
+ public static class TestHandler implements ThriftTest.Iface {
+
+ public TestHandler() {}
+
+ public void testVoid() {
+ System.out.print("testVoid()\n");
+ }
+
+ public String testString(String thing) {
+ System.out.print("testString(\"" + thing + "\")\n");
+ return thing;
+ }
+
+ public boolean testBool(boolean thing) {
+ System.out.print("testBool(" + thing + ")\n");
+ return thing;
+ }
+
+ public byte testByte(byte thing) {
+ System.out.print("testByte(" + thing + ")\n");
+ return thing;
+ }
+
+ public int testI32(int thing) {
+ System.out.print("testI32(" + thing + ")\n");
+ return thing;
+ }
+
+ public long testI64(long thing) {
+ System.out.print("testI64(" + thing + ")\n");
+ return thing;
+ }
+
+ public double testDouble(double thing) {
+ System.out.print("testDouble(" + thing + ")\n");
+ return thing;
+ }
+
+ public ByteBuffer testBinary(ByteBuffer thing) {
+ StringBuilder sb = new StringBuilder(thing.remaining() * 3);
+ thing.mark();
+ int limit = 0; // limit output to keep the log size sane
+ while ((thing.remaining() > 0) && (++limit < 1024)) {
+ sb.append(String.format("%02X ", thing.get()));
+ }
+ if(thing.remaining() > 0) {
+ sb.append("..."); // indicate we have more date
+ }
+ System.out.print("testBinary(" + sb.toString() + ")\n");
+ thing.reset();
+ return thing;
+ }
+
+ public Xtruct testStruct(Xtruct thing) {
+ System.out.print("testStruct({" +
+ "\"" + thing.string_thing + "\", " +
+ thing.byte_thing + ", " +
+ thing.i32_thing + ", " +
+ thing.i64_thing + "})\n");
+ return thing;
+ }
+
+ public Xtruct2 testNest(Xtruct2 nest) {
+ Xtruct thing = nest.struct_thing;
+ System.out.print("testNest({" +
+ nest.byte_thing + ", {" +
+ "\"" + thing.string_thing + "\", " +
+ thing.byte_thing + ", " +
+ thing.i32_thing + ", " +
+ thing.i64_thing + "}, " +
+ nest.i32_thing + "})\n");
+ return nest;
+ }
+
+ public Map<Integer,Integer> testMap(Map<Integer,Integer> thing) {
+ System.out.print("testMap({");
+ System.out.print(thing);
+ System.out.print("})\n");
+ return thing;
+ }
+
+ public Map<String,String> testStringMap(Map<String,String> thing) {
+ System.out.print("testStringMap({");
+ System.out.print(thing);
+ System.out.print("})\n");
+ return thing;
+ }
+
+ public Set<Integer> testSet(Set<Integer> thing) {
+ System.out.print("testSet({");
+ boolean first = true;
+ for (int elem : thing) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(elem);
+ }
+ System.out.print("})\n");
+ return thing;
+ }
+
+ public List<Integer> testList(List<Integer> thing) {
+ System.out.print("testList({");
+ boolean first = true;
+ for (int elem : thing) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(elem);
+ }
+ System.out.print("})\n");
+ return thing;
+ }
+
+ public Numberz testEnum(Numberz thing) {
+ System.out.print("testEnum(" + thing + ")\n");
+ return thing;
+ }
+
+ public long testTypedef(long thing) {
+ System.out.print("testTypedef(" + thing + ")\n");
+ return thing;
+ }
+
+ public Map<Integer,Map<Integer,Integer>> testMapMap(int hello) {
+ System.out.print("testMapMap(" + hello + ")\n");
+ Map<Integer,Map<Integer,Integer>> mapmap =
+ new HashMap<Integer,Map<Integer,Integer>>();
+
+ HashMap<Integer,Integer> pos = new HashMap<Integer,Integer>();
+ HashMap<Integer,Integer> neg = new HashMap<Integer,Integer>();
+ for (int i = 1; i < 5; i++) {
+ pos.put(i, i);
+ neg.put(-i, -i);
+ }
+
+ mapmap.put(4, pos);
+ mapmap.put(-4, neg);
+
+ return mapmap;
+ }
+
+ public Map<Long, Map<Numberz,Insanity>> testInsanity(Insanity argument) {
+ System.out.print("testInsanity()\n");
+
+ HashMap<Numberz,Insanity> first_map = new HashMap<Numberz, Insanity>();
+ HashMap<Numberz,Insanity> second_map = new HashMap<Numberz, Insanity>();;
+
+ first_map.put(Numberz.TWO, argument);
+ first_map.put(Numberz.THREE, argument);
+
+ Insanity looney = new Insanity();
+ second_map.put(Numberz.SIX, looney);
+
+ Map<Long,Map<Numberz,Insanity>> insane =
+ new HashMap<Long, Map<Numberz,Insanity>>();
+ insane.put((long)1, first_map);
+ insane.put((long)2, second_map);
+
+ return insane;
+ }
+
+ public Xtruct testMulti(byte arg0, int arg1, long arg2, Map<Short,String> arg3, Numberz arg4, long arg5) {
+ System.out.print("testMulti()\n");
+
+ Xtruct hello = new Xtruct();;
+ hello.string_thing = "Hello2";
+ hello.byte_thing = arg0;
+ hello.i32_thing = arg1;
+ hello.i64_thing = arg2;
+ return hello;
+ }
+
+ public void testException(String arg) throws Xception, TException {
+ System.out.print("testException("+arg+")\n");
+ if ("Xception".equals(arg)) {
+ Xception x = new Xception();
+ x.errorCode = 1001;
+ x.message = arg;
+ throw x;
+ } else if ("TException".equals(arg)) {
+ // Unspecified exception should yield a TApplicationException on client side
+ throw new RuntimeException(arg);
+ } else {
+ Xtruct result = new Xtruct();
+ result.string_thing = arg;
+ }
+ return;
+ }
+
+ public Xtruct testMultiException(String arg0, String arg1) throws Xception, Xception2 {
+ System.out.print("testMultiException(" + arg0 + ", " + arg1 + ")\n");
+ if (arg0.equals("Xception")) {
+ Xception x = new Xception();
+ x.errorCode = 1001;
+ x.message = "This is an Xception";
+ throw x;
+ } else if (arg0.equals("Xception2")) {
+ Xception2 x = new Xception2();
+ x.errorCode = 2002;
+ x.struct_thing = new Xtruct();
+ x.struct_thing.string_thing = "This is an Xception2";
+ throw x;
+ }
+
+ Xtruct result = new Xtruct();
+ result.string_thing = arg1;
+ return result;
+ }
+
+ public void testOneway(int sleepFor) {
+ System.out.println("testOneway(" + Integer.toString(sleepFor) +
+ ") => sleeping...");
+ try {
+ Thread.sleep(sleepFor * SLEEP_DELAY);
+ System.out.println("Done sleeping!");
+ } catch (InterruptedException ie) {
+ throw new RuntimeException(ie);
+ }
+ }
+ } // class TestHandler
+
+ private static final List<TProtocolFactory> PROTOCOLS = Arrays.asList(
+ new TBinaryProtocol.Factory(),
+ new TCompactProtocol.Factory());
+
+ public static final String HOST = "localhost";
+ public static final int PORT = Integer.valueOf(
+ System.getProperty("test.port", "9090"));
+ protected static final int SLEEP_DELAY = 1000;
+ protected static final int SOCKET_TIMEOUT = 1500;
+ private static final Xtruct XSTRUCT = new Xtruct("Zero", (byte) 1, -3, -5);
+ private static final Xtruct2 XSTRUCT2 = new Xtruct2((byte)1, XSTRUCT, 5);
+
+ public void startServer(TProcessor processor, TProtocolFactory protoFactory) throws Exception{
+ startServer(processor, protoFactory, null);
+ }
+
+ public abstract void startServer(TProcessor processor, TProtocolFactory protoFactory, TTransportFactory factory) throws Exception;
+
+ public abstract void stopServer() throws Exception;
+
+ public abstract TTransport getClientTransport(TTransport underlyingTransport) throws Exception;
+
+ private void testBool(ThriftTest.Client testClient) throws TException {
+ boolean t = testClient.testBool(true);
+ assertEquals(true, t);
+ boolean f = testClient.testBool(false);
+ assertEquals(false, f);
+ }
+
+ private void testByte(ThriftTest.Client testClient) throws TException {
+ byte i8 = testClient.testByte((byte)1);
+ assertEquals(1, i8);
+ }
+
+ private void testDouble(ThriftTest.Client testClient) throws TException {
+ double dub = testClient.testDouble(5.325098235);
+ assertEquals(5.325098235, dub);
+ }
+
+ private void testEnum(ThriftTest.Client testClient) throws TException {
+ assertEquals(Numberz.ONE, testClient.testEnum(Numberz.ONE));
+ assertEquals(Numberz.TWO, testClient.testEnum(Numberz.TWO));
+ assertEquals(Numberz.THREE, testClient.testEnum(Numberz.THREE));
+ assertEquals(Numberz.FIVE, testClient.testEnum(Numberz.FIVE));
+ assertEquals(Numberz.EIGHT, testClient.testEnum(Numberz.EIGHT));
+ }
+
+ private void testI32(ThriftTest.Client testClient) throws TException {
+ int i32 = testClient.testI32(-1);
+ assertEquals(i32, -1);
+ }
+
+ private void testI64(ThriftTest.Client testClient) throws TException {
+ long i64 = testClient.testI64(-34359738368L);
+ assertEquals(i64, -34359738368L);
+ }
+
+ // todo: add assertions
+ private void testInsanity(ThriftTest.Client testClient) throws TException {
+ Insanity insane;
+
+ insane = new Insanity();
+ insane.userMap = new HashMap<Numberz, Long>();
+ insane.userMap.put(Numberz.FIVE, (long)5000);
+ Xtruct truck = new Xtruct();
+ truck.string_thing = "Truck";
+ truck.byte_thing = (byte)8;
+ truck.i32_thing = 8;
+ truck.i64_thing = 8;
+ insane.xtructs = new ArrayList<Xtruct>();
+ insane.xtructs.add(truck);
+ System.out.print("testInsanity()");
+ Map<Long,Map<Numberz,Insanity>> whoa =
+ testClient.testInsanity(insane);
+ System.out.print(" = {");
+ for (long key : whoa.keySet()) {
+ Map<Numberz,Insanity> val = whoa.get(key);
+ System.out.print(key + " => {");
+
+ for (Numberz k2 : val.keySet()) {
+ Insanity v2 = val.get(k2);
+ System.out.print(k2 + " => {");
+ Map<Numberz, Long> userMap = v2.userMap;
+ System.out.print("{");
+ if (userMap != null) {
+ for (Numberz k3 : userMap.keySet()) {
+ System.out.print(k3 + " => " + userMap.get(k3) + ", ");
+ }
+ }
+ System.out.print("}, ");
+
+ List<Xtruct> xtructs = v2.xtructs;
+ System.out.print("{");
+ if (xtructs != null) {
+ for (Xtruct x : xtructs) {
+ System.out.print("{" + "\"" + x.string_thing + "\", " + x.byte_thing + ", " + x.i32_thing + ", "+ x.i64_thing + "}, ");
+ }
+ }
+ System.out.print("}");
+
+ System.out.print("}, ");
+ }
+ System.out.print("}, ");
+ }
+ System.out.print("}\n");
+ }
+
+ public boolean useAsyncProcessor() {
+ return false;
+ }
+
+ public void testIt() throws Exception {
+
+ for (TProtocolFactory protoFactory : getProtocols()) {
+ TProcessor processor = useAsyncProcessor() ? new ThriftTest.AsyncProcessor<AsyncTestHandler>(new AsyncTestHandler()) : new ThriftTest.Processor<TestHandler>(new TestHandler());
+
+ startServer(processor, protoFactory);
+
+ TSocket socket = new TSocket(HOST, PORT);
+ socket.setTimeout(SOCKET_TIMEOUT);
+ TTransport transport = getClientTransport(socket);
+
+ TProtocol protocol = protoFactory.getProtocol(transport);
+ ThriftTest.Client testClient = new ThriftTest.Client(protocol);
+
+ open(transport);
+ testVoid(testClient);
+ testString(testClient);
+ testBool(testClient);
+ testByte(testClient);
+ testI32(testClient);
+ testI64(testClient);
+ testDouble(testClient);
+ testStruct(testClient);
+ testNestedStruct(testClient);
+ testMap(testClient);
+ testStringMap(testClient);
+ testSet(testClient);
+ testList(testClient);
+ testEnum(testClient);
+ testTypedef(testClient);
+ testNestedMap(testClient);
+ testInsanity(testClient);
+ testException(testClient);
+ testOneway(testClient);
+ testI32(testClient);
+ transport.close();
+ socket.close();
+
+ stopServer();
+ }
+ }
+
+ public void open(TTransport transport) throws Exception {
+ transport.open();
+ }
+
+ public List<TProtocolFactory> getProtocols() {
+ return PROTOCOLS;
+ }
+
+ private void testList(ThriftTest.Client testClient) throws TException {
+ List<Integer> listout = new ArrayList<Integer>();
+ for (int i = -2; i < 3; ++i) {
+ listout.add(i);
+ }
+ List<Integer> listin = testClient.testList(listout);
+ assertEquals(listout, listin);
+ }
+
+ private void testMap(ThriftTest.Client testClient) throws TException {
+ Map<Integer,Integer> mapout = new HashMap<Integer,Integer>();
+ for (int i = 0; i < 5; ++i) {
+ mapout.put(i, i-10);
+ }
+ Map<Integer,Integer> mapin = testClient.testMap(mapout);
+ assertEquals(mapout, mapin);
+ }
+
+ private void testStringMap(ThriftTest.Client testClient) throws TException {
+ Map<String,String> mapout = new HashMap<String,String>();
+ mapout.put("a", "123");
+ mapout.put(" x y ", " with spaces ");
+ mapout.put("same", "same");
+ mapout.put("0", "numeric key");
+ Map<String,String> mapin = testClient.testStringMap(mapout);
+ assertEquals(mapout, mapin);
+ }
+
+ private void testNestedMap(ThriftTest.Client testClient) throws TException {
+ Map<Integer,Map<Integer,Integer>> mm =
+ testClient.testMapMap(1);
+ Map<Integer,Map<Integer,Integer>> mapmap =
+ new HashMap<Integer,Map<Integer,Integer>>();
+
+ HashMap<Integer,Integer> pos = new HashMap<Integer,Integer>();
+ HashMap<Integer,Integer> neg = new HashMap<Integer,Integer>();
+ for (int i = 1; i < 5; i++) {
+ pos.put(i, i);
+ neg.put(-i, -i);
+ }
+
+ mapmap.put(4, pos);
+ mapmap.put(-4, neg);
+ assertEquals(mapmap, mm);
+ }
+
+ private void testNestedStruct(ThriftTest.Client testClient) throws TException {
+ Xtruct2 in2 = testClient.testNest(XSTRUCT2);
+ assertEquals(XSTRUCT2, in2);
+ }
+
+ private void testOneway(ThriftTest.Client testClient) throws Exception {
+ long begin = System.currentTimeMillis();
+ testClient.testOneway(1);
+ long elapsed = System.currentTimeMillis() - begin;
+ assertTrue(elapsed < 500);
+ }
+
+ private void testSet(ThriftTest.Client testClient) throws TException {
+ Set<Integer> setout = new HashSet<Integer>();
+ for (int i = -2; i < 3; ++i) {
+ setout.add(i);
+ }
+ Set<Integer> setin = testClient.testSet(setout);
+ assertEquals(setout, setin);
+ }
+
+ private void testString(ThriftTest.Client testClient) throws TException {
+ String s = testClient.testString("Test");
+ assertEquals("Test", s);
+ }
+
+ private void testStruct(ThriftTest.Client testClient) throws TException {
+ assertEquals(XSTRUCT, testClient.testStruct(XSTRUCT));
+ }
+
+ private void testTypedef(ThriftTest.Client testClient) throws TException {
+ assertEquals(309858235082523L, testClient.testTypedef(309858235082523L));
+ }
+
+ private void testVoid(ThriftTest.Client testClient) throws TException {
+ testClient.testVoid();
+ }
+
+ private static class CallCountingTransportFactory extends TTransportFactory {
+ public int count = 0;
+ private final Factory factory;
+
+ public CallCountingTransportFactory(Factory factory) {
+ this.factory = factory;
+ }
+
+ @Override
+ public TTransport getTransport(TTransport trans) {
+ count++;
+ return factory.getTransport(trans);
+ }
+ }
+
+ public void testTransportFactory() throws Exception {
+ for (TProtocolFactory protoFactory : getProtocols()) {
+ TestHandler handler = new TestHandler();
+ ThriftTest.Processor<TestHandler> processor = new ThriftTest.Processor<TestHandler>(handler);
+
+ final CallCountingTransportFactory factory = new CallCountingTransportFactory(new TFramedTransport.Factory());
+
+ startServer(processor, protoFactory, factory);
+ assertEquals(0, factory.count);
+
+ TSocket socket = new TSocket(HOST, PORT);
+ socket.setTimeout(SOCKET_TIMEOUT);
+ TTransport transport = getClientTransport(socket);
+ open(transport);
+
+ TProtocol protocol = protoFactory.getProtocol(transport);
+ ThriftTest.Client testClient = new ThriftTest.Client(protocol);
+ assertEquals(0, testClient.testByte((byte) 0));
+ assertEquals(2, factory.count);
+ socket.close();
+ stopServer();
+ }
+ }
+
+ private void testException(ThriftTest.Client testClient) throws TException, Xception {
+ try {
+ testClient.testException("Xception");
+ assert false;
+ } catch(Xception e) {
+ assertEquals(e.message, "Xception");
+ assertEquals(e.errorCode, 1001);
+ }
+ try {
+ testClient.testException("TException");
+ assert false;
+ } catch(TException e) {
+ }
+ testClient.testException("no Exception");
+ }
+
+
+ public static class AsyncTestHandler implements ThriftTest.AsyncIface {
+
+ TestHandler handler = new TestHandler();
+
+ @Override
+ public void testVoid(AsyncMethodCallback<Void> resultHandler) throws TException {
+ resultHandler.onComplete(null);
+ }
+
+ @Override
+ public void testString(String thing, AsyncMethodCallback<String> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testString(thing));
+ }
+
+ @Override
+ public void testBool(boolean thing, AsyncMethodCallback<Boolean> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testBool(thing));
+ }
+
+ @Override
+ public void testByte(byte thing, AsyncMethodCallback<Byte> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testByte(thing));
+ }
+
+ @Override
+ public void testI32(int thing, AsyncMethodCallback<Integer> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testI32(thing));
+ }
+
+ @Override
+ public void testI64(long thing, AsyncMethodCallback<Long> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testI64(thing));
+ }
+
+ @Override
+ public void testDouble(double thing, AsyncMethodCallback<Double> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testDouble(thing));
+ }
+
+ @Override
+ public void testBinary(ByteBuffer thing, AsyncMethodCallback<ByteBuffer> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testBinary(thing));
+ }
+
+ @Override
+ public void testStruct(Xtruct thing, AsyncMethodCallback<Xtruct> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testStruct(thing));
+ }
+
+ @Override
+ public void testNest(Xtruct2 thing, AsyncMethodCallback<Xtruct2> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testNest(thing));
+ }
+
+ @Override
+ public void testMap(Map<Integer, Integer> thing, AsyncMethodCallback<Map<Integer, Integer>> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testMap(thing));
+ }
+
+ @Override
+ public void testStringMap(Map<String, String> thing, AsyncMethodCallback<Map<String, String>> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testStringMap(thing));
+ }
+
+ @Override
+ public void testSet(Set<Integer> thing, AsyncMethodCallback<Set<Integer>> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testSet(thing));
+ }
+
+ @Override
+ public void testList(List<Integer> thing, AsyncMethodCallback<List<Integer>> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testList(thing));
+ }
+
+ @Override
+ public void testEnum(Numberz thing, AsyncMethodCallback<Numberz> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testEnum(thing));
+ }
+
+ @Override
+ public void testTypedef(long thing, AsyncMethodCallback<Long> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testTypedef(thing));
+ }
+
+ @Override
+ public void testMapMap(int hello, AsyncMethodCallback<Map<Integer,Map<Integer,Integer>>> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testMapMap(hello));
+ }
+
+ @Override
+ public void testInsanity(Insanity argument, AsyncMethodCallback<Map<Long, Map<Numberz,Insanity>>> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testInsanity(argument));
+ }
+
+ @Override
+ public void testMulti(byte arg0, int arg1, long arg2, Map<Short, String> arg3, Numberz arg4, long arg5, AsyncMethodCallback<Xtruct> resultHandler) throws TException {
+ resultHandler.onComplete(handler.testMulti(arg0,arg1,arg2,arg3,arg4,arg5));
+ }
+
+ @Override
+ public void testException(String arg, AsyncMethodCallback<Void> resultHandler) throws TException {
+ System.out.print("testException("+arg+")\n");
+ if ("Xception".equals(arg)) {
+ Xception x = new Xception();
+ x.errorCode = 1001;
+ x.message = arg;
+ // throw and onError yield the same result.
+ // throw x;
+ resultHandler.onError(x);
+ return;
+ } else if ("TException".equals(arg)) {
+ // throw and onError yield the same result.
+ // resultHandler.onError(new TException(arg));
+ // return;
+ // Unspecified exception should yield a TApplicationException on client side
+ throw new RuntimeException(arg);
+ }
+ resultHandler.onComplete(null);
+ }
+
+ @Override
+ public void testMultiException(String arg0, String arg1, AsyncMethodCallback<Xtruct> resultHandler) throws TException {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void testOneway(int secondsToSleep, AsyncMethodCallback<Void> resultHandler) throws TException {
+ handler.testOneway(secondsToSleep);
+ resultHandler.onComplete(null);
+ }
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestAsyncServer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestAsyncServer.java
new file mode 100644
index 000000000..29c54cbbc
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestAsyncServer.java
@@ -0,0 +1,28 @@
+/*
+ * 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.thrift.server;
+
+public class TestAsyncServer extends TestNonblockingServer {
+
+ @Override
+ public boolean useAsyncProcessor(){
+ return true;
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestHsHaServer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestHsHaServer.java
new file mode 100644
index 000000000..6638a333f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestHsHaServer.java
@@ -0,0 +1,30 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.THsHaServer.Args;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+
+public class TestHsHaServer extends TestNonblockingServer {
+ protected TServer getServer(TProcessor processor, TNonblockingServerSocket socket, TProtocolFactory protoFactory) {
+ return new THsHaServer(new Args(socket).processor(processor).protocolFactory(protoFactory));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java
new file mode 100644
index 000000000..3df3bd827
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java
@@ -0,0 +1,123 @@
+/*
+ * 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.thrift.server;
+
+
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.TNonblockingServer.Args;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.apache.thrift.transport.TTransportFactory;
+
+import thrift.test.ThriftTest;
+
+public class TestNonblockingServer extends ServerTestBase {
+
+ private Thread serverThread;
+ private TServer server;
+ private static final int NUM_QUERIES = 1000;
+
+ protected TServer getServer(TProcessor processor, TNonblockingServerSocket socket, TProtocolFactory protoFactory, TTransportFactory factory) {
+ final Args args = new Args(socket).processor(processor).protocolFactory(protoFactory);
+ if (factory != null) {
+ args.transportFactory(factory);
+ }
+ return new TNonblockingServer(args);
+ }
+
+ @Override
+ public void startServer(final TProcessor processor, final TProtocolFactory protoFactory, final TTransportFactory factory) throws Exception {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ // Transport
+ TNonblockingServerSocket tServerSocket =
+ new TNonblockingServerSocket(new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(PORT));
+
+ server = getServer(processor, tServerSocket, protoFactory, factory);
+
+ // Run it
+ System.out.println("Starting the server on port " + PORT + "...");
+ server.serve();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+ };
+ serverThread.start();
+ Thread.sleep(1000);
+ }
+
+ @Override
+ public void stopServer() throws Exception {
+ server.stop();
+ try {
+ serverThread.join();
+ } catch (InterruptedException e) {}
+ }
+
+ @Override
+ public TTransport getClientTransport(TTransport underlyingTransport) throws Exception {
+ return new TFramedTransport(underlyingTransport);
+ }
+
+
+ public void testCleanupAllSelectionKeys() throws Exception {
+ for (TProtocolFactory protoFactory : getProtocols()) {
+ TestHandler handler = new TestHandler();
+ ThriftTest.Processor processor = new ThriftTest.Processor(handler);
+
+ startServer(processor, protoFactory);
+
+ TSocket socket = new TSocket(HOST, PORT);
+ socket.setTimeout(SOCKET_TIMEOUT);
+ TTransport transport = getClientTransport(socket);
+
+ TProtocol protocol = protoFactory.getProtocol(transport);
+ ThriftTest.Client testClient = new ThriftTest.Client(protocol);
+
+ open(transport);
+
+ for (int i = 0; i < NUM_QUERIES; ++i) {
+ testClient.testI32(1);
+ }
+ server.stop();
+ for (int i = 0; i < NUM_QUERIES; ++i) {
+ try {
+ testClient.testI32(1);
+ } catch(TTransportException e) {
+ System.err.println(e);
+ e.printStackTrace();
+ if (e.getCause() instanceof java.net.SocketTimeoutException) {
+ fail("timed out when it should have thrown another kind of error!");
+ }
+ }
+ }
+
+ transport.close();
+ stopServer();
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestThreadedSelectorServer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestThreadedSelectorServer.java
new file mode 100644
index 000000000..ed729a296
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/server/TestThreadedSelectorServer.java
@@ -0,0 +1,30 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.TThreadedSelectorServer.Args;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+
+public class TestThreadedSelectorServer extends TestNonblockingServer {
+ protected TServer getServer(TProcessor processor, TNonblockingServerSocket socket, TProtocolFactory protoFactory) {
+ return new TThreadedSelectorServer(new Args(socket).processor(processor).protocolFactory(protoFactory));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/EqualityTest.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/EqualityTest.java
new file mode 100644
index 000000000..94ba543a8
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/EqualityTest.java
@@ -0,0 +1,663 @@
+/*
+ * 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.
+ */
+
+/*
+This program was generated by the following Python script:
+
+#!/usr/bin/python2.5
+
+# Remove this when Python 2.6 hits the streets.
+from __future__ import with_statement
+
+import sys
+import os.path
+
+
+# Quines the easy way.
+with open(sys.argv[0], 'r') as handle:
+ source = handle.read()
+
+with open(os.path.join(os.path.dirname(sys.argv[0]), 'EqualityTest.java'), 'w') as out:
+ print >> out, ("/""*" r"""
+ * 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.
+ """ "*""/")
+ print >> out
+ print >> out, "/""*"
+ print >> out, "This program was generated by the following Python script:"
+ print >> out
+ out.write(source)
+ print >> out, "*""/"
+
+ print >> out, r'''
+package org.apache.thrift.test;
+
+// Generated code
+import thrift.test.*;
+
+/'''r'''**
+ *'''r'''/
+public class EqualityTest {
+ public static void main(String[] args) throws Exception {
+ JavaTestHelper lhs, rhs;
+'''
+
+ vals = {
+ 'int': ("1", "2"),
+ 'obj': ("\"foo\"", "\"bar\""),
+ 'bin': ("new byte[]{1,2}", "new byte[]{3,4}"),
+ }
+ matrix = (
+ (False,False),
+ (False,True ),
+ (True ,False),
+ (True ,True ),
+ )
+
+ for type in ('int', 'obj', 'bin'):
+ for option in ('req', 'opt'):
+ nulls = matrix[0:1] if type == 'int' else matrix[-1::-1]
+ issets = matrix
+ for is_null in nulls:
+ for is_set in issets:
+ # isset is implied for non-primitives, so only consider the case
+ # where isset and non-null match.
+ if type != 'int' and list(is_set) != [ not null for null in is_null ]:
+ continue
+ for equal in (True, False):
+ print >> out
+ print >> out, " lhs = new JavaTestHelper();"
+ print >> out, " rhs = new JavaTestHelper();"
+ print >> out, " lhs." + option + "_" + type, "=", vals[type][0] + ";"
+ print >> out, " rhs." + option + "_" + type, "=", vals[type][0 if equal else 1] + ";"
+ isset_setter = "set" + option[0].upper() + option[1:] + "_" + type + "IsSet"
+ if (type == 'int' and is_set[0]): print >> out, " lhs." + isset_setter + "(true);"
+ if (type == 'int' and is_set[1]): print >> out, " rhs." + isset_setter + "(true);"
+ if (is_null[0]): print >> out, " lhs." + option + "_" + type, "= null;"
+ if (is_null[1]): print >> out, " rhs." + option + "_" + type, "= null;"
+ this_present = not is_null[0] and (option == 'req' or is_set[0])
+ that_present = not is_null[1] and (option == 'req' or is_set[1])
+ print >> out, " // this_present = " + repr(this_present)
+ print >> out, " // that_present = " + repr(that_present)
+ is_equal = \
+ (not this_present and not that_present) or \
+ (this_present and that_present and equal)
+ eq_str = 'true' if is_equal else 'false'
+
+ print >> out, " if (lhs.equals(rhs) != "+eq_str+")"
+ print >> out, " throw new RuntimeException(\"Failure\");"
+ if is_equal:
+ print >> out, " if (lhs.hashCode() != rhs.hashCode())"
+ print >> out, " throw new RuntimeException(\"Failure\");"
+
+ print >> out, r'''
+ }
+}
+'''
+*/
+
+package org.apache.thrift.test;
+
+// Generated code
+import java.nio.ByteBuffer;
+
+import thrift.test.JavaTestHelper;
+
+/**
+ */
+public class EqualityTest {
+ public static void main(String[] args) throws Exception {
+ JavaTestHelper lhs, rhs;
+
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 1;
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 2;
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 1;
+ rhs.setReq_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 2;
+ rhs.setReq_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 1;
+ lhs.setReq_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 2;
+ lhs.setReq_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 1;
+ lhs.setReq_intIsSet(true);
+ rhs.setReq_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_int = 1;
+ rhs.req_int = 2;
+ lhs.setReq_intIsSet(true);
+ rhs.setReq_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 1;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 2;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 1;
+ rhs.setOpt_intIsSet(true);
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 2;
+ rhs.setOpt_intIsSet(true);
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 1;
+ lhs.setOpt_intIsSet(true);
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 2;
+ lhs.setOpt_intIsSet(true);
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 1;
+ lhs.setOpt_intIsSet(true);
+ rhs.setOpt_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_int = 1;
+ rhs.opt_int = 2;
+ lhs.setOpt_intIsSet(true);
+ rhs.setOpt_intIsSet(true);
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "foo";
+ lhs.req_obj = null;
+ rhs.req_obj = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "bar";
+ lhs.req_obj = null;
+ rhs.req_obj = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "foo";
+ lhs.req_obj = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "bar";
+ lhs.req_obj = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "foo";
+ rhs.req_obj = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "bar";
+ rhs.req_obj = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "foo";
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_obj = "foo";
+ rhs.req_obj = "bar";
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "foo";
+ lhs.opt_obj = null;
+ rhs.opt_obj = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "bar";
+ lhs.opt_obj = null;
+ rhs.opt_obj = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "foo";
+ lhs.opt_obj = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "bar";
+ lhs.opt_obj = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "foo";
+ rhs.opt_obj = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "bar";
+ rhs.opt_obj = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "foo";
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_obj = "foo";
+ rhs.opt_obj = "bar";
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ lhs.req_bin = null;
+ rhs.req_bin = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{3,4});
+ lhs.req_bin = null;
+ rhs.req_bin = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ lhs.req_bin = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{3,4});
+ lhs.req_bin = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{3,4});
+ rhs.req_bin = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.req_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.req_bin = ByteBuffer.wrap(new byte[]{3,4});
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ lhs.opt_bin = null;
+ rhs.opt_bin = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{3,4});
+ lhs.opt_bin = null;
+ rhs.opt_bin = null;
+ // this_present = False
+ // that_present = False
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ lhs.opt_bin = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{3,4});
+ lhs.opt_bin = null;
+ // this_present = False
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{3,4});
+ rhs.opt_bin = null;
+ // this_present = True
+ // that_present = False
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != true)
+ throw new RuntimeException("Failure");
+ if (lhs.hashCode() != rhs.hashCode())
+ throw new RuntimeException("Failure");
+
+ lhs = new JavaTestHelper();
+ rhs = new JavaTestHelper();
+ lhs.opt_bin = ByteBuffer.wrap(new byte[]{1,2});
+ rhs.opt_bin = ByteBuffer.wrap(new byte[]{3,4});
+ // this_present = True
+ // that_present = True
+ if (lhs.equals(rhs) != false)
+ throw new RuntimeException("Failure");
+
+ }
+}
+
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/JavaBeansTest.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/JavaBeansTest.java
new file mode 100644
index 000000000..6a2a0ed0c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/JavaBeansTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.thrift.test;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+
+import thrift.test.OneOfEachBeans;
+
+public class JavaBeansTest {
+ public static void main(String[] args) throws Exception {
+ // Test isSet methods
+ OneOfEachBeans ooe = new OneOfEachBeans();
+
+ // Nothing should be set
+ if (ooe.is_set_a_bite())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_base64())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_byte_list())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_double_precision())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_i16_list())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_i64_list())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_boolean_field())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_integer16())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_integer32())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_integer64())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+ if (ooe.is_set_some_characters())
+ throw new RuntimeException("isSet method error: unset field returned as set!");
+
+ for (int i = 1; i < 12; i++){
+ if (ooe.isSet(ooe.fieldForId(i)))
+ throw new RuntimeException("isSet method error: unset field " + i + " returned as set!");
+ }
+
+ // Everything is set
+ ooe.set_a_bite((byte) 1);
+ ooe.set_base64(ByteBuffer.wrap("bytes".getBytes()));
+ ooe.set_byte_list(new LinkedList<Byte>());
+ ooe.set_double_precision(1);
+ ooe.set_i16_list(new LinkedList<Short>());
+ ooe.set_i64_list(new LinkedList<Long>());
+ ooe.set_boolean_field(true);
+ ooe.set_integer16((short) 1);
+ ooe.set_integer32(1);
+ ooe.set_integer64(1);
+ ooe.set_some_characters("string");
+
+ if (!ooe.is_set_a_bite())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_base64())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_byte_list())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_double_precision())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_i16_list())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_i64_list())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_boolean_field())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_integer16())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_integer32())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_integer64())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+ if (!ooe.is_set_some_characters())
+ throw new RuntimeException("isSet method error: set field returned as unset!");
+
+ for (int i = 1; i < 12; i++){
+ if (!ooe.isSet(ooe.fieldForId(i)))
+ throw new RuntimeException("isSet method error: set field " + i + " returned as unset!");
+ }
+
+ // Should throw exception when field doesn't exist
+ boolean exceptionThrown = false;
+ try{
+ if (ooe.isSet(ooe.fieldForId(100)));
+ } catch (IllegalArgumentException e){
+ exceptionThrown = true;
+ }
+ if (!exceptionThrown)
+ throw new RuntimeException("isSet method error: non-existent field provided as agument but no exception thrown!");
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/ReadStruct.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/ReadStruct.java
new file mode 100644
index 000000000..7e3b091d4
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/ReadStruct.java
@@ -0,0 +1,62 @@
+/*
+ * 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.thrift.test;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TIOStreamTransport;
+import org.apache.thrift.transport.TTransport;
+
+import thrift.test.CompactProtoTestStruct;
+
+public class ReadStruct {
+ public static void main(String[] args) throws Exception {
+ if (args.length != 2) {
+ System.out.println("usage: java -cp build/classes org.apache.thrift.test.ReadStruct filename proto_factory_class");
+ System.out.println("Read in an instance of CompactProtocolTestStruct from 'file', making sure that it is equivalent to Fixtures.compactProtoTestStruct. Use a protocol from 'proto_factory_class'.");
+ }
+
+ TTransport trans = new TIOStreamTransport(new BufferedInputStream(new FileInputStream(args[0])));
+
+ TProtocolFactory factory = (TProtocolFactory)Class.forName(args[1]).newInstance();
+
+ TProtocol proto = factory.getProtocol(trans);
+
+ CompactProtoTestStruct cpts = new CompactProtoTestStruct();
+
+ for (CompactProtoTestStruct._Fields fid : CompactProtoTestStruct.metaDataMap.keySet()) {
+ cpts.setFieldValue(fid, null);
+ }
+
+ cpts.read(proto);
+
+ if (cpts.equals(Fixtures.compactProtoTestStruct)) {
+ System.out.println("Object verified successfully!");
+ } else {
+ System.out.println("Object failed verification!");
+ System.out.println("Expected: " + Fixtures.compactProtoTestStruct + " but got " + cpts);
+ }
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/SerializationBenchmark.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/SerializationBenchmark.java
new file mode 100644
index 000000000..2b0db3132
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/SerializationBenchmark.java
@@ -0,0 +1,80 @@
+/*
+ * 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.thrift.test;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.TBase;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TMemoryBuffer;
+import org.apache.thrift.transport.TMemoryInputTransport;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+
+import thrift.test.OneOfEach;
+
+public class SerializationBenchmark {
+ private final static int HOW_MANY = 10000000;
+
+ public static void main(String[] args) throws Exception {
+ TProtocolFactory factory = new TBinaryProtocol.Factory();
+
+ testSerialization(factory, Fixtures.oneOfEach);
+ testDeserialization(factory, Fixtures.oneOfEach, OneOfEach.class);
+ }
+
+ public static void testSerialization(TProtocolFactory factory, TBase object) throws Exception {
+ TTransport trans = new TTransport() {
+ public void write(byte[] bin, int x, int y) throws TTransportException {}
+ public int read(byte[] bin, int x, int y) throws TTransportException {return 0;}
+ public void close() {}
+ public void open() {}
+ public boolean isOpen() {return true;}
+ };
+
+ TProtocol proto = factory.getProtocol(trans);
+
+ long startTime = System.currentTimeMillis();
+ for (int i = 0; i < HOW_MANY; i++) {
+ object.write(proto);
+ }
+ long endTime = System.currentTimeMillis();
+
+ System.out.println("Serialization test time: " + (endTime - startTime) + " ms");
+ }
+
+ public static <T extends TBase> void testDeserialization(TProtocolFactory factory, T object, Class<T> klass) throws Exception {
+ TMemoryBuffer buf = new TMemoryBuffer(0);
+ object.write(factory.getProtocol(buf));
+ byte[] serialized = new byte[100*1024];
+ buf.read(serialized, 0, 100*1024);
+
+ long startTime = System.currentTimeMillis();
+ for (int i = 0; i < HOW_MANY; i++) {
+ T o2 = klass.newInstance();
+ o2.read(factory.getProtocol(new TMemoryInputTransport(serialized)));
+ }
+ long endTime = System.currentTimeMillis();
+
+ System.out.println("Deserialization test time: " + (endTime - startTime) + " ms");
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestClient.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestClient.java
new file mode 100644
index 000000000..84410cea0
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestClient.java
@@ -0,0 +1,811 @@
+/*
+ * 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.thrift.test;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.thrift.TApplicationException;
+import org.apache.thrift.TException;
+import org.apache.thrift.TSerializer;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TSimpleJSONProtocol;
+import org.apache.thrift.transport.TFastFramedTransport;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.THttpClient;
+import org.apache.thrift.transport.TSSLTransportFactory;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+
+// Generated code
+import thrift.test.Insanity;
+import thrift.test.Numberz;
+import thrift.test.SecondService;
+import thrift.test.ThriftTest;
+import thrift.test.Xception;
+import thrift.test.Xception2;
+import thrift.test.Xtruct;
+import thrift.test.Xtruct2;
+
+/**
+ * Test Java client for thrift. Essentially just a copy of the C++ version,
+ * this makes a variety of requests to enable testing for both performance and
+ * correctness of the output.
+ *
+ */
+public class TestClient {
+
+ private static int ERR_BASETYPES = 1;
+ private static int ERR_STRUCTS = 2;
+ private static int ERR_CONTAINERS = 4;
+ private static int ERR_EXCEPTIONS = 8;
+ private static int ERR_PROTOCOLS = 16;
+ private static int ERR_UNKNOWN = 64;
+
+ public static void main(String [] args) {
+ String host = "localhost";
+ int port = 9090;
+ int numTests = 1;
+ String protocol_type = "binary";
+ String transport_type = "buffered";
+ boolean ssl = false;
+
+ int socketTimeout = 1000;
+
+ try {
+ for (int i = 0; i < args.length; ++i) {
+ if (args[i].startsWith("--host")) {
+ host = args[i].split("=")[1];
+ host.trim();
+ } else if (args[i].startsWith("--port")) {
+ port = Integer.valueOf(args[i].split("=")[1]);
+ } else if (args[i].startsWith("--n") ||
+ args[i].startsWith("--testloops")){
+ numTests = Integer.valueOf(args[i].split("=")[1]);
+ } else if (args[i].equals("--timeout")) {
+ socketTimeout = Integer.valueOf(args[i].split("=")[1]);
+ } else if (args[i].startsWith("--protocol")) {
+ protocol_type = args[i].split("=")[1];
+ protocol_type.trim();
+ } else if (args[i].startsWith("--transport")) {
+ transport_type = args[i].split("=")[1];
+ transport_type.trim();
+ } else if (args[i].equals("--ssl")) {
+ ssl = true;
+ } else if (args[i].equals("--help")) {
+ System.out.println("Allowed options:");
+ System.out.println(" --help\t\t\tProduce help message");
+ System.out.println(" --host=arg (=" + host + ")\tHost to connect");
+ System.out.println(" --port=arg (=" + port + ")\tPort number to connect");
+ System.out.println(" --transport=arg (=" + transport_type + ")\n\t\t\t\tTransport: buffered, framed, fastframed, http");
+ System.out.println(" --protocol=arg (=" + protocol_type + ")\tProtocol: binary, compact, json, multi, multic, multij");
+ System.out.println(" --ssl\t\t\tEncrypted Transport using SSL");
+ System.out.println(" --testloops[--n]=arg (=" + numTests + ")\tNumber of Tests");
+ System.exit(0);
+ }
+ }
+ } catch (Exception x) {
+ System.err.println("Can not parse arguments! See --help");
+ System.exit(ERR_UNKNOWN);
+ }
+
+ try {
+ if (protocol_type.equals("binary")) {
+ } else if (protocol_type.equals("compact")) {
+ } else if (protocol_type.equals("json")) {
+ } else if (protocol_type.equals("multi")) {
+ } else if (protocol_type.equals("multic")) {
+ } else if (protocol_type.equals("multij")) {
+ } else {
+ throw new Exception("Unknown protocol type! " + protocol_type);
+ }
+ if (transport_type.equals("buffered")) {
+ } else if (transport_type.equals("framed")) {
+ } else if (transport_type.equals("fastframed")) {
+ } else if (transport_type.equals("http")) {
+ } else {
+ throw new Exception("Unknown transport type! " + transport_type);
+ }
+ if (transport_type.equals("http") && ssl == true) {
+ throw new Exception("SSL is not supported over http.");
+ }
+ } catch (Exception e) {
+ System.err.println("Error: " + e.getMessage());
+ System.exit(ERR_UNKNOWN);
+ }
+
+ TTransport transport = null;
+
+ try {
+ if (transport_type.equals("http")) {
+ String url = "http://" + host + ":" + port + "/service";
+ transport = new THttpClient(url);
+ } else {
+ TSocket socket = null;
+ if (ssl == true) {
+ socket = TSSLTransportFactory.getClientSocket(host, port, 0);
+ } else {
+ socket = new TSocket(host, port);
+ }
+ socket.setTimeout(socketTimeout);
+ transport = socket;
+ if (transport_type.equals("buffered")) {
+ } else if (transport_type.equals("framed")) {
+ transport = new TFramedTransport(transport);
+ } else if (transport_type.equals("fastframed")) {
+ transport = new TFastFramedTransport(transport);
+ }
+ }
+ } catch (Exception x) {
+ x.printStackTrace();
+ System.exit(ERR_UNKNOWN);
+ }
+
+ TProtocol tProtocol = null;
+ TProtocol tProtocol2 = null;
+ if (protocol_type.equals("json") || protocol_type.equals("multij")) {
+ tProtocol = new TJSONProtocol(transport);
+ } else if (protocol_type.equals("compact") || protocol_type.equals("multic")) {
+ tProtocol = new TCompactProtocol(transport);
+ } else {
+ tProtocol = new TBinaryProtocol(transport);
+ }
+
+ if (protocol_type.startsWith("multi")) {
+ tProtocol2 = new TMultiplexedProtocol(tProtocol, "SecondService");
+ tProtocol = new TMultiplexedProtocol(tProtocol, "ThriftTest");
+ }
+
+ ThriftTest.Client testClient = new ThriftTest.Client(tProtocol);
+ Insanity insane = new Insanity();
+
+ long timeMin = 0;
+ long timeMax = 0;
+ long timeTot = 0;
+
+ int returnCode = 0;
+ for (int test = 0; test < numTests; ++test) {
+ try {
+ /**
+ * CONNECT TEST
+ */
+ System.out.println("Test #" + (test+1) + ", " + "connect " + host + ":" + port);
+
+ if (transport.isOpen() == false) {
+ try {
+ transport.open();
+ } catch (TTransportException ttx) {
+ ttx.printStackTrace();
+ System.out.println("Connect failed: " + ttx.getMessage());
+ System.exit(ERR_UNKNOWN);
+ }
+ }
+
+ long start = System.nanoTime();
+
+ /**
+ * VOID TEST
+ */
+ try {
+ System.out.print("testVoid()");
+ testClient.testVoid();
+ System.out.print(" = void\n");
+ } catch (TApplicationException tax) {
+ tax.printStackTrace();
+ returnCode |= ERR_BASETYPES;
+ }
+
+ /**
+ * STRING TEST
+ */
+ System.out.print("testString(\"Test\")");
+ String s = testClient.testString("Test");
+ System.out.print(" = \"" + s + "\"\n");
+ if (!s.equals("Test")) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * Multiplexed test
+ */
+ if (protocol_type.startsWith("multi")) {
+ SecondService.Client secondClient = new SecondService.Client(tProtocol2);
+ System.out.print("secondtestString(\"Test2\")");
+ s = secondClient.secondtestString("Test2");
+ System.out.print(" = \"" + s + "\"\n");
+ if (!s.equals("testString(\"Test2\")")) {
+ returnCode |= ERR_PROTOCOLS;
+ System.out.println("*** FAILURE ***\n");
+ }
+ }
+ /**
+ * BYTE TEST
+ */
+ System.out.print("testByte(1)");
+ byte i8 = testClient.testByte((byte)1);
+ System.out.print(" = " + i8 + "\n");
+ if (i8 != 1) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * I32 TEST
+ */
+ System.out.print("testI32(-1)");
+ int i32 = testClient.testI32(-1);
+ System.out.print(" = " + i32 + "\n");
+ if (i32 != -1) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * I64 TEST
+ */
+ System.out.print("testI64(-34359738368)");
+ long i64 = testClient.testI64(-34359738368L);
+ System.out.print(" = " + i64 + "\n");
+ if (i64 != -34359738368L) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * DOUBLE TEST
+ */
+ System.out.print("testDouble(-5.325098235)");
+ double dub = testClient.testDouble(-5.325098235);
+ System.out.print(" = " + dub + "\n");
+ if (Math.abs(dub - (-5.325098235)) > 0.001) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * BINARY TEST
+ */
+ try {
+ System.out.print("testBinary(-128...127) = ");
+ byte[] data = new byte[] {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127};
+ ByteBuffer bin = testClient.testBinary(ByteBuffer.wrap(data));
+ bin.mark();
+ byte[] bytes = new byte[bin.limit() - bin.position()];
+ bin.get(bytes);
+ bin.reset();
+ System.out.print("{");
+ boolean first = true;
+ for (int i = 0; i < bytes.length; ++i) {
+ if (first)
+ first = false;
+ else
+ System.out.print(", ");
+ System.out.print(bytes[i]);
+ }
+ System.out.println("}");
+ if (!ByteBuffer.wrap(data).equals(bin)) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("*** FAILURE ***\n");
+ }
+ } catch (Exception ex) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("\n*** FAILURE ***\n");
+ ex.printStackTrace(System.out);
+ }
+
+ /**
+ * STRUCT TEST
+ */
+ System.out.print("testStruct({\"Zero\", 1, -3, -5})");
+ Xtruct out = new Xtruct();
+ out.string_thing = "Zero";
+ out.byte_thing = (byte) 1;
+ out.i32_thing = -3;
+ out.i64_thing = -5;
+ Xtruct in = testClient.testStruct(out);
+ System.out.print(" = {" + "\"" +
+ in.string_thing + "\"," +
+ in.byte_thing + ", " +
+ in.i32_thing + ", " +
+ in.i64_thing + "}\n");
+ if (!in.equals(out)) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * NESTED STRUCT TEST
+ */
+ System.out.print("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
+ Xtruct2 out2 = new Xtruct2();
+ out2.byte_thing = (short)1;
+ out2.struct_thing = out;
+ out2.i32_thing = 5;
+ Xtruct2 in2 = testClient.testNest(out2);
+ in = in2.struct_thing;
+ System.out.print(" = {" + in2.byte_thing + ", {" + "\"" +
+ in.string_thing + "\", " +
+ in.byte_thing + ", " +
+ in.i32_thing + ", " +
+ in.i64_thing + "}, " +
+ in2.i32_thing + "}\n");
+ if (!in2.equals(out2)) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * MAP TEST
+ */
+ Map<Integer,Integer> mapout = new HashMap<Integer,Integer>();
+ for (int i = 0; i < 5; ++i) {
+ mapout.put(i, i-10);
+ }
+ System.out.print("testMap({");
+ boolean first = true;
+ for (int key : mapout.keySet()) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(key + " => " + mapout.get(key));
+ }
+ System.out.print("})");
+ Map<Integer,Integer> mapin = testClient.testMap(mapout);
+ System.out.print(" = {");
+ first = true;
+ for (int key : mapin.keySet()) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(key + " => " + mapout.get(key));
+ }
+ System.out.print("}\n");
+ if (!mapout.equals(mapin)) {
+ returnCode |= ERR_CONTAINERS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * STRING MAP TEST
+ */
+ try {
+ Map<String, String> smapout = new HashMap<String, String>();
+ smapout.put("a", "2");
+ smapout.put("b", "blah");
+ smapout.put("some", "thing");
+ for (String key : smapout.keySet()) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(key + " => " + smapout.get(key));
+ }
+ System.out.print("})");
+ Map<String, String> smapin = testClient.testStringMap(smapout);
+ System.out.print(" = {");
+ first = true;
+ for (String key : smapin.keySet()) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(key + " => " + smapout.get(key));
+ }
+ System.out.print("}\n");
+ if (!smapout.equals(smapin)) {
+ returnCode |= ERR_CONTAINERS;
+ System.out.println("*** FAILURE ***\n");
+ }
+ } catch (Exception ex) {
+ returnCode |= ERR_CONTAINERS;
+ System.out.println("*** FAILURE ***\n");
+ ex.printStackTrace(System.out);
+ }
+
+ /**
+ * SET TEST
+ */
+ Set<Integer> setout = new HashSet<Integer>();
+ for (int i = -2; i < 3; ++i) {
+ setout.add(i);
+ }
+ System.out.print("testSet({");
+ first = true;
+ for (int elem : setout) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(elem);
+ }
+ System.out.print("})");
+ Set<Integer> setin = testClient.testSet(setout);
+ System.out.print(" = {");
+ first = true;
+ for (int elem : setin) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(elem);
+ }
+ System.out.print("}\n");
+ if (!setout.equals(setin)) {
+ returnCode |= ERR_CONTAINERS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * LIST TEST
+ */
+ List<Integer> listout = new ArrayList<Integer>();
+ for (int i = -2; i < 3; ++i) {
+ listout.add(i);
+ }
+ System.out.print("testList({");
+ first = true;
+ for (int elem : listout) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(elem);
+ }
+ System.out.print("})");
+ List<Integer> listin = testClient.testList(listout);
+ System.out.print(" = {");
+ first = true;
+ for (int elem : listin) {
+ if (first) {
+ first = false;
+ } else {
+ System.out.print(", ");
+ }
+ System.out.print(elem);
+ }
+ System.out.print("}\n");
+ if (!listout.equals(listin)) {
+ returnCode |= ERR_CONTAINERS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * ENUM TEST
+ */
+ System.out.print("testEnum(ONE)");
+ Numberz ret = testClient.testEnum(Numberz.ONE);
+ System.out.print(" = " + ret + "\n");
+ if (ret != Numberz.ONE) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ System.out.print("testEnum(TWO)");
+ ret = testClient.testEnum(Numberz.TWO);
+ System.out.print(" = " + ret + "\n");
+ if (ret != Numberz.TWO) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ System.out.print("testEnum(THREE)");
+ ret = testClient.testEnum(Numberz.THREE);
+ System.out.print(" = " + ret + "\n");
+ if (ret != Numberz.THREE) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ System.out.print("testEnum(FIVE)");
+ ret = testClient.testEnum(Numberz.FIVE);
+ System.out.print(" = " + ret + "\n");
+ if (ret != Numberz.FIVE) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ System.out.print("testEnum(EIGHT)");
+ ret = testClient.testEnum(Numberz.EIGHT);
+ System.out.print(" = " + ret + "\n");
+ if (ret != Numberz.EIGHT) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * TYPEDEF TEST
+ */
+ System.out.print("testTypedef(309858235082523)");
+ long uid = testClient.testTypedef(309858235082523L);
+ System.out.print(" = " + uid + "\n");
+ if (uid != 309858235082523L) {
+ returnCode |= ERR_BASETYPES;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * NESTED MAP TEST
+ */
+ System.out.print("testMapMap(1)");
+ Map<Integer,Map<Integer,Integer>> mm =
+ testClient.testMapMap(1);
+ System.out.print(" = {");
+ for (int key : mm.keySet()) {
+ System.out.print(key + " => {");
+ Map<Integer,Integer> m2 = mm.get(key);
+ for (int k2 : m2.keySet()) {
+ System.out.print(k2 + " => " + m2.get(k2) + ", ");
+ }
+ System.out.print("}, ");
+ }
+ System.out.print("}\n");
+ if (mm.size() != 2 || !mm.containsKey(4) || !mm.containsKey(-4)) {
+ returnCode |= ERR_CONTAINERS;
+ System.out.println("*** FAILURE ***\n");
+ } else {
+ Map<Integer, Integer> m1 = mm.get(4);
+ Map<Integer, Integer> m2 = mm.get(-4);
+ if (m1.get(1) != 1 || m1.get(2) != 2 || m1.get(3) != 3 || m1.get(4) != 4 ||
+ m2.get(-1) != -1 || m2.get(-2) != -2 || m2.get(-3) != -3 || m2.get(-4) != -4) {
+ returnCode |= ERR_CONTAINERS;
+ System.out.println("*** FAILURE ***\n");
+ }
+ }
+
+ /**
+ * INSANITY TEST
+ */
+
+ boolean insanityFailed = true;
+ try {
+ Xtruct hello = new Xtruct();
+ hello.string_thing = "Hello2";
+ hello.byte_thing = 2;
+ hello.i32_thing = 2;
+ hello.i64_thing = 2;
+
+ Xtruct goodbye = new Xtruct();
+ goodbye.string_thing = "Goodbye4";
+ goodbye.byte_thing = (byte)4;
+ goodbye.i32_thing = 4;
+ goodbye.i64_thing = (long)4;
+
+ insane.userMap = new HashMap<Numberz, Long>();
+ insane.userMap.put(Numberz.EIGHT, (long)8);
+ insane.userMap.put(Numberz.FIVE, (long)5);
+ insane.xtructs = new ArrayList<Xtruct>();
+ insane.xtructs.add(goodbye);
+ insane.xtructs.add(hello);
+
+ System.out.print("testInsanity()");
+ Map<Long,Map<Numberz,Insanity>> whoa =
+ testClient.testInsanity(insane);
+ System.out.print(" = {");
+ for (long key : whoa.keySet()) {
+ Map<Numberz,Insanity> val = whoa.get(key);
+ System.out.print(key + " => {");
+
+ for (Numberz k2 : val.keySet()) {
+ Insanity v2 = val.get(k2);
+ System.out.print(k2 + " => {");
+ Map<Numberz, Long> userMap = v2.userMap;
+ System.out.print("{");
+ if (userMap != null) {
+ for (Numberz k3 : userMap.keySet()) {
+ System.out.print(k3 + " => " + userMap.get(k3) + ", ");
+ }
+ }
+ System.out.print("}, ");
+
+ List<Xtruct> xtructs = v2.xtructs;
+ System.out.print("{");
+ if (xtructs != null) {
+ for (Xtruct x : xtructs) {
+ System.out.print("{" + "\"" + x.string_thing + "\", " + x.byte_thing + ", " + x.i32_thing + ", "+ x.i64_thing + "}, ");
+ }
+ }
+ System.out.print("}");
+
+ System.out.print("}, ");
+ }
+ System.out.print("}, ");
+ }
+ System.out.print("}\n");
+ if (whoa.size() == 2 && whoa.containsKey(1L) && whoa.containsKey(2L)) {
+ Map<Numberz, Insanity> first_map = whoa.get(1L);
+ Map<Numberz, Insanity> second_map = whoa.get(2L);
+ if (first_map.size() == 2 &&
+ first_map.containsKey(Numberz.TWO) &&
+ first_map.containsKey(Numberz.THREE) &&
+ second_map.size() == 1 &&
+ second_map.containsKey(Numberz.SIX) &&
+ insane.equals(first_map.get(Numberz.TWO)) &&
+ insane.equals(first_map.get(Numberz.THREE))) {
+ Insanity six =second_map.get(Numberz.SIX);
+ // Cannot use "new Insanity().equals(six)" because as of now, struct/container
+ // fields with default requiredness have isset=false for local instances and yet
+ // received empty values from other languages like C++ have isset=true .
+ if (six.getUserMapSize() == 0 && six.getXtructsSize() == 0) {
+ // OK
+ insanityFailed = false;
+ }
+ }
+ }
+ } catch (Exception ex) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ ex.printStackTrace(System.out);
+ insanityFailed = false;
+ }
+ if (insanityFailed) {
+ returnCode |= ERR_STRUCTS;
+ System.out.println("*** FAILURE ***\n");
+ }
+
+ /**
+ * EXECPTION TEST
+ */
+ try {
+ System.out.print("testClient.testException(\"Xception\") =>");
+ testClient.testException("Xception");
+ System.out.print(" void\n*** FAILURE ***\n");
+ returnCode |= ERR_EXCEPTIONS;
+ } catch(Xception e) {
+ System.out.printf(" {%d, \"%s\"}\n", e.errorCode, e.message);
+ }
+
+ try {
+ System.out.print("testClient.testException(\"TException\") =>");
+ testClient.testException("TException");
+ System.out.print(" void\n*** FAILURE ***\n");
+ returnCode |= ERR_EXCEPTIONS;
+ } catch(TException e) {
+ System.out.printf(" {\"%s\"}\n", e.getMessage());
+ }
+
+ try {
+ System.out.print("testClient.testException(\"success\") =>");
+ testClient.testException("success");
+ System.out.print(" void\n");
+ }catch(Exception e) {
+ System.out.printf(" exception\n*** FAILURE ***\n");
+ returnCode |= ERR_EXCEPTIONS;
+ }
+
+
+ /**
+ * MULTI EXCEPTION TEST
+ */
+
+ try {
+ System.out.printf("testClient.testMultiException(\"Xception\", \"test 1\") =>");
+ testClient.testMultiException("Xception", "test 1");
+ System.out.print(" result\n*** FAILURE ***\n");
+ returnCode |= ERR_EXCEPTIONS;
+ } catch(Xception e) {
+ System.out.printf(" {%d, \"%s\"}\n", e.errorCode, e.message);
+ }
+
+ try {
+ System.out.printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
+ testClient.testMultiException("Xception2", "test 2");
+ System.out.print(" result\n*** FAILURE ***\n");
+ returnCode |= ERR_EXCEPTIONS;
+ } catch(Xception2 e) {
+ System.out.printf(" {%d, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing);
+ }
+
+ try {
+ System.out.print("testClient.testMultiException(\"success\", \"test 3\") =>");
+ Xtruct result;
+ result = testClient.testMultiException("success", "test 3");
+ System.out.printf(" {{\"%s\"}}\n", result.string_thing);
+ } catch(Exception e) {
+ System.out.printf(" exception\n*** FAILURE ***\n");
+ returnCode |= ERR_EXCEPTIONS;
+ }
+
+
+
+ /**
+ * ONEWAY TEST
+ */
+ System.out.print("testOneway(3)...");
+ long startOneway = System.nanoTime();
+ testClient.testOneway(3);
+ long onewayElapsedMillis = (System.nanoTime() - startOneway) / 1000000;
+ if (onewayElapsedMillis > 200) {
+ System.out.println("Oneway test took too long to execute failed: took " +
+ Long.toString(onewayElapsedMillis) +
+ "ms");
+ System.out.println("oneway calls are 'fire and forget' and therefore should not cause blocking.");
+ System.out.println("Some transports (HTTP) have a required response, and typically this failure");
+ System.out.println("means the transport response was delayed until after the execution");
+ System.out.println("of the RPC. The server should post the transport response immediately and");
+ System.out.println("before executing the RPC.");
+ System.out.println("*** FAILURE ***");
+ returnCode |= ERR_BASETYPES;
+ } else {
+ System.out.println("Success - fire and forget only took " +
+ Long.toString(onewayElapsedMillis) +
+ "ms");
+ }
+
+
+ long stop = System.nanoTime();
+ long tot = stop-start;
+
+ System.out.println("Total time: " + tot/1000 + "us");
+
+ if (timeMin == 0 || tot < timeMin) {
+ timeMin = tot;
+ }
+ if (tot > timeMax) {
+ timeMax = tot;
+ }
+ timeTot += tot;
+
+ transport.close();
+ } catch (Exception x) {
+ System.out.printf("*** FAILURE ***\n");
+ x.printStackTrace();
+ returnCode |= ERR_UNKNOWN;
+ }
+ }
+
+ long timeAvg = timeTot / numTests;
+
+ System.out.println("Min time: " + timeMin/1000 + "us");
+ System.out.println("Max time: " + timeMax/1000 + "us");
+ System.out.println("Avg time: " + timeAvg/1000 + "us");
+
+ try {
+ String json = (new TSerializer(new TSimpleJSONProtocol.Factory())).toString(insane);
+ System.out.println("\nSample TSimpleJSONProtocol output:\n" + json);
+ } catch (TException x) {
+ System.out.println("*** FAILURE ***");
+ x.printStackTrace();
+ returnCode |= ERR_BASETYPES;
+ }
+
+
+ System.exit(returnCode);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java
new file mode 100644
index 000000000..41c4b6500
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java
@@ -0,0 +1,76 @@
+/*
+ * 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.thrift.test;
+
+import org.apache.thrift.server.THsHaServer;
+import org.apache.thrift.server.TNonblockingServer;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.THsHaServer.Args;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+import org.apache.thrift.server.ServerTestBase.TestHandler;
+
+import thrift.test.ThriftTest;
+
+
+public class TestNonblockingServer extends TestServer {
+ public static void main(String [] args) {
+ try {
+ int port = 9090;
+ boolean hsha = false;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-p")) {
+ port = Integer.valueOf(args[i++]);
+ } else if (args[i].equals("-hsha")) {
+ hsha = true;
+ }
+ }
+ //@TODO add other protocol and transport types
+
+ // Processor
+ TestHandler testHandler =
+ new TestHandler();
+ ThriftTest.Processor testProcessor =
+ new ThriftTest.Processor(testHandler);
+
+ // Transport
+ TNonblockingServerSocket tServerSocket =
+ new TNonblockingServerSocket(new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(port));
+
+ TServer serverEngine;
+
+ if (hsha) {
+ // HsHa Server
+ serverEngine = new THsHaServer(new Args(tServerSocket).processor(testProcessor));
+ } else {
+ // Nonblocking Server
+ serverEngine = new TNonblockingServer(new Args(tServerSocket).processor(testProcessor));
+ }
+
+ // Run it
+ System.out.println("Starting the server on port " + port + "...");
+ serverEngine.serve();
+
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ System.out.println("done.");
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestServer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestServer.java
new file mode 100644
index 000000000..1f3e555d9
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/TestServer.java
@@ -0,0 +1,310 @@
+/*
+ * 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.thrift.test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
+import org.apache.thrift.server.ServerContext;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TServer.Args;
+import org.apache.thrift.server.TSimpleServer;
+import org.apache.thrift.server.TThreadPoolServer;
+import org.apache.thrift.server.ServerTestBase.TestHandler;
+import org.apache.thrift.server.TServerEventHandler;
+import org.apache.thrift.server.TThreadedSelectorServer;
+import org.apache.thrift.server.TNonblockingServer;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TFastFramedTransport;
+import org.apache.thrift.transport.TServerSocket;
+import org.apache.thrift.transport.TSSLTransportFactory;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportFactory;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+import org.apache.thrift.TMultiplexedProcessor;
+
+import thrift.test.Insanity;
+import thrift.test.Numberz;
+import thrift.test.SecondService;
+import thrift.test.ThriftTest;
+import thrift.test.Xception;
+import thrift.test.Xception2;
+import thrift.test.Xtruct;
+import thrift.test.Xtruct2;
+
+public class TestServer {
+
+ // Multiplexed Protocol Support Details:
+ //
+ // For multiplexed testing we always use binary protocol underneath.
+ //
+ // "ThriftTest" named service implements "ThriftTest" from ThriftTest.thrift
+ // "SecondService" named service implements "SecondService" from ThriftTest.thrift
+ // In addition, to support older non-multiplexed clients using the same concrete protocol
+ // the multiplexed processor is taught to use "ThriftTest" if the incoming request has no
+ // multiplexed call name decoration.
+
+ static class SecondHandler implements thrift.test.SecondService.Iface {
+
+ @Override
+ public java.lang.String secondtestString(java.lang.String thing) throws org.apache.thrift.TException
+ { return "testString(\"" + thing + "\")"; }
+
+ }
+
+ static class TestServerContext implements ServerContext {
+
+ int connectionId;
+
+ public TestServerContext(int connectionId) {
+ this.connectionId = connectionId;
+ }
+
+ public int getConnectionId() {
+ return connectionId;
+ }
+
+ public void setConnectionId(int connectionId) {
+ this.connectionId = connectionId;
+ }
+
+ }
+
+ static class TestServerEventHandler implements TServerEventHandler {
+
+ private int nextConnectionId = 1;
+
+ public void preServe() {
+ System.out.println("TServerEventHandler.preServe - called only once before server starts accepting connections");
+ }
+
+ public ServerContext createContext(TProtocol input, TProtocol output) {
+ //we can create some connection level data which is stored while connection is alive & served
+ TestServerContext ctx = new TestServerContext(nextConnectionId++);
+ System.out.println("TServerEventHandler.createContext - connection #"+ctx.getConnectionId()+" established");
+ return ctx;
+ }
+
+ public void deleteContext(ServerContext serverContext, TProtocol input, TProtocol output) {
+ TestServerContext ctx = (TestServerContext)serverContext;
+ System.out.println("TServerEventHandler.deleteContext - connection #"+ctx.getConnectionId()+" terminated");
+ }
+
+ public void processContext(ServerContext serverContext, TTransport inputTransport, TTransport outputTransport) {
+ TestServerContext ctx = (TestServerContext)serverContext;
+ System.out.println("TServerEventHandler.processContext - connection #"+ctx.getConnectionId()+" is ready to process next request");
+ }
+
+ }
+
+ public static void main(String [] args) {
+ try {
+ int port = 9090;
+ boolean ssl = false;
+ String transport_type = "buffered";
+ String protocol_type = "binary";
+ String server_type = "thread-pool";
+ String domain_socket = "";
+ int string_limit = -1;
+ int container_limit = -1;
+ try {
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].startsWith("--port")) {
+ port = Integer.valueOf(args[i].split("=")[1]);
+ } else if (args[i].startsWith("--server-type")) {
+ server_type = args[i].split("=")[1];
+ server_type.trim();
+ } else if (args[i].startsWith("--port")) {
+ port=Integer.parseInt(args[i].split("=")[1]);
+ } else if (args[i].startsWith("--protocol")) {
+ protocol_type = args[i].split("=")[1];
+ protocol_type.trim();
+ } else if (args[i].startsWith("--transport")) {
+ transport_type = args[i].split("=")[1];
+ transport_type.trim();
+ } else if (args[i].equals("--ssl")) {
+ ssl = true;
+ } else if (args[i].startsWith("--string-limit")) {
+ string_limit = Integer.valueOf(args[i].split("=")[1]);
+ } else if (args[i].startsWith("--container-limit")) {
+ container_limit = Integer.valueOf(args[i].split("=")[1]);
+ } else if (args[i].equals("--help")) {
+ System.out.println("Allowed options:");
+ System.out.println(" --help\t\t\tProduce help message");
+ System.out.println(" --port=arg (=" + port + ")\tPort number to connect");
+ System.out.println(" --transport=arg (=" + transport_type + ")\n\t\t\t\tTransport: buffered, framed, fastframed");
+ System.out.println(" --protocol=arg (=" + protocol_type + ")\tProtocol: binary, compact, json, multi, multic, multij");
+ System.out.println(" --ssl\t\t\tEncrypted Transport using SSL");
+ System.out.println(" --server-type=arg (=" + server_type +")\n\t\t\t\tType of server: simple, thread-pool, nonblocking, threaded-selector");
+ System.out.println(" --string-limit=arg (=" + string_limit + ")\tString read length limit");
+ System.out.println(" --container-limit=arg (=" + container_limit + ")\tContainer read length limit");
+ System.exit(0);
+ }
+ }
+ } catch (Exception e) {
+ System.err.println("Can not parse arguments! See --help");
+ System.exit(1);
+ }
+
+ try {
+ if (server_type.equals("simple")) {
+ } else if (server_type.equals("thread-pool")) {
+ } else if (server_type.equals("nonblocking")) {
+ if (ssl == true) {
+ throw new Exception("SSL is not supported over nonblocking servers!");
+ }
+ } else if (server_type.equals("threaded-selector")) {
+ if (ssl == true) {
+ throw new Exception("SSL is not supported over nonblocking servers!");
+ }
+ } else {
+ throw new Exception("Unknown server type! " + server_type);
+ }
+ if (protocol_type.equals("binary")) {
+ } else if (protocol_type.equals("compact")) {
+ } else if (protocol_type.equals("json")) {
+ } else if (protocol_type.equals("multi")) {
+ } else if (protocol_type.equals("multic")) {
+ } else if (protocol_type.equals("multij")) {
+ } else {
+ throw new Exception("Unknown protocol type! " + protocol_type);
+ }
+ if (transport_type.equals("buffered")) {
+ } else if (transport_type.equals("framed")) {
+ } else if (transport_type.equals("fastframed")) {
+ } else {
+ throw new Exception("Unknown transport type! " + transport_type);
+ }
+ } catch (Exception e) {
+ System.err.println("Error: " + e.getMessage());
+ System.exit(1);
+ }
+
+ // Processors
+ TestHandler testHandler = new TestHandler();
+ ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler);
+
+ SecondHandler secondHandler = new SecondHandler();
+ SecondService.Processor secondProcessor = new SecondService.Processor(secondHandler);
+
+ // Protocol factory
+ TProtocolFactory tProtocolFactory = null;
+ if (protocol_type.equals("json") || protocol_type.equals("multij")) {
+ tProtocolFactory = new TJSONProtocol.Factory();
+ } else if (protocol_type.equals("compact") || protocol_type.equals("multic")) {
+ tProtocolFactory = new TCompactProtocol.Factory(string_limit, container_limit);
+ } else { // also covers multi
+ tProtocolFactory = new TBinaryProtocol.Factory(string_limit, container_limit);
+ }
+
+ TTransportFactory tTransportFactory = null;
+
+ if (transport_type.equals("framed")) {
+ tTransportFactory = new TFramedTransport.Factory();
+ } else if (transport_type.equals("fastframed")) {
+ tTransportFactory = new TFastFramedTransport.Factory();
+ } else { // .equals("buffered") => default value
+ tTransportFactory = new TTransportFactory();
+ }
+
+ TServer serverEngine = null;
+
+ // If we are multiplexing services in one server...
+ TMultiplexedProcessor multiplexedProcessor = new TMultiplexedProcessor();
+ multiplexedProcessor.registerDefault (testProcessor);
+ multiplexedProcessor.registerProcessor("ThriftTest", testProcessor);
+ multiplexedProcessor.registerProcessor("SecondService", secondProcessor);
+
+ if (server_type.equals("nonblocking") ||
+ server_type.equals("threaded-selector")) {
+ // Nonblocking servers
+ TNonblockingServerSocket tNonblockingServerSocket =
+ new TNonblockingServerSocket(new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(port));
+
+ if (server_type.contains("nonblocking")) {
+ // Nonblocking Server
+ TNonblockingServer.Args tNonblockingServerArgs
+ = new TNonblockingServer.Args(tNonblockingServerSocket);
+ tNonblockingServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
+ tNonblockingServerArgs.protocolFactory(tProtocolFactory);
+ tNonblockingServerArgs.transportFactory(tTransportFactory);
+ serverEngine = new TNonblockingServer(tNonblockingServerArgs);
+ } else { // server_type.equals("threaded-selector")
+ // ThreadedSelector Server
+ TThreadedSelectorServer.Args tThreadedSelectorServerArgs
+ = new TThreadedSelectorServer.Args(tNonblockingServerSocket);
+ tThreadedSelectorServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
+ tThreadedSelectorServerArgs.protocolFactory(tProtocolFactory);
+ tThreadedSelectorServerArgs.transportFactory(tTransportFactory);
+ serverEngine = new TThreadedSelectorServer(tThreadedSelectorServerArgs);
+ }
+ } else {
+ // Blocking servers
+
+ // SSL socket
+ TServerSocket tServerSocket = null;
+ if (ssl) {
+ tServerSocket = TSSLTransportFactory.getServerSocket(port, 0);
+ } else {
+ tServerSocket = new TServerSocket(new TServerSocket.ServerSocketTransportArgs().port(port));
+ }
+
+ if (server_type.equals("simple")) {
+ // Simple Server
+ TServer.Args tServerArgs = new TServer.Args(tServerSocket);
+ tServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
+ tServerArgs.protocolFactory(tProtocolFactory);
+ tServerArgs.transportFactory(tTransportFactory);
+ serverEngine = new TSimpleServer(tServerArgs);
+ } else { // server_type.equals("threadpool")
+ // ThreadPool Server
+ TThreadPoolServer.Args tThreadPoolServerArgs
+ = new TThreadPoolServer.Args(tServerSocket);
+ tThreadPoolServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
+ tThreadPoolServerArgs.protocolFactory(tProtocolFactory);
+ tThreadPoolServerArgs.transportFactory(tTransportFactory);
+ serverEngine = new TThreadPoolServer(tThreadPoolServerArgs);
+ }
+ }
+
+ // Set server event handler
+ serverEngine.setServerEventHandler(new TestServerEventHandler());
+
+ // Run it
+ System.out.println("Starting the " + (ssl ? "ssl server" : "server") +
+ " [" + protocol_type + "/" + transport_type + "/" + server_type + "] on " +
+ ((domain_socket == "") ? ("port " + port) : ("unix socket " + domain_socket)));
+ serverEngine.serve();
+
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ System.out.println("done.");
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/WriteStruct.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/WriteStruct.java
new file mode 100644
index 000000000..a0013a93a
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/test/WriteStruct.java
@@ -0,0 +1,48 @@
+/*
+ * 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.thrift.test;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.transport.TIOStreamTransport;
+import org.apache.thrift.transport.TTransport;
+
+public class WriteStruct {
+ public static void main(String[] args) throws Exception {
+ if (args.length != 2) {
+ System.out.println("usage: java -cp build/classes org.apache.thrift.test.WriteStruct filename proto_factory_class");
+ System.out.println("Write out an instance of Fixtures.compactProtocolTestStruct to 'file'. Use a protocol from 'proto_factory_class'.");
+ }
+
+ TTransport trans = new TIOStreamTransport(new BufferedOutputStream(new FileOutputStream(args[0])));
+
+ TProtocolFactory factory = (TProtocolFactory)Class.forName(args[1]).newInstance();
+
+ TProtocol proto = factory.getProtocol(trans);
+
+ Fixtures.compactProtoTestStruct.write(proto);
+ trans.flush();
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java
new file mode 100644
index 000000000..3c749f9fb
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java
@@ -0,0 +1,61 @@
+/*
+ * 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.thrift.transport;
+
+
+public class ReadCountingTransport extends TTransport {
+ public int readCount = 0;
+ private TTransport trans;
+ private boolean open = true;
+
+ public ReadCountingTransport(TTransport underlying) {
+ trans = underlying;
+ }
+
+ @Override
+ public void close() {
+ open = false;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return open;
+ }
+
+ @Override
+ public void open() throws TTransportException {
+ open = true;
+ }
+
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ if (!isOpen()) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Transport is closed");
+ }
+ readCount++;
+ return trans.read(buf, off, len);
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ if (!isOpen()) {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Transport is closed");
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java
new file mode 100644
index 000000000..c35348953
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java
@@ -0,0 +1,37 @@
+/*
+ * 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.thrift.transport;
+
+import junit.framework.TestCase;
+
+public class TestAutoExpandingBuffer extends TestCase {
+ public void testExpands() throws Exception {
+ // has expected initial capacity
+ AutoExpandingBuffer b = new AutoExpandingBuffer(10);
+ assertEquals(10, b.array().length);
+
+ // doesn't shrink
+ b.resizeIfNecessary(8);
+ assertEquals(10, b.array().length);
+
+ // grows when more capacity is needed
+ b.resizeIfNecessary(100);
+ assertTrue(b.array().length >= 100);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java
new file mode 100644
index 000000000..83ebc2d4c
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.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.thrift.transport;
+
+import java.nio.ByteBuffer;
+
+import junit.framework.TestCase;
+
+public class TestAutoExpandingBufferReadTransport extends TestCase {
+ private static final byte[] HUNDRED_BYTES = new byte[100];
+
+ static {
+ for (byte i = 0; i < 100; i++) {
+ HUNDRED_BYTES[i] = i;
+ }
+ }
+
+ public void testIt() throws Exception {
+ AutoExpandingBufferReadTransport t = new AutoExpandingBufferReadTransport(150);
+
+ TMemoryInputTransport membuf = new TMemoryInputTransport(HUNDRED_BYTES);
+
+ t.fill(membuf, 100);
+ assertEquals(100, t.getBytesRemainingInBuffer());
+ assertEquals(0, t.getBufferPosition());
+
+ byte[] target = new byte[10];
+ assertEquals(10, t.read(target, 0, 10));
+ assertEquals(ByteBuffer.wrap(HUNDRED_BYTES, 0, 10), ByteBuffer.wrap(target));
+
+ assertEquals(90, t.getBytesRemainingInBuffer());
+ assertEquals(10, t.getBufferPosition());
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java
new file mode 100644
index 000000000..86b5b0d0f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java
@@ -0,0 +1,69 @@
+/*
+ * 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.thrift.transport;
+
+import java.nio.ByteBuffer;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class TestAutoExpandingBufferWriteTransport {
+
+ @Test
+ public void testIt() throws Exception {
+ AutoExpandingBufferWriteTransport t = new AutoExpandingBufferWriteTransport(1, 0);
+ assertEquals(0, t.getLength());
+ assertEquals(1, t.getBuf().array().length);
+ byte[] b1 = new byte[]{1,2,3};
+ t.write(b1);
+ assertEquals(3, t.getLength());
+ assertTrue(t.getBuf().array().length >= 3);
+ assertEquals(ByteBuffer.wrap(b1), ByteBuffer.wrap(t.getBuf().array(), 0, 3));
+
+ t.reset();
+ assertEquals(0, t.getLength());
+ assertTrue(t.getBuf().array().length >= 3);
+ byte[] b2 = new byte[]{4,5};
+ t.write(b2);
+ assertEquals(2, t.getLength());
+ assertEquals(ByteBuffer.wrap(b2), ByteBuffer.wrap(t.getBuf().array(), 0, 2));
+
+ AutoExpandingBufferWriteTransport uut = new AutoExpandingBufferWriteTransport(8, 4);
+ assertEquals(4, uut.getLength());
+ assertEquals(8, uut.getBuf().array().length);
+ uut.write(b1);
+ assertEquals(7, uut.getLength());
+ assertEquals(8, uut.getBuf().array().length);
+ assertEquals(ByteBuffer.wrap(b1), ByteBuffer.wrap(uut.getBuf().array(), 4, 3));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testBadInitialSize() throws IllegalArgumentException {
+ new AutoExpandingBufferWriteTransport(0, 0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testBadFrontReserveSize() throws IllegalArgumentException {
+ new AutoExpandingBufferWriteTransport(4, -1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testTooSmallFrontReserveSize() throws IllegalArgumentException {
+ new AutoExpandingBufferWriteTransport(4, 5);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java
new file mode 100644
index 000000000..bdc0a848a
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java
@@ -0,0 +1,36 @@
+package org.apache.thrift.transport;
+
+import junit.framework.TestCase;
+import java.nio.charset.StandardCharsets;
+import org.apache.thrift.TException;
+
+import java.nio.ByteBuffer;
+
+public class TestTByteBuffer extends TestCase {
+ public void testReadWrite() throws Exception {
+ final TByteBuffer byteBuffer = new TByteBuffer(ByteBuffer.allocate(16));
+ byteBuffer.write("Hello World".getBytes(StandardCharsets.UTF_8));
+ assertEquals("Hello World", new String(byteBuffer.flip().toByteArray(), StandardCharsets.UTF_8));
+ }
+
+ public void testReuseReadWrite() throws Exception {
+ final TByteBuffer byteBuffer = new TByteBuffer(ByteBuffer.allocate(16));
+ byteBuffer.write("Hello World".getBytes(StandardCharsets.UTF_8));
+ assertEquals("Hello World", new String(byteBuffer.flip().toByteArray(), StandardCharsets.UTF_8));
+
+ byteBuffer.clear();
+
+ byteBuffer.write("Goodbye Horses".getBytes(StandardCharsets.UTF_8));
+ assertEquals("Goodbye Horses", new String(byteBuffer.flip().toByteArray(), StandardCharsets.UTF_8));
+ }
+
+ public void testOverflow() throws Exception {
+ final TByteBuffer byteBuffer = new TByteBuffer(ByteBuffer.allocate(4));
+ try {
+ byteBuffer.write("Hello World".getBytes(StandardCharsets.UTF_8));
+ fail("Expected write operation to fail with TTransportException");
+ } catch (TTransportException e) {
+ assertEquals("Not enough room in output buffer", e.getMessage());
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java
new file mode 100644
index 000000000..06ee20666
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java
@@ -0,0 +1,33 @@
+/*
+ * 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.thrift.transport;
+
+public class TestTFastFramedTransport extends TestTFramedTransport {
+ protected final static int INITIAL_CAPACITY = 50;
+
+ @Override
+ protected TTransport getTransport(TTransport underlying) {
+ return new TFastFramedTransport(underlying, INITIAL_CAPACITY, 10 * 1024 * 1024);
+ }
+
+ @Override
+ protected TTransport getTransport(TTransport underlying, int maxLength) {
+ return new TFastFramedTransport(underlying, INITIAL_CAPACITY, maxLength);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java
new file mode 100644
index 000000000..e30d74b07
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java
@@ -0,0 +1,214 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class TestTFramedTransport extends TestCase {
+
+ protected TTransport getTransport(TTransport underlying) {
+ return new TFramedTransport(underlying);
+ }
+
+ protected TTransport getTransport(TTransport underlying, int maxLength) {
+ return new TFramedTransport(underlying, maxLength);
+ }
+
+ public static byte[] byteSequence(int start, int end) {
+ byte[] result = new byte[end-start+1];
+ for (int i = 0; i <= (end-start); i++) {
+ result[i] = (byte)(start+i);
+ }
+ return result;
+ }
+
+ public void testRead() throws IOException, TTransportException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+ dos.writeInt(50);
+ dos.write(byteSequence(0, 49));
+
+ dos.writeInt(220);
+ dos.write(byteSequence(0, 219));
+
+ TMemoryBuffer membuf = new TMemoryBuffer(0);
+ membuf.write(baos.toByteArray());
+
+ ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+ TTransport trans = getTransport(countTrans);
+
+ byte[] readBuf = new byte[10];
+ trans.read(readBuf, 0, 10);
+ assertTrue(Arrays.equals(readBuf, byteSequence(0,9)));
+ assertEquals(2, countTrans.readCount);
+
+ trans.read(readBuf, 0, 10);
+ assertTrue(Arrays.equals(readBuf, byteSequence(10,19)));
+ assertEquals(2, countTrans.readCount);
+
+ assertEquals(30, trans.read(new byte[30], 0, 30));
+ assertEquals(2, countTrans.readCount);
+
+ readBuf = new byte[220];
+ assertEquals(220, trans.read(readBuf, 0, 220));
+ assertTrue(Arrays.equals(readBuf, byteSequence(0, 219)));
+ assertEquals(4, countTrans.readCount);
+ }
+
+ public void testInvalidFrameSize() throws IOException, TTransportException {
+ int maxLength = 128;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+ dos.writeInt(130);
+ dos.write(byteSequence(0, 129));
+
+ TMemoryBuffer membuf = new TMemoryBuffer(0);
+ membuf.write(baos.toByteArray());
+
+ ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+ TTransport trans = getTransport(countTrans, maxLength);
+
+ byte[] readBuf = new byte[10];
+ try {
+ trans.read(readBuf, 0, 4);
+ fail("Expected a TTransportException");
+ } catch (TTransportException e) {
+ // We expect this exception because the frame we're trying to read is larger than our max frame length
+ assertEquals(TTransportException.CORRUPTED_DATA, e.getType());
+ }
+
+ assertFalse(trans.isOpen());
+
+ try {
+ trans.read(readBuf, 0, 4);
+ fail("Expected a TTransportException");
+ } catch (TTransportException e) {
+ // This time we get an exception indicating the connection was closed
+ assertEquals(TTransportException.NOT_OPEN, e.getType());
+ }
+ }
+
+ public void testWrite() throws TTransportException, IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ WriteCountingTransport countingTrans = new WriteCountingTransport(new TIOStreamTransport(new BufferedOutputStream(baos)));
+ TTransport trans = getTransport(countingTrans);
+
+ trans.write(byteSequence(0,100));
+ assertEquals(0, countingTrans.writeCount);
+ trans.write(byteSequence(101,200));
+ trans.write(byteSequence(201,255));
+ assertEquals(0, countingTrans.writeCount);
+
+ trans.flush();
+ assertEquals(1, countingTrans.writeCount);
+
+ trans.write(byteSequence(0, 245));
+ trans.flush();
+ assertEquals(2, countingTrans.writeCount);
+
+ DataInputStream din = new DataInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ assertEquals(256, din.readInt());
+
+ byte[] buf = new byte[256];
+ din.read(buf, 0, 256);
+ assertTrue(Arrays.equals(byteSequence(0,255), buf));
+
+ assertEquals(246, din.readInt());
+ buf = new byte[246];
+ din.read(buf, 0, 246);
+ assertTrue(Arrays.equals(byteSequence(0,245), buf));
+ }
+
+ public void testDirectRead() throws IOException, TTransportException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+ dos.writeInt(50);
+ dos.write(byteSequence(0, 49));
+ dos.writeInt(75);
+ dos.write(byteSequence(125, 200));
+
+ TMemoryBuffer membuf = new TMemoryBuffer(0);
+ membuf.write(baos.toByteArray());
+
+ ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+ TTransport trans = getTransport(countTrans);
+
+ assertEquals(0, trans.getBytesRemainingInBuffer());
+
+ byte[] readBuf = new byte[10];
+ trans.read(readBuf, 0, 10);
+ assertTrue(Arrays.equals(readBuf, byteSequence(0,9)));
+
+ assertEquals(40, trans.getBytesRemainingInBuffer());
+ assertEquals(10, trans.getBufferPosition());
+
+ trans.consumeBuffer(5);
+ assertEquals(35, trans.getBytesRemainingInBuffer());
+ assertEquals(15, trans.getBufferPosition());
+
+ assertEquals(2, countTrans.readCount);
+
+ assertEquals(35, trans.read(new byte[35], 0, 35));
+ assertEquals(0, trans.getBytesRemainingInBuffer());
+ assertEquals(50, trans.getBufferPosition());
+
+ trans.read(readBuf, 0, 10);
+ assertEquals(4, countTrans.readCount);
+ assertTrue(Arrays.equals(readBuf, byteSequence(125,134)));
+ assertEquals(65, trans.getBytesRemainingInBuffer());
+ assertEquals(10, trans.getBufferPosition());
+ }
+
+ public void testClear() throws IOException, TTransportException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+ dos.writeInt(220);
+ dos.write(byteSequence(0, 219));
+
+ TMemoryBuffer membuf = new TMemoryBuffer(0);
+ membuf.write(baos.toByteArray());
+
+ ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+ TTransport trans = getTransport(countTrans);
+
+ byte[] readBuf = new byte[220];
+ trans.read(readBuf, 0, 220);
+ assertTrue(Arrays.equals(readBuf, byteSequence(0,219)));
+
+ assertTrue(trans instanceof TFramedTransport || trans instanceof TFastFramedTransport);
+ if (trans instanceof TFramedTransport) {
+ assertTrue(trans.getBuffer() != null && trans.getBuffer().length > 0);
+ ((TFramedTransport) trans).clear();
+ assertTrue(trans.getBuffer() == null);
+ } else if (trans instanceof TFastFramedTransport) {
+ assertTrue(trans.getBuffer().length > TestTFastFramedTransport.INITIAL_CAPACITY);
+ ((TFastFramedTransport) trans).clear();
+ assertTrue(trans.getBuffer().length == TestTFastFramedTransport.INITIAL_CAPACITY);
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTMemoryInputTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTMemoryInputTransport.java
new file mode 100644
index 000000000..273145bd2
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTMemoryInputTransport.java
@@ -0,0 +1,85 @@
+/*
+ * 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.thrift.transport;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class TestTMemoryInputTransport extends TestCase {
+ public void testFresh() throws Exception {
+ byte[] input_buf = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TMemoryInputTransport trans = new TMemoryInputTransport(input_buf);
+ assertEquals(0, trans.getBufferPosition());
+ assertEquals(input_buf, trans.getBuffer());
+ assertEquals(10, trans.getBytesRemainingInBuffer());
+
+ byte[] buf1 = new byte[4];
+ trans.readAll(buf1, 0, 4);
+ assertTrue(Arrays.equals(new byte[]{1, 2, 3, 4}, buf1));
+ assertEquals(4, trans.getBufferPosition());
+ assertEquals(6, trans.getBytesRemainingInBuffer());
+
+ trans.consumeBuffer(2);
+
+ assertEquals(6, trans.getBufferPosition());
+ assertEquals(4, trans.getBytesRemainingInBuffer());
+
+ trans.readAll(buf1, 0, 4);
+ assertTrue(Arrays.equals(new byte[]{7, 8, 9, 10}, buf1));
+ assertEquals(10, trans.getBufferPosition());
+ assertEquals(0, trans.getBytesRemainingInBuffer());
+ }
+
+ public void testReused() throws Exception {
+ byte[] input_buf = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TMemoryInputTransport trans = new TMemoryInputTransport(input_buf);
+ assertEquals(0, trans.getBufferPosition());
+ assertEquals(input_buf, trans.getBuffer());
+ assertEquals(10, trans.getBytesRemainingInBuffer());
+
+ byte[] new_buf = new byte[]{10, 9, 8};
+ trans.reset(new_buf);
+ assertEquals(0, trans.getBufferPosition());
+ assertEquals(new_buf, trans.getBuffer());
+ assertEquals(3, trans.getBytesRemainingInBuffer());
+ }
+
+ public void testWithOffsetAndLength() throws Exception {
+ byte[] input_buf = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TMemoryInputTransport trans = new TMemoryInputTransport(input_buf, 1, 3);
+ assertEquals(1, trans.getBufferPosition());
+ assertEquals(3, trans.getBytesRemainingInBuffer());
+ byte[] readBuffer = new byte[3];
+ trans.readAll(readBuffer, 0, 3);
+ assertTrue(Arrays.equals(new byte[]{2, 3, 4}, readBuffer));
+
+ try {
+ assertEquals(0, trans.readAll(readBuffer, 0, 3));
+ fail("should have thrown an exception");
+ } catch (Exception e) {
+ // yay
+ }
+
+ trans.reset(input_buf, 3, 4);
+ readBuffer = new byte[4];
+ trans.readAll(readBuffer, 0, 4);
+ assertTrue(Arrays.equals(new byte[]{4, 5, 6, 7}, readBuffer));
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java
new file mode 100644
index 000000000..032c2eb71
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java
@@ -0,0 +1,92 @@
+/*
+ * 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.thrift.transport;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.ServerTestBase;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TSimpleServer;
+import org.apache.thrift.server.TServer.Args;
+
+public class TestTSSLTransportFactory extends ServerTestBase {
+ private Thread serverThread;
+ private TServer server;
+
+ private static final List<TProtocolFactory> protocols = new ArrayList<TProtocolFactory>();
+ static {
+ // TODO: Only supported on TBinaryProtocol. Doesn't work for TCompactProtocol
+ protocols.add(new TBinaryProtocol.Factory());
+ }
+
+ @Override
+ public TTransport getClientTransport(TTransport underlyingTransport)
+ throws Exception {
+ return TSSLTransportFactory.getClientSocket(HOST, PORT);
+ }
+
+ protected TServerSocket getServerTransport() throws Exception {
+ return TSSLTransportFactory.getServerSocket(PORT);
+ }
+
+ @Override
+ public void startServer(final TProcessor processor, final TProtocolFactory protoFactory, final TTransportFactory factory)
+ throws Exception {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ TServerTransport serverTransport = getServerTransport();
+ final Args args = new Args(serverTransport).processor(processor);
+ server = new TSimpleServer(args);
+ server.serve();
+ } catch (Exception e) {
+ e.printStackTrace();
+ assert false;
+ }
+ }
+ };
+
+ serverThread.start();
+ Thread.sleep(SLEEP_DELAY);
+ }
+
+ @Override
+ public void stopServer() throws Exception {
+ server.stop();
+ serverThread.join();
+ }
+
+ @Override
+ public void open(TTransport transport) throws Exception {}
+
+ @Override
+ public List<TProtocolFactory> getProtocols() {
+ return protocols;
+ }
+
+ @Override
+ public void testTransportFactory() throws Exception {
+ // this test doesn't really apply to this suite, so let's skip it.
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java
new file mode 100644
index 000000000..da1659f9d
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java
@@ -0,0 +1,35 @@
+/*
+ * 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.thrift.transport;
+
+public class TestTSSLTransportFactoryCustomClient1 extends TestTSSLTransportFactory {
+
+ @Override
+ public TTransport getClientTransport(TTransport underlyingTransport)
+ throws Exception {
+ TSSLTransportFactory.TSSLTransportParameters params = new
+ TSSLTransportFactory.TSSLTransportParameters();
+
+ params.setTrustStore(System.getProperty("javax.net.ssl.trustStore"),
+ System.getProperty("javax.net.ssl.trustStorePassword"));
+
+ return TSSLTransportFactory.getClientSocket(HOST, PORT, 0/*timeout*/, params);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java
new file mode 100644
index 000000000..eaed46057
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java
@@ -0,0 +1,34 @@
+/*
+ * 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.thrift.transport;
+
+public class TestTSSLTransportFactoryCustomClient2 extends TestTSSLTransportFactory {
+
+ @Override
+ public TTransport getClientTransport(TTransport underlyingTransport)
+ throws Exception {
+ TSSLTransportFactory.TSSLTransportParameters params = new
+ TSSLTransportFactory.TSSLTransportParameters();
+
+ params.setTrustStore(System.getProperty("javax.net.ssl.trustStore"), null);
+
+ return TSSLTransportFactory.getClientSocket(HOST, PORT, 0/*timeout*/, params);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryStreamedStore.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryStreamedStore.java
new file mode 100644
index 000000000..25bf5cebb
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryStreamedStore.java
@@ -0,0 +1,62 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.FileInputStream;
+import java.net.InetAddress;
+
+public class TestTSSLTransportFactoryStreamedStore extends TestTSSLTransportFactory {
+ private static String keyStoreLocation = System.getProperty("javax.net.ssl.keyStore");
+ private static String trustStoreLocation = System.getProperty("javax.net.ssl.trustStore");
+
+ public TestTSSLTransportFactoryStreamedStore() {
+ super();
+
+ /**
+ * Override system properties to be able to test passing
+ * the trustStore and keyStore as input stream
+ */
+ System.setProperty("javax.net.ssl.trustStore", "");
+ System.setProperty("javax.net.ssl.keyStore", "");
+ }
+
+ @Override
+ public TTransport getClientTransport(TTransport underlyingTransport)
+ throws Exception {
+ TSSLTransportFactory.TSSLTransportParameters params = new
+ TSSLTransportFactory.TSSLTransportParameters();
+
+ params.setTrustStore(new FileInputStream(trustStoreLocation),
+ System.getProperty("javax.net.ssl.trustStorePassword"));
+
+ return TSSLTransportFactory.getClientSocket(HOST, PORT, 0/*timeout*/, params);
+ }
+
+ @Override
+ protected TServerSocket getServerTransport() throws Exception {
+ TSSLTransportFactory.TSSLTransportParameters params = new
+ TSSLTransportFactory.TSSLTransportParameters();
+
+ params.setKeyStore(new FileInputStream(keyStoreLocation),
+ System.getProperty("javax.net.ssl.keyStorePassword"));
+
+ return TSSLTransportFactory.getServerSocket(PORT, 0/*timeout*/, InetAddress.getByName(HOST), params);
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java
new file mode 100644
index 000000000..36a06e9e5
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java
@@ -0,0 +1,471 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.RealmCallback;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslClientFactory;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslServerFactory;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.ServerTestBase;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TSimpleServer;
+import org.apache.thrift.server.TServer.Args;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestTSaslTransports extends TestCase {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TestTSaslTransports.class);
+
+ private static final String HOST = "localhost";
+ private static final String SERVICE = "thrift-test";
+ private static final String PRINCIPAL = "thrift-test-principal";
+ private static final String PASSWORD = "super secret password";
+ private static final String REALM = "thrift-test-realm";
+
+ private static final String UNWRAPPED_MECHANISM = "CRAM-MD5";
+ private static final Map<String, String> UNWRAPPED_PROPS = null;
+
+ private static final String WRAPPED_MECHANISM = "DIGEST-MD5";
+ private static final Map<String, String> WRAPPED_PROPS = new HashMap<String, String>();
+
+ static {
+ WRAPPED_PROPS.put(Sasl.QOP, "auth-int");
+ WRAPPED_PROPS.put("com.sun.security.sasl.digest.realm", REALM);
+ }
+
+ private static final String testMessage1 = "Hello, world! Also, four "
+ + "score and seven years ago our fathers brought forth on this "
+ + "continent a new nation, conceived in liberty, and dedicated to the "
+ + "proposition that all men are created equal.";
+
+ private static final String testMessage2 = "I have a dream that one day "
+ + "this nation will rise up and live out the true meaning of its creed: "
+ + "'We hold these truths to be self-evident, that all men are created equal.'";
+
+
+ private static class TestSaslCallbackHandler implements CallbackHandler {
+ private final String password;
+
+ public TestSaslCallbackHandler(String password) {
+ this.password = password;
+ }
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (Callback c : callbacks) {
+ if (c instanceof NameCallback) {
+ ((NameCallback) c).setName(PRINCIPAL);
+ } else if (c instanceof PasswordCallback) {
+ ((PasswordCallback) c).setPassword(password.toCharArray());
+ } else if (c instanceof AuthorizeCallback) {
+ ((AuthorizeCallback) c).setAuthorized(true);
+ } else if (c instanceof RealmCallback) {
+ ((RealmCallback) c).setText(REALM);
+ } else {
+ throw new UnsupportedCallbackException(c);
+ }
+ }
+ }
+ }
+
+ private class ServerThread extends Thread {
+ final String mechanism;
+ final Map<String, String> props;
+ volatile Throwable thrown;
+
+ public ServerThread(String mechanism, Map<String, String> props) {
+ this.mechanism = mechanism;
+ this.props = props;
+ }
+
+ public void run() {
+ try {
+ internalRun();
+ } catch (Throwable t) {
+ thrown = t;
+ }
+ }
+
+ private void internalRun() throws Exception {
+ TServerSocket serverSocket = new TServerSocket(
+ new TServerSocket.ServerSocketTransportArgs().
+ port(ServerTestBase.PORT));
+ try {
+ acceptAndWrite(serverSocket);
+ } finally {
+ serverSocket.close();
+ }
+ }
+
+ private void acceptAndWrite(TServerSocket serverSocket)
+ throws Exception {
+ TTransport serverTransport = serverSocket.accept();
+ TTransport saslServerTransport = new TSaslServerTransport(
+ mechanism, SERVICE, HOST,
+ props, new TestSaslCallbackHandler(PASSWORD), serverTransport);
+
+ saslServerTransport.open();
+
+ byte[] inBuf = new byte[testMessage1.getBytes().length];
+ // Deliberately read less than the full buffer to ensure
+ // that TSaslTransport is correctly buffering reads. This
+ // will fail for the WRAPPED test, if it doesn't work.
+ saslServerTransport.readAll(inBuf, 0, 5);
+ saslServerTransport.readAll(inBuf, 5, 10);
+ saslServerTransport.readAll(inBuf, 15, inBuf.length - 15);
+ LOGGER.debug("server got: {}", new String(inBuf));
+ assertEquals(new String(inBuf), testMessage1);
+
+ LOGGER.debug("server writing: {}", testMessage2);
+ saslServerTransport.write(testMessage2.getBytes());
+ saslServerTransport.flush();
+
+ saslServerTransport.close();
+ }
+ }
+
+ private void testSaslOpen(final String mechanism, final Map<String, String> props)
+ throws Exception {
+ ServerThread serverThread = new ServerThread(mechanism, props);
+ serverThread.start();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ah well.
+ }
+
+ try {
+ TSocket clientSocket = new TSocket(HOST, ServerTestBase.PORT);
+ TTransport saslClientTransport = new TSaslClientTransport(mechanism,
+ PRINCIPAL, SERVICE, HOST, props, new TestSaslCallbackHandler(PASSWORD), clientSocket);
+ saslClientTransport.open();
+ LOGGER.debug("client writing: {}", testMessage1);
+ saslClientTransport.write(testMessage1.getBytes());
+ saslClientTransport.flush();
+
+ byte[] inBuf = new byte[testMessage2.getBytes().length];
+ saslClientTransport.readAll(inBuf, 0, inBuf.length);
+ LOGGER.debug("client got: {}", new String(inBuf));
+ assertEquals(new String(inBuf), testMessage2);
+
+ TTransportException expectedException = null;
+ try {
+ saslClientTransport.open();
+ } catch (TTransportException e) {
+ expectedException = e;
+ }
+ assertNotNull(expectedException);
+
+ saslClientTransport.close();
+ } catch (Exception e) {
+ LOGGER.warn("Exception caught", e);
+ throw e;
+ } finally {
+ serverThread.interrupt();
+ try {
+ serverThread.join();
+ } catch (InterruptedException e) {
+ // Ah well.
+ }
+ assertNull(serverThread.thrown);
+ }
+ }
+
+ public void testUnwrappedOpen() throws Exception {
+ testSaslOpen(UNWRAPPED_MECHANISM, UNWRAPPED_PROPS);
+ }
+
+ public void testWrappedOpen() throws Exception {
+ testSaslOpen(WRAPPED_MECHANISM, WRAPPED_PROPS);
+ }
+
+ public void testAnonymousOpen() throws Exception {
+ testSaslOpen("ANONYMOUS", null);
+ }
+
+ /**
+ * Test that we get the proper exceptions thrown back the server when
+ * the client provides invalid password.
+ */
+ public void testBadPassword() throws Exception {
+ ServerThread serverThread = new ServerThread(UNWRAPPED_MECHANISM, UNWRAPPED_PROPS);
+ serverThread.start();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ah well.
+ }
+
+ boolean clientSidePassed = true;
+
+ try {
+ TSocket clientSocket = new TSocket(HOST, ServerTestBase.PORT);
+ TTransport saslClientTransport = new TSaslClientTransport(
+ UNWRAPPED_MECHANISM, PRINCIPAL, SERVICE, HOST, UNWRAPPED_PROPS,
+ new TestSaslCallbackHandler("NOT THE PASSWORD"), clientSocket);
+ saslClientTransport.open();
+ clientSidePassed = false;
+ fail("Was able to open transport with bad password");
+ } catch (TTransportException tte) {
+ LOGGER.error("Exception for bad password", tte);
+ assertNotNull(tte.getMessage());
+ assertTrue(tte.getMessage().contains("Invalid response"));
+
+ } finally {
+ serverThread.interrupt();
+ serverThread.join();
+
+ if (clientSidePassed) {
+ assertNotNull(serverThread.thrown);
+ assertTrue(serverThread.thrown.getMessage().contains("Invalid response"));
+ }
+ }
+ }
+
+ public void testWithServer() throws Exception {
+ new TestTSaslTransportsWithServer().testIt();
+ }
+
+ private static class TestTSaslTransportsWithServer extends ServerTestBase {
+
+ private Thread serverThread;
+ private TServer server;
+
+ @Override
+ public TTransport getClientTransport(TTransport underlyingTransport) throws Exception {
+ return new TSaslClientTransport(
+ WRAPPED_MECHANISM, PRINCIPAL, SERVICE, HOST, WRAPPED_PROPS,
+ new TestSaslCallbackHandler(PASSWORD), underlyingTransport);
+ }
+
+ @Override
+ public void startServer(final TProcessor processor, final TProtocolFactory protoFactory, final TTransportFactory factory) throws Exception {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ // Transport
+ TServerSocket socket = new TServerSocket(new TServerSocket.ServerSocketTransportArgs().port(PORT));
+
+ TTransportFactory factory = new TSaslServerTransport.Factory(
+ WRAPPED_MECHANISM, SERVICE, HOST, WRAPPED_PROPS,
+ new TestSaslCallbackHandler(PASSWORD));
+ server = new TSimpleServer(new Args(socket).processor(processor).transportFactory(factory).protocolFactory(protoFactory));
+
+ // Run it
+ LOGGER.debug("Starting the server on port {}", PORT);
+ server.serve();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+ };
+ serverThread.start();
+ Thread.sleep(1000);
+ }
+
+ @Override
+ public void stopServer() throws Exception {
+ server.stop();
+ try {
+ serverThread.join();
+ } catch (InterruptedException e) {}
+ }
+
+ }
+
+
+ /**
+ * Implementation of SASL ANONYMOUS, used for testing client-side
+ * initial responses.
+ */
+ private static class AnonymousClient implements SaslClient {
+ private final String username;
+ private boolean hasProvidedInitialResponse;
+
+ public AnonymousClient(String username) {
+ this.username = username;
+ }
+
+ public String getMechanismName() { return "ANONYMOUS"; }
+ public boolean hasInitialResponse() { return true; }
+ public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
+ if (hasProvidedInitialResponse) {
+ throw new SaslException("Already complete!");
+ }
+
+ hasProvidedInitialResponse = true;
+ return username.getBytes(StandardCharsets.UTF_8);
+ }
+ public boolean isComplete() { return hasProvidedInitialResponse; }
+ public byte[] unwrap(byte[] incoming, int offset, int len) {
+ throw new UnsupportedOperationException();
+ }
+ public byte[] wrap(byte[] outgoing, int offset, int len) {
+ throw new UnsupportedOperationException();
+ }
+ public Object getNegotiatedProperty(String propName) { return null; }
+ public void dispose() {}
+ }
+
+ private static class AnonymousServer implements SaslServer {
+ private String user;
+ public String getMechanismName() { return "ANONYMOUS"; }
+ public byte[] evaluateResponse(byte[] response) throws SaslException {
+ this.user = new String(response, StandardCharsets.UTF_8);
+ return null;
+ }
+ public boolean isComplete() { return user != null; }
+ public String getAuthorizationID() { return user; }
+ public byte[] unwrap(byte[] incoming, int offset, int len) {
+ throw new UnsupportedOperationException();
+ }
+ public byte[] wrap(byte[] outgoing, int offset, int len) {
+ throw new UnsupportedOperationException();
+ }
+ public Object getNegotiatedProperty(String propName) { return null; }
+ public void dispose() {}
+
+ }
+
+ public static class SaslAnonymousFactory
+ implements SaslClientFactory, SaslServerFactory {
+
+ public SaslClient createSaslClient(
+ String[] mechanisms, String authorizationId, String protocol,
+ String serverName, Map<String,?> props, CallbackHandler cbh)
+ {
+ for (String mech : mechanisms) {
+ if ("ANONYMOUS".equals(mech)) {
+ return new AnonymousClient(authorizationId);
+ }
+ }
+ return null;
+ }
+
+ public SaslServer createSaslServer(
+ String mechanism, String protocol, String serverName, Map<String,?> props, CallbackHandler cbh)
+ {
+ if ("ANONYMOUS".equals(mechanism)) {
+ return new AnonymousServer();
+ }
+ return null;
+ }
+ public String[] getMechanismNames(Map<String, ?> props) {
+ return new String[] { "ANONYMOUS" };
+ }
+ }
+
+ static {
+ java.security.Security.addProvider(new SaslAnonymousProvider());
+ }
+ public static class SaslAnonymousProvider extends java.security.Provider {
+ public SaslAnonymousProvider() {
+ super("ThriftSaslAnonymous", 1.0, "Thrift Anonymous SASL provider");
+ put("SaslClientFactory.ANONYMOUS", SaslAnonymousFactory.class.getName());
+ put("SaslServerFactory.ANONYMOUS", SaslAnonymousFactory.class.getName());
+ }
+ }
+
+ private static class MockTTransport extends TTransport {
+
+ byte[] badHeader = null;
+ private TMemoryInputTransport readBuffer = new TMemoryInputTransport();
+
+ public MockTTransport(int mode) {
+ if (mode==1) {
+ // Invalid status byte
+ badHeader = new byte[] { (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05 };
+ } else if (mode == 2) {
+ // Valid status byte, negative payload length
+ badHeader = new byte[] { (byte)0x01, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
+ } else if (mode == 3) {
+ // Valid status byte, excessively large, bogus payload length
+ badHeader = new byte[] { (byte)0x01, (byte)0x64, (byte)0x00, (byte)0x00, (byte)0x00 };
+ }
+ readBuffer.reset(badHeader);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public void open() throws TTransportException {}
+
+ @Override
+ public void close() {}
+
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ return readBuffer.read(buf, off, len);
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {}
+ }
+
+ public void testBadHeader() {
+ TSaslTransport saslTransport = new TSaslServerTransport(new MockTTransport(1));
+ try {
+ saslTransport.receiveSaslMessage();
+ fail("Should have gotten an error due to incorrect status byte value.");
+ } catch (TTransportException e) {
+ assertEquals(e.getMessage(), "Invalid status -1");
+ }
+ saslTransport = new TSaslServerTransport(new MockTTransport(2));
+ try {
+ saslTransport.receiveSaslMessage();
+ fail("Should have gotten an error due to negative payload length.");
+ } catch (TTransportException e) {
+ assertEquals(e.getMessage(), "Invalid payload header length: -1");
+ }
+ saslTransport = new TSaslServerTransport(new MockTTransport(3));
+ try {
+ saslTransport.receiveSaslMessage();
+ fail("Should have gotten an error due to bogus (large) payload length.");
+ } catch (TTransportException e) {
+ assertEquals(e.getMessage(), "Invalid payload header length: 1677721600");
+ }
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java
new file mode 100644
index 000000000..7b880f499
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java
@@ -0,0 +1,74 @@
+/*
+ * 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.thrift.transport;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+public class TestTSimpleFileTransport extends TestCase {
+ public void testFresh() throws Exception {
+ //Test write side
+ Path tempFilePathName = Files.createTempFile("TSimpleFileTransportTest", null);
+ Files.delete(tempFilePathName);
+ byte[] input_buf = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TSimpleFileTransport trans_write = new TSimpleFileTransport(tempFilePathName.toString(),false, true, false);
+ assert (!trans_write.isOpen());
+ trans_write.open();
+ assert(trans_write.isOpen());
+ trans_write.write(input_buf);
+ trans_write.write(input_buf,2,2);
+ trans_write.flush();
+ trans_write.close();
+
+ //Test read side
+ TSimpleFileTransport trans = new TSimpleFileTransport(tempFilePathName.toString(),true, false);
+ assert(trans.isOpen());
+
+ //Simple file trans provides no buffer access
+ assert(0 == trans.getBufferPosition());
+ assert(null == trans.getBuffer());
+ assert(-1 == trans.getBytesRemainingInBuffer());
+
+ //Test file pointer operations
+ assert(0 == trans.getFilePointer());
+ assert(12 == trans.length());
+
+ final int BUFSIZ = 4;
+ byte[] buf1 = new byte[BUFSIZ];
+ trans.readAll(buf1, 0, BUFSIZ);
+ assert(BUFSIZ == trans.getFilePointer());
+ assert(Arrays.equals(new byte[]{1, 2, 3, 4}, buf1));
+
+ int bytesRead = trans.read(buf1, 0, BUFSIZ);
+ assert(bytesRead > 0);
+ for (int i = 0; i < bytesRead; ++i) {
+ assert(buf1[i] == i+5);
+ }
+
+ trans.seek(0);
+ assert(0 == trans.getFilePointer());
+ trans.readAll(buf1, 0, BUFSIZ);
+ assert(Arrays.equals(new byte[]{1, 2, 3, 4}, buf1));
+ assert(BUFSIZ == trans.getFilePointer());
+ trans.close();
+ Files.delete(tempFilePathName);
+ }
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTZlibTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTZlibTransport.java
new file mode 100644
index 000000000..3d7f9c1c9
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/TestTZlibTransport.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.thrift.transport;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+import junit.framework.TestCase;
+
+public class TestTZlibTransport extends TestCase {
+
+ protected TTransport getTransport(TTransport underlying) {
+ return new TZlibTransport(underlying);
+ }
+
+ public static byte[] byteSequence(int start, int end) {
+ byte[] result = new byte[end-start+1];
+ for (int i = 0; i <= (end-start); i++) {
+ result[i] = (byte)(start+i);
+ }
+ return result;
+ }
+
+ public void testClose() throws TTransportException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ WriteCountingTransport countingTrans = new WriteCountingTransport(new TIOStreamTransport(new BufferedOutputStream
+ (baos)));
+ TTransport trans = getTransport(countingTrans);
+ trans.write(byteSequence(0, 245));
+ countingTrans.close();
+ trans.close();
+ }
+
+ public void testCloseOpen() throws TTransportException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ TTransport trans = getTransport(new TIOStreamTransport(baos));
+ byte[] uncompressed = byteSequence(0, 245);
+ trans.write(uncompressed);
+ trans.close();
+ final byte[] compressed = baos.toByteArray();
+
+ final byte[] buf = new byte[255];
+ TTransport transRead = getTransport(new TIOStreamTransport(new ByteArrayInputStream(compressed)));
+ int readBytes = transRead.read(buf, 0, buf.length);
+ assertEquals(uncompressed.length, readBytes);
+ transRead.close();
+ }
+
+ public void testRead() throws IOException, TTransportException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(baos);
+ DataOutputStream dos = new DataOutputStream(deflaterOutputStream);
+ dos.write(byteSequence(0, 49));
+ dos.write(byteSequence(0, 219));
+
+ deflaterOutputStream.finish();
+
+ TMemoryBuffer membuf = new TMemoryBuffer(0);
+ membuf.write(baos.toByteArray());
+
+ ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+ TTransport trans = getTransport(countTrans);
+
+ byte[] readBuf = new byte[10];
+ trans.read(readBuf, 0, 10);
+ assertTrue(Arrays.equals(readBuf, byteSequence(0,9)));
+ assertEquals(1, countTrans.readCount);
+
+ trans.read(readBuf, 0, 10);
+ assertTrue(Arrays.equals(readBuf, byteSequence(10,19)));
+ assertEquals(1, countTrans.readCount);
+
+ assertEquals(30, trans.read(new byte[30], 0, 30));
+ assertEquals(1, countTrans.readCount);
+
+ readBuf = new byte[220];
+ assertEquals(220, trans.read(readBuf, 0, 220));
+ assertTrue(Arrays.equals(readBuf, byteSequence(0, 219)));
+ assertEquals(1, countTrans.readCount);
+ }
+
+ public void testWrite() throws TTransportException, IOException, DataFormatException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ WriteCountingTransport countingTrans = new WriteCountingTransport(new TIOStreamTransport(new BufferedOutputStream(baos)));
+ TTransport trans = getTransport(countingTrans);
+
+ trans.write(byteSequence(0, 100));
+ assertEquals(1, countingTrans.writeCount);
+ trans.write(byteSequence(101, 200));
+ trans.write(byteSequence(201, 255));
+ assertEquals(1, countingTrans.writeCount);
+
+ trans.flush();
+ assertEquals(2, countingTrans.writeCount);
+
+ trans.write(byteSequence(0, 245));
+ trans.flush();
+ assertEquals(3, countingTrans.writeCount);
+
+ DataInputStream din = new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(baos.toByteArray())));
+ byte[] buf = new byte[256];
+ int n = din.read(buf, 0, 256);
+ assertEquals(n, 256);
+ assertTrue(Arrays.equals(byteSequence(0, 255), buf));
+
+ buf = new byte[246];
+ n = din.read(buf, 0, 246);
+ assertEquals(n, 246);
+ for (int i = 0; i<buf.length; i++) {
+ assertEquals("for "+i, byteSequence(0,245)[i], buf[i]);
+ }
+
+ assertTrue(Arrays.equals(byteSequence(0,245), buf));
+ }
+
+}
diff --git a/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/WriteCountingTransport.java b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/WriteCountingTransport.java
new file mode 100644
index 000000000..358f5c6eb
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/java/test/org/apache/thrift/transport/WriteCountingTransport.java
@@ -0,0 +1,54 @@
+/*
+ * 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.thrift.transport;
+
+
+public class WriteCountingTransport extends TTransport {
+ public int writeCount = 0;
+ private final TTransport trans;
+
+ public WriteCountingTransport(TTransport underlying) {
+ trans = underlying;
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean isOpen() {return true;}
+
+ @Override
+ public void open() throws TTransportException {}
+
+ @Override
+ public int read(byte[] buf, int off, int len) throws TTransportException {
+ return 0;
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) throws TTransportException {
+ writeCount ++;
+ trans.write(buf, off, len);
+ }
+
+ @Override
+ public void flush() throws TTransportException {
+ trans.flush();
+ }
+} \ No newline at end of file