15
15
*/
16
16
package com .google .cloud .bigtable .admin .v2 ;
17
17
18
+ import com .google .api .core .ApiFunction ;
19
+ import com .google .api .core .ApiFuture ;
20
+ import com .google .api .core .ApiFutures ;
21
+ import com .google .bigtable .admin .v2 .DeleteInstanceRequest ;
22
+ import com .google .bigtable .admin .v2 .GetInstanceRequest ;
23
+ import com .google .bigtable .admin .v2 .InstanceName ;
24
+ import com .google .bigtable .admin .v2 .ListInstancesRequest ;
25
+ import com .google .bigtable .admin .v2 .ListInstancesResponse ;
26
+ import com .google .bigtable .admin .v2 .LocationName ;
18
27
import com .google .bigtable .admin .v2 .ProjectName ;
28
+ import com .google .cloud .bigtable .admin .v2 .models .CreateInstanceRequest ;
29
+ import com .google .cloud .bigtable .admin .v2 .models .Instance ;
30
+ import com .google .cloud .bigtable .admin .v2 .models .PartialListInstancesException ;
31
+ import com .google .cloud .bigtable .admin .v2 .models .UpdateInstanceRequest ;
19
32
import com .google .cloud .bigtable .admin .v2 .stub .BigtableInstanceAdminStub ;
33
+ import com .google .common .base .Verify ;
34
+ import com .google .common .collect .ImmutableList ;
35
+ import com .google .common .util .concurrent .Futures ;
36
+ import com .google .common .util .concurrent .MoreExecutors ;
37
+ import com .google .common .util .concurrent .UncheckedExecutionException ;
38
+ import com .google .protobuf .Empty ;
20
39
import java .io .IOException ;
40
+ import java .util .List ;
41
+ import java .util .Objects ;
21
42
import javax .annotation .Nonnull ;
22
43
23
44
/**
29
50
* <pre>{@code
30
51
* try(BigtableInstanceAdminClient client = BigtableInstanceAdminClient.create(ProjectName.of("my-project"))) {
31
52
* CreateInstanceRequest request = CreateInstanceRequest.of("my-instance")
32
- * .addFamily("cf1")
33
- * .addFamily("cf2", GCRULES.maxVersions(10))
34
- * .addSplit(ByteString.copyFromUtf8("b"))
35
- * .addSplit(ByteString.copyFromUtf8("q"));
53
+ * .addCluster("my-cluster", "us-east1-c", 3, StorageType.SSD);
36
54
*
37
- * client.createInstance(request);
55
+ * Instance instance = client.createInstance(request);
38
56
* }
39
57
* }</pre>
40
58
*
48
66
*
49
67
* <pre>{@code
50
68
* BigtableInstanceAdminSettings settings = BigtableInstanceAdminSettings.newBuilder()
51
- * .setProjectName(ProjectName.of("[PROJECT] "))
69
+ * .setProjectName(ProjectName.of("my-project "))
52
70
* .setCredentialsProvider(FixedCredentialsProvider.create(myCredentials))
53
71
* .build();
54
72
*
59
77
*
60
78
* <pre>{@code
61
79
* BigtableInstanceAdminSettings settings = BigtableInstanceAdminSettings.newBuilder()
62
- * .setProjectName(ProjectName.of("[PROJECT] "))
80
+ * .setProjectName(ProjectName.of("my-project "))
63
81
* .setEndpoint(myEndpoint)
64
82
* .build();
65
83
*
@@ -82,7 +100,7 @@ public static BigtableInstanceAdminClient create(@Nonnull BigtableInstanceAdminS
82
100
return create (settings .getProjectName (), settings .getStubSettings ().createStub ());
83
101
}
84
102
85
- /** Constructs an instance of BigtableInstanceAdminClient with the given Projectname and stub. */
103
+ /** Constructs an instance of BigtableInstanceAdminClient with the given ProjectName and stub. */
86
104
public static BigtableInstanceAdminClient create (@ Nonnull ProjectName projectName ,
87
105
@ Nonnull BigtableInstanceAdminStub stub ) {
88
106
return new BigtableInstanceAdminClient (projectName , stub );
@@ -96,6 +114,7 @@ private BigtableInstanceAdminClient(
96
114
}
97
115
98
116
/** Gets the ProjectName this client is associated with. */
117
+ @ SuppressWarnings ("WeakerAccess" )
99
118
public ProjectName getProjectName () {
100
119
return projectName ;
101
120
}
@@ -105,4 +124,304 @@ public ProjectName getProjectName() {
105
124
public void close () {
106
125
stub .close ();
107
126
}
127
+
128
+ /**
129
+ * Creates a new instance and returns its representation.
130
+ *
131
+ * <p>Sample code:
132
+ *
133
+ * <pre>{@code
134
+ * Instance instance = client.createInstance(
135
+ * CreateInstanceRequest.of("my-instance")
136
+ * .addCluster("my-cluster", "us-east1-c", 3, StorageType.SSD)
137
+ * );
138
+ * }</pre>
139
+ *
140
+ * @see CreateInstanceRequest for details.
141
+ */
142
+ @ SuppressWarnings ("WeakerAccess" )
143
+ public Instance createInstance (CreateInstanceRequest request ) {
144
+ return awaitFuture (createInstanceAsync (request ));
145
+ }
146
+
147
+ /**
148
+ * Asynchronously creates a new instance and returns its representation wrapped in a future.
149
+ *
150
+ * <p>Sample code:
151
+ *
152
+ * <pre>{@code
153
+ * ApiFuture<Instance> instanceFuture = client.createInstanceAsync(
154
+ * CreateInstanceRequest.of("my-instance")
155
+ * .addCluster("my-cluster", "us-east1-c", 3, StorageType.SSD)
156
+ * );
157
+ *
158
+ * Instance instance = instanceFuture.get();
159
+ * }</pre>
160
+ *
161
+ * @see CreateInstanceRequest for details.
162
+ */
163
+ @ SuppressWarnings ("WeakerAccess" )
164
+ public ApiFuture <Instance > createInstanceAsync (CreateInstanceRequest request ) {
165
+ return ApiFutures .transform (
166
+ stub .createInstanceOperationCallable ().futureCall (request .toProto (projectName )),
167
+ new ApiFunction <com .google .bigtable .admin .v2 .Instance , Instance >() {
168
+ @ Override
169
+ public Instance apply (com .google .bigtable .admin .v2 .Instance proto ) {
170
+ return Instance .fromProto (proto );
171
+ }
172
+ },
173
+ MoreExecutors .directExecutor ());
174
+ }
175
+
176
+ /**
177
+ * Updates a new instance and returns its representation.
178
+ *
179
+ * <p>Sample code:
180
+ *
181
+ * <pre>{@code
182
+ * Instance instance = client.updateInstance(
183
+ * UpdateInstanceRequest.of("my-instance")
184
+ * .setProductionType()
185
+ * );
186
+ * }</pre>
187
+ *
188
+ * @see UpdateInstanceRequest for details.
189
+ */
190
+ @ SuppressWarnings ("WeakerAccess" )
191
+ public Instance updateInstance (UpdateInstanceRequest request ) {
192
+ return awaitFuture (updateInstanceAsync (request ));
193
+ }
194
+
195
+ /**
196
+ * Asynchronously updates a new instance and returns its representation wrapped in a future.
197
+ *
198
+ * <p>Sample code:
199
+ *
200
+ * <pre>{@code
201
+ * ApiFuture<Instance> instanceFuture = client.updateInstanceAsync(
202
+ * UpdateInstanceRequest.of("my-instance")
203
+ * .setProductionType()
204
+ * );
205
+ *
206
+ * Instance instance = instanceFuture.get();
207
+ * }</pre>
208
+ *
209
+ * @see UpdateInstanceRequest for details.
210
+ */
211
+ @ SuppressWarnings ("WeakerAccess" )
212
+ public ApiFuture <Instance > updateInstanceAsync (UpdateInstanceRequest request ) {
213
+ return ApiFutures .transform (
214
+ stub .partialUpdateInstanceOperationCallable ().futureCall (request .toProto (projectName )),
215
+ new ApiFunction <com .google .bigtable .admin .v2 .Instance , Instance >() {
216
+ @ Override
217
+ public Instance apply (com .google .bigtable .admin .v2 .Instance proto ) {
218
+ return Instance .fromProto (proto );
219
+ }
220
+ },
221
+ MoreExecutors .directExecutor ());
222
+ }
223
+
224
+ /**
225
+ * Get the instance representation by ID.
226
+ *
227
+ * <p>Sample code:
228
+ *
229
+ * <pre>{@code
230
+ * Instance instance = client.getInstance("my-instance");
231
+ * }</pre>
232
+ */
233
+ @ SuppressWarnings ("WeakerAccess" )
234
+ public Instance getInstance (String id ) {
235
+ return awaitFuture (getInstanceAsync (id ));
236
+ }
237
+
238
+ /**
239
+ * Asynchronously gets the instance representation by ID wrapped in a future.
240
+ *
241
+ * <p>Sample code:
242
+ *
243
+ * <pre>{@code
244
+ * ApiFuture<Instance> instanceFuture = client.getInstanceAsync("my-instance");
245
+ * Instance instance = instanceFuture.get();
246
+ * }</pre>
247
+ */
248
+ @ SuppressWarnings ("WeakerAccess" )
249
+ public ApiFuture <Instance > getInstanceAsync (String instanceId ) {
250
+ InstanceName name = InstanceName .of (projectName .getProject (), instanceId );
251
+
252
+ GetInstanceRequest request = GetInstanceRequest .newBuilder ()
253
+ .setName (name .toString ())
254
+ .build ();
255
+
256
+ return ApiFutures .transform (
257
+ stub .getInstanceCallable ().futureCall (request ),
258
+ new ApiFunction <com .google .bigtable .admin .v2 .Instance , Instance >() {
259
+ @ Override
260
+ public Instance apply (com .google .bigtable .admin .v2 .Instance proto ) {
261
+ return Instance .fromProto (proto );
262
+ }
263
+ },
264
+ MoreExecutors .directExecutor ());
265
+ }
266
+
267
+ /**
268
+ * Lists all of the instances in the current project.
269
+ *
270
+ * <p>This method will throw a {@link PartialListInstancesException} when any zone is
271
+ * unavailable. If partial listing are ok, the exception can be caught and inspected.
272
+ *
273
+ * <p>Sample code:
274
+ *
275
+ * <pre>{@code
276
+ * try {
277
+ * List<Instance> instances = client.listInstances();
278
+ * } catch (PartialListInstancesException e) {
279
+ * System.out.println("The following zones are unavailable: " + e.getUnavailableZones());
280
+ * System.out.println("But the following instances are reachable: " + e.getInstances());
281
+ * }
282
+ * }</pre>
283
+ */
284
+ @ SuppressWarnings ("WeakerAccess" )
285
+ public List <Instance > listInstances () {
286
+ return awaitFuture (listInstancesAsync ());
287
+ }
288
+
289
+ /**
290
+ * Asynchronously lists all of the instances in the current project.
291
+ *
292
+ * <p>This method will throw a {@link PartialListInstancesException} when any zone is
293
+ * unavailable.
294
+ * If partial listing are ok, the exception can be caught and inspected.
295
+ *
296
+ * <p>Sample code:
297
+ *
298
+ * <pre>{@code
299
+ * ApiFuture<Instance> instancesFuture = client.listInstancesAsync();
300
+ *
301
+ * ApiFutures.addCallback(instancesFuture, new ApiFutureCallback<List<Instance>>() {
302
+ * public void onFailure(Throwable t) {
303
+ * if (t instanceof PartialListInstancesException) {
304
+ * PartialListInstancesException partialError = (PartialListInstancesException)t;
305
+ * System.out.println("The following zones are unavailable: " + partialError.getUnavailableZones());
306
+ * System.out.println("But the following instances are reachable: " + partialError.getInstances());
307
+ * } else {
308
+ * t.printStackTrace();
309
+ * }
310
+ * }
311
+ *
312
+ * public void onSuccess(List<Instance> result) {
313
+ * System.out.println("Found a complete set of instances: " + result);
314
+ * }
315
+ * }, MoreExecutors.directExecutor());
316
+ * }</pre>
317
+ */
318
+ @ SuppressWarnings ("WeakerAccess" )
319
+ public ApiFuture <List <Instance >> listInstancesAsync () {
320
+ ListInstancesRequest request = ListInstancesRequest .newBuilder ()
321
+ .setParent (projectName .toString ())
322
+ .build ();
323
+
324
+ ApiFuture <ListInstancesResponse > responseFuture = stub .listInstancesCallable ()
325
+ .futureCall (request );
326
+
327
+ return ApiFutures
328
+ .transform (responseFuture , new ApiFunction <ListInstancesResponse , List <Instance >>() {
329
+ @ Override
330
+ public List <Instance > apply (ListInstancesResponse proto ) {
331
+ // NOTE: pagination is intentionally ignored. The server does not implement it and never
332
+ // will.
333
+ Verify .verify (proto .getNextPageToken ().isEmpty (),
334
+ "Server returned an unexpected paginated response" );
335
+
336
+ ImmutableList .Builder <Instance > instances = ImmutableList .builder ();
337
+
338
+ for (com .google .bigtable .admin .v2 .Instance protoInstance : proto .getInstancesList ()) {
339
+ instances .add (Instance .fromProto (protoInstance ));
340
+ }
341
+
342
+ ImmutableList .Builder <String > failedZones = ImmutableList .builder ();
343
+ for (String locationStr : proto .getFailedLocationsList ()) {
344
+ LocationName fullLocation = Objects .requireNonNull (LocationName .parse (locationStr ));
345
+ failedZones .add (fullLocation .getLocation ());
346
+ }
347
+
348
+ if (!failedZones .build ().isEmpty ()) {
349
+ throw new PartialListInstancesException (failedZones .build (), instances .build ());
350
+ }
351
+
352
+ return instances .build ();
353
+ }
354
+ }, MoreExecutors .directExecutor ());
355
+ }
356
+
357
+ /**
358
+ * Deletes the specified instance.
359
+ *
360
+ * <p>Sample code:
361
+ *
362
+ * <pre>{@code
363
+ * client.deleteInstance("my-instance");
364
+ * }</pre>
365
+ */
366
+ @ SuppressWarnings ("WeakerAccess" )
367
+ public void deleteInstance (String instanceId ) {
368
+ awaitFuture (deleteInstanceAsync (instanceId ));
369
+ }
370
+
371
+ /**
372
+ * Asynchronously deletes the specified instance.
373
+ *
374
+ * <p>Sample code:
375
+ *
376
+ * <pre>{@code
377
+ * ApiFuture<Void> deleteFuture = client.deleteInstance("my-instance");
378
+ * deleteFuture.get();
379
+ * }</pre>
380
+ */
381
+ @ SuppressWarnings ("WeakerAccess" )
382
+ public ApiFuture <Void > deleteInstanceAsync (String instanceId ) {
383
+ InstanceName instanceName = InstanceName .of (projectName .getProject (), instanceId );
384
+
385
+ DeleteInstanceRequest request = DeleteInstanceRequest .newBuilder ()
386
+ .setName (instanceName .toString ())
387
+ .build ();
388
+
389
+ return ApiFutures .transform (stub .deleteInstanceCallable ().futureCall (request ),
390
+ new ApiFunction <Empty , Void >() {
391
+ @ Override
392
+ public Void apply (Empty input ) {
393
+ return null ;
394
+ }
395
+ },
396
+ MoreExecutors .directExecutor ()
397
+ );
398
+ }
399
+
400
+ /**
401
+ * Awaits the result of a future, taking care to propagate errors while maintaining the call site
402
+ * in a suppressed exception. This allows semantic errors to be caught across threads, while
403
+ * preserving the call site in the error. The caller's stacktrace will be made available as a
404
+ * suppressed exception.
405
+ */
406
+ // TODO(igorbernstein2): try to move this into gax
407
+ private <T > T awaitFuture (ApiFuture <T > future ) {
408
+ RuntimeException error ;
409
+
410
+ try {
411
+ return Futures .getUnchecked (future );
412
+ } catch (UncheckedExecutionException e ) {
413
+ if (e .getCause () instanceof RuntimeException ) {
414
+ error = (RuntimeException ) e .getCause ();
415
+ } else {
416
+ error = e ;
417
+ }
418
+ } catch (RuntimeException e ) {
419
+ error = e ;
420
+ }
421
+
422
+ // Add the caller's stack as a suppressed exception
423
+ error .addSuppressed (new RuntimeException ("Encountered error while awaiting future" ));
424
+
425
+ throw error ;
426
+ }
108
427
}
0 commit comments