7
7
import okhttp3 .HttpUrl ;
8
8
import okhttp3 .MediaType ;
9
9
import okhttp3 .OkHttpClient ;
10
+ import okhttp3 .Request ;
10
11
import okhttp3 .RequestBody ;
11
12
import okhttp3 .ResponseBody ;
12
13
import okhttp3 .logging .HttpLoggingInterceptor ;
25
26
import org .influxdb .dto .QueryResult ;
26
27
import org .influxdb .impl .BatchProcessor .HttpBatchEntry ;
27
28
import org .influxdb .impl .BatchProcessor .UdpBatchEntry ;
29
+ import org .influxdb .msgpack .MessagePackConverterFactory ;
30
+ import org .influxdb .msgpack .MessagePackTraverser ;
31
+
28
32
import retrofit2 .Call ;
29
33
import retrofit2 .Callback ;
34
+ import retrofit2 .Converter .Factory ;
30
35
import retrofit2 .Response ;
31
36
import retrofit2 .Retrofit ;
32
37
import retrofit2 .converter .moshi .MoshiConverterFactory ;
33
38
34
39
import java .io .EOFException ;
35
40
import java .io .IOException ;
41
+ import java .io .InputStream ;
36
42
import java .net .DatagramPacket ;
37
43
import java .net .DatagramSocket ;
38
44
import java .net .InetAddress ;
56
62
*/
57
63
public class InfluxDBImpl implements InfluxDB {
58
64
65
+ private static final String APPLICATION_MSGPACK = "application/x-msgpack" ;
66
+
59
67
static final okhttp3 .MediaType MEDIA_TYPE_STRING = MediaType .parse ("text/plain" );
60
68
61
69
private static final String SHOW_DATABASE_COMMAND_ENCODED = Query .encode ("SHOW DATABASES" );
@@ -82,15 +90,28 @@ public class InfluxDBImpl implements InfluxDB {
82
90
private final HttpLoggingInterceptor loggingInterceptor ;
83
91
private final GzipRequestInterceptor gzipRequestInterceptor ;
84
92
private LogLevel logLevel = LogLevel .NONE ;
85
- private JsonAdapter <QueryResult > adapter ;
86
93
private String database ;
87
94
private String retentionPolicy = "autogen" ;
88
95
private ConsistencyLevel consistency = ConsistencyLevel .ONE ;
96
+ private final ChunkProccesor chunkProccesor ;
89
97
90
- public InfluxDBImpl (final String url , final String username , final String password ,
91
- final OkHttpClient .Builder client ) {
92
- super ();
93
- Moshi moshi = new Moshi .Builder ().build ();
98
+ /**
99
+ * Constructs a new {@code InfluxDBImpl}.
100
+ *
101
+ * @param url
102
+ * The InfluxDB server API URL
103
+ * @param username
104
+ * The InfluxDB user name
105
+ * @param password
106
+ * The InfluxDB user password
107
+ * @param client
108
+ * The OkHttp Client Builder
109
+ * @param responseFormat
110
+ * The {@code ResponseFormat} to use for response from InfluxDB
111
+ * server
112
+ */
113
+ public InfluxDBImpl (final String url , final String username , final String password , final OkHttpClient .Builder client ,
114
+ final ResponseFormat responseFormat ) {
94
115
this .hostAddress = parseHostAddress (url );
95
116
this .username = username ;
96
117
this .password = password ;
@@ -99,38 +120,72 @@ public InfluxDBImpl(final String url, final String username, final String passwo
99
120
setLogLevel (LOG_LEVEL );
100
121
101
122
this .gzipRequestInterceptor = new GzipRequestInterceptor ();
102
- this .retrofit = new Retrofit .Builder ()
103
- .baseUrl (url )
104
- .client (client .addInterceptor (loggingInterceptor ).addInterceptor (gzipRequestInterceptor ).build ())
105
- .addConverterFactory (MoshiConverterFactory .create ())
123
+ client .addInterceptor (loggingInterceptor ).addInterceptor (gzipRequestInterceptor );
124
+
125
+ Factory converterFactory = null ;
126
+ switch (responseFormat ) {
127
+ case MSGPACK :
128
+ client .addInterceptor (chain -> {
129
+ Request request = chain .request ().newBuilder ().addHeader ("Accept" , APPLICATION_MSGPACK )
130
+ .addHeader ("Accept-Encoding" , "identity" ).build ();
131
+ return chain .proceed (request );
132
+ });
133
+
134
+ converterFactory = MessagePackConverterFactory .create ();
135
+ chunkProccesor = new MessagePackChunkProccesor ();
136
+ break ;
137
+ case JSON :
138
+ default :
139
+ converterFactory = MoshiConverterFactory .create ();
140
+
141
+ Moshi moshi = new Moshi .Builder ().build ();
142
+ JsonAdapter <QueryResult > adapter = moshi .adapter (QueryResult .class );
143
+ chunkProccesor = new JSONChunkProccesor (adapter );
144
+ break ;
145
+ }
146
+
147
+ this .retrofit = new Retrofit .Builder ().baseUrl (url ).client (client .build ()).addConverterFactory (converterFactory )
106
148
.build ();
107
149
this .influxDBService = this .retrofit .create (InfluxDBService .class );
108
- this .adapter = moshi .adapter (QueryResult .class );
109
- }
110
-
111
- InfluxDBImpl (final String url , final String username , final String password , final OkHttpClient .Builder client ,
112
- final InfluxDBService influxDBService , final JsonAdapter <QueryResult > adapter ) {
113
- super ();
114
- this .hostAddress = parseHostAddress (url );
115
- this .username = username ;
116
- this .password = password ;
117
-
118
- this .loggingInterceptor = new HttpLoggingInterceptor ();
119
- setLogLevel (LOG_LEVEL );
120
-
121
- this .gzipRequestInterceptor = new GzipRequestInterceptor ();
122
- this .retrofit = new Retrofit .Builder ()
123
- .baseUrl (url )
124
- .client (client .addInterceptor (loggingInterceptor ).addInterceptor (gzipRequestInterceptor ).build ())
125
- .addConverterFactory (MoshiConverterFactory .create ())
126
- .build ();
127
- this .influxDBService = influxDBService ;
128
- this .adapter = adapter ;
150
+
151
+ if (ResponseFormat .MSGPACK .equals (responseFormat )) {
152
+ String [] versionNumbers = version ().split ("\\ ." );
153
+ final int major = Integer .parseInt (versionNumbers [0 ]);
154
+ final int minor = Integer .parseInt (versionNumbers [1 ]);
155
+ final int fromMinor = 4 ;
156
+ if ((major < 2 ) && ((major != 1 ) || (minor < fromMinor ))) {
157
+ throw new InfluxDBException ("MessagePack format is only supported from InfluxDB version 1.4 and later" );
158
+ }
129
159
}
160
+ }
130
161
131
162
public InfluxDBImpl (final String url , final String username , final String password ,
132
- final OkHttpClient .Builder client , final String database ,
133
- final String retentionPolicy , final ConsistencyLevel consistency ) {
163
+ final OkHttpClient .Builder client ) {
164
+ this (url , username , password , client , ResponseFormat .JSON );
165
+
166
+ }
167
+
168
+ InfluxDBImpl (final String url , final String username , final String password , final OkHttpClient .Builder client ,
169
+ final InfluxDBService influxDBService , final JsonAdapter <QueryResult > adapter ) {
170
+ super ();
171
+ this .hostAddress = parseHostAddress (url );
172
+ this .username = username ;
173
+ this .password = password ;
174
+
175
+ this .loggingInterceptor = new HttpLoggingInterceptor ();
176
+ setLogLevel (LOG_LEVEL );
177
+
178
+ this .gzipRequestInterceptor = new GzipRequestInterceptor ();
179
+ this .retrofit = new Retrofit .Builder ().baseUrl (url )
180
+ .client (client .addInterceptor (loggingInterceptor ).addInterceptor (gzipRequestInterceptor ).build ())
181
+ .addConverterFactory (MoshiConverterFactory .create ()).build ();
182
+ this .influxDBService = influxDBService ;
183
+
184
+ chunkProccesor = new JSONChunkProccesor (adapter );
185
+ }
186
+
187
+ public InfluxDBImpl (final String url , final String username , final String password , final OkHttpClient .Builder client ,
188
+ final String database , final String retentionPolicy , final ConsistencyLevel consistency ) {
134
189
this (url , username , password , client );
135
190
136
191
setConsistency (consistency );
@@ -493,32 +548,26 @@ public void query(final Query query, final int chunkSize, final Consumer<QueryRe
493
548
query .getDatabase (), query .getCommandWithUrlEncoded (), chunkSize );
494
549
}
495
550
496
- call .enqueue (new Callback <ResponseBody >() {
497
- @ Override
498
- public void onResponse (final Call <ResponseBody > call , final Response <ResponseBody > response ) {
499
- try {
500
- if (response .isSuccessful ()) {
501
- BufferedSource source = response .body ().source ();
502
- while (true ) {
503
- QueryResult result = InfluxDBImpl .this .adapter .fromJson (source );
504
- if (result != null ) {
505
- consumer .accept (result );
506
- }
507
- }
508
- }
509
- try (ResponseBody errorBody = response .errorBody ()) {
510
- throw new InfluxDBException (errorBody .string ());
511
- }
512
- } catch (EOFException e ) {
513
- QueryResult queryResult = new QueryResult ();
514
- queryResult .setError ("DONE" );
515
- consumer .accept (queryResult );
516
- } catch (IOException e ) {
517
- QueryResult queryResult = new QueryResult ();
518
- queryResult .setError (e .toString ());
519
- consumer .accept (queryResult );
520
- }
551
+ call .enqueue (new Callback <ResponseBody >() {
552
+ @ Override
553
+ public void onResponse (final Call <ResponseBody > call , final Response <ResponseBody > response ) {
554
+ try {
555
+ if (response .isSuccessful ()) {
556
+ ResponseBody chunkedBody = response .body ();
557
+ chunkProccesor .process (chunkedBody , consumer );
558
+ } else {
559
+ // REVIEW: must be handled consistently with IOException.
560
+ ResponseBody errorBody = response .errorBody ();
561
+ if (errorBody != null ) {
562
+ throw new InfluxDBException (errorBody .string ());
521
563
}
564
+ }
565
+ } catch (IOException e ) {
566
+ QueryResult queryResult = new QueryResult ();
567
+ queryResult .setError (e .toString ());
568
+ consumer .accept (queryResult );
569
+ }
570
+ }
522
571
523
572
@ Override
524
573
public void onFailure (final Call <ResponseBody > call , final Throwable t ) {
@@ -752,4 +801,44 @@ public void dropRetentionPolicy(final String rpName, final String database) {
752
801
Query .encode (queryBuilder .toString ())));
753
802
}
754
803
804
+ private interface ChunkProccesor {
805
+ void process (ResponseBody chunkedBody , Consumer <QueryResult > consumer ) throws IOException ;
806
+ }
807
+
808
+ private class MessagePackChunkProccesor implements ChunkProccesor {
809
+ @ Override
810
+ public void process (final ResponseBody chunkedBody , final Consumer <QueryResult > consumer ) throws IOException {
811
+ MessagePackTraverser traverser = new MessagePackTraverser ();
812
+ try (InputStream is = chunkedBody .byteStream ()) {
813
+ for (QueryResult result : traverser .traverse (is )) {
814
+ consumer .accept (result );
815
+ }
816
+ }
817
+ }
818
+ }
819
+
820
+ private class JSONChunkProccesor implements ChunkProccesor {
821
+ private JsonAdapter <QueryResult > adapter ;
822
+
823
+ public JSONChunkProccesor (final JsonAdapter <QueryResult > adapter ) {
824
+ this .adapter = adapter ;
825
+ }
826
+
827
+ @ Override
828
+ public void process (final ResponseBody chunkedBody , final Consumer <QueryResult > consumer ) throws IOException {
829
+ try {
830
+ BufferedSource source = chunkedBody .source ();
831
+ while (true ) {
832
+ QueryResult result = adapter .fromJson (source );
833
+ if (result != null ) {
834
+ consumer .accept (result );
835
+ }
836
+ }
837
+ } catch (EOFException e ) {
838
+ QueryResult queryResult = new QueryResult ();
839
+ queryResult .setError ("DONE" );
840
+ consumer .accept (queryResult );
841
+ }
842
+ }
843
+ }
755
844
}
0 commit comments