Skip to content

Commit e29f635

Browse files
committed
Add whenDone method and CompletionCallback to Compute Operation
1 parent f3cd884 commit e29f635

9 files changed

Lines changed: 378 additions & 333 deletions

File tree

README.md

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,22 +202,31 @@ import com.google.cloud.compute.Compute;
202202
import com.google.cloud.compute.ComputeOptions;
203203
import com.google.cloud.compute.Disk;
204204
import com.google.cloud.compute.DiskId;
205-
import com.google.cloud.compute.Operation;
205+
import com.google.cloud.compute.Operation.OperationError;
206+
import com.google.cloud.compute.Operation.OperationWarning;
206207
import com.google.cloud.compute.Snapshot;
207208
208-
Compute compute = ComputeOptions.defaultInstance().service();
209+
import java.util.List;
210+
211+
final Compute compute = ComputeOptions.defaultInstance().service();
209212
DiskId diskId = DiskId.of("us-central1-a", "disk-name");
210213
Disk disk = compute.getDisk(diskId, Compute.DiskOption.fields());
211214
if (disk != null) {
212-
String snapshotName = "disk-name-snapshot";
215+
final String snapshotName = "disk-name-snapshot";
213216
Operation operation = disk.createSnapshot(snapshotName);
214-
while (!operation.isDone()) {
215-
Thread.sleep(1000L);
216-
}
217-
if (operation.errors() == null) {
218-
// use snapshot
219-
Snapshot snapshot = compute.getSnapshot("disk-name-snapshot");
220-
}
217+
operation.whenDone(new Operation.CompletionCallback() {
218+
@Override
219+
public void success(Operation operation) {
220+
// use snapshot
221+
Snapshot snapshot = compute.getSnapshot(snapshotName);
222+
}
223+
224+
@Override
225+
public void error(List<OperationError> errors, List<OperationWarning> warnings) {
226+
// inspect errors
227+
throw new RuntimeException("Snaphsot creation failed");
228+
}
229+
});
221230
}
222231
```
223232
The second snippet shows how to create a virtual machine instance. Complete source code can be found
@@ -233,8 +242,10 @@ import com.google.cloud.compute.InstanceId;
233242
import com.google.cloud.compute.InstanceInfo;
234243
import com.google.cloud.compute.MachineTypeId;
235244
import com.google.cloud.compute.NetworkId;
236-
import com.google.cloud.compute.NetworkInterface;
237-
import com.google.cloud.compute.Operation;
245+
import com.google.cloud.compute.Operation.OperationError;
246+
import com.google.cloud.compute.Operation.OperationWarning;
247+
248+
import java.util.List;
238249
239250
Compute compute = ComputeOptions.defaultInstance().service();
240251
ImageId imageId = ImageId.of("debian-cloud", "debian-8-jessie-v20160329");

gcloud-java-compute/README.md

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -104,26 +104,33 @@ Add the following imports at the top of your file:
104104
```java
105105
import com.google.cloud.compute.AddressInfo;
106106
import com.google.cloud.compute.Operation;
107+
import com.google.cloud.compute.Operation.OperationError;
108+
import com.google.cloud.compute.Operation.OperationWarning;
107109
import com.google.cloud.compute.RegionAddressId;
110+
111+
import java.util.List;
108112
```
109113

110114
Then add the following code to create an address. Most Compute Engine calls return an `Operation`
111115
object that can be used to wait for operation completion and to check whether operation failed or
112116
succeeded:
113117

114118
```java
115-
RegionAddressId addressId = RegionAddressId.of("us-central1", "test-address");
119+
final RegionAddressId addressId = RegionAddressId.of("us-central1", "test-address");
116120
Operation operation = compute.create(AddressInfo.of(addressId));
117-
while (!operation.isDone()) {
118-
Thread.sleep(1000L);
119-
}
120-
operation = operation.reload();
121-
if (operation.errors() == null) {
122-
System.out.println("Address " + addressId + " was successfully created");
123-
} else {
124-
// inspect operation.errors()
125-
throw new RuntimeException("Address creation failed");
126-
}
121+
// Wait for operation to complete
122+
operation.whenDone(new Operation.CompletionCallback() {
123+
@Override
124+
public void success(Operation operation) {
125+
System.out.println("Address " + addressId + " was successfully created");
126+
}
127+
128+
@Override
129+
public void error(List<OperationError> errors, List<OperationWarning> warnings) {
130+
// inspect errors
131+
throw new RuntimeException("Address creation failed");
132+
}
133+
});
127134
```
128135

129136
#### Creating a persistent disk
@@ -145,21 +152,23 @@ import com.google.cloud.compute.ImageId;
145152
Then add the following code to create a disk and wait for disk creation to terminate.
146153

147154
```java
148-
ImageId imageId = ImageId.of("debian-cloud", "debian-8-jessie-v20160329");
155+
final ImageId imageId = ImageId.of("debian-cloud", "debian-8-jessie-v20160329");
149156
DiskId diskId = DiskId.of("us-central1-a", "test-disk");
150157
ImageDiskConfiguration diskConfiguration = ImageDiskConfiguration.of(imageId);
151158
DiskInfo disk = DiskInfo.of(diskId, diskConfiguration);
152159
Operation operation = compute.create(disk);
153-
while (!operation.isDone()) {
154-
Thread.sleep(1000L);
155-
}
156-
operation = operation.reload();
157-
if (operation.errors() == null) {
158-
System.out.println("Disk " + diskId + " was successfully created");
159-
} else {
160-
// inspect operation.errors()
161-
throw new RuntimeException("Disk creation failed");
162-
}
160+
operation.whenDone(new Operation.CompletionCallback() {
161+
@Override
162+
public void success(Operation operation) {
163+
System.out.println("Disk " + diskId + " was successfully created");
164+
}
165+
166+
@Override
167+
public void error(List<OperationError> errors, List<OperationWarning> warnings) {
168+
// inspect errors
169+
throw new RuntimeException("Disk creation failed");
170+
}
171+
});
163172
```
164173

165174
#### Creating a virtual machine instance
@@ -186,7 +195,7 @@ Then add the following code to create an instance and wait for instance creation
186195

187196
```java
188197
Address externalIp = compute.getAddress(addressId);
189-
InstanceId instanceId = InstanceId.of("us-central1-a", "test-instance");
198+
final InstanceId instanceId = InstanceId.of("us-central1-a", "test-instance");
190199
NetworkId networkId = NetworkId.of("default");
191200
PersistentDiskConfiguration attachConfiguration =
192201
PersistentDiskConfiguration.builder(diskId).boot(true).build();
@@ -198,16 +207,18 @@ MachineTypeId machineTypeId = MachineTypeId.of("us-central1-a", "n1-standard-1")
198207
InstanceInfo instance =
199208
InstanceInfo.of(instanceId, machineTypeId, attachedDisk, networkInterface);
200209
Operation operation = compute.create(instance);
201-
while (!operation.isDone()) {
202-
Thread.sleep(1000L);
203-
}
204-
operation = operation.reload();
205-
if (operation.errors() == null) {
206-
System.out.println("Instance " + instanceId + " was successfully created");
207-
} else {
208-
// inspect operation.errors()
209-
throw new RuntimeException("Instance creation failed");
210-
}
210+
operation.whenDone(new Operation.CompletionCallback() {
211+
@Override
212+
public void success(Operation operation) {
213+
System.out.println("Instance " + instanceId + " was successfully created");
214+
}
215+
216+
@Override
217+
public void error(List<OperationError> errors, List<OperationWarning> warnings) {
218+
// inspect errors
219+
throw new RuntimeException("Instance creation failed");
220+
}
221+
});
211222
```
212223

213224
#### Complete source code

gcloud-java-compute/src/main/java/com/google/cloud/compute/Operation.java

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* {@link #operationId()} returns {@link GlobalOperationId} for global operations,
4343
* {@link RegionOperationId} for region operations, and {@link ZoneOperationId} for zone operations.
4444
* To get an {@code Operation} object with the most recent information, use
45-
* {@link #reload(OperationOption...)}.
45+
* {@link #reload(Compute.OperationOption...)}.
4646
*/
4747
public class Operation implements Serializable {
4848

@@ -292,6 +292,24 @@ public int hashCode() {
292292
}
293293
}
294294

295+
/**
296+
* A callback for operation completion.
297+
*/
298+
public interface CompletionCallback {
299+
/**
300+
* The method called when the operation completes successfully.
301+
*/
302+
void success(Operation operation);
303+
304+
/**
305+
* The method called when the operation completes with errors. {@code errors} contains all
306+
* errors encountered while processing this operation (see {@link Operation#errors()}).
307+
* {@code warnings} contains all warnings encountered while processing this operation (see
308+
* {@link Operation#warnings()}).
309+
*/
310+
void error(List<OperationError> errors, List<OperationWarning> warnings);
311+
}
312+
295313
static final class Builder {
296314

297315
private Compute compute;
@@ -635,7 +653,7 @@ public String description() {
635653
* @return {@code true} if this operation exists, {@code false} otherwise
636654
* @throws ComputeException upon failure
637655
*/
638-
public boolean exists() throws ComputeException {
656+
public boolean exists() {
639657
return reload(OperationOption.fields()) != null;
640658
}
641659

@@ -652,12 +670,49 @@ public boolean exists() throws ComputeException {
652670
* not exist, {@code false} if the state is not {@link Operation.Status#DONE}
653671
* @throws ComputeException upon failure
654672
*/
655-
public boolean isDone() throws ComputeException {
673+
public boolean isDone() {
656674
Operation operation = compute.getOperation(operationId,
657675
OperationOption.fields(Compute.OperationField.STATUS));
658676
return operation == null || operation.status() == Status.DONE;
659677
}
660678

679+
/**
680+
* Waits until this operation completes its execution, either failing or succeeding. If the
681+
* operation does not exist, this method returns without executing any method of the provided
682+
* callback. If the operation completed successfully the
683+
* {@link CompletionCallback#success(Operation)} method is called. If the operation completed with
684+
* errors the {@link CompletionCallback#error(List, List)} method is called.
685+
* <pre> {@code
686+
* operation.whenDone(new CompletionCallback() {
687+
* void success(Operation operation) {
688+
* // completed successfully
689+
* }
690+
*
691+
* void error(List<OperationError> errors, List<OperationWarning> warnings) {
692+
* // handle error
693+
* }
694+
* });}</pre>
695+
*
696+
* @throws ComputeException upon failure
697+
* @throws InterruptedException if the current thread gets interrupted while waiting for the
698+
* operation to complete
699+
*/
700+
public void whenDone(CompletionCallback callback) throws InterruptedException {
701+
while (!isDone()) {
702+
Thread.sleep(500L);
703+
}
704+
Operation updatedOperation = reload();
705+
if (updatedOperation == null) {
706+
return;
707+
}
708+
List<OperationError> errors = updatedOperation.errors();
709+
if (errors != null) {
710+
callback.error(errors, updatedOperation.warnings());
711+
} else {
712+
callback.success(updatedOperation);
713+
}
714+
}
715+
661716
/**
662717
* Fetches current operation's latest information. Returns {@code null} if the operation does not
663718
* exist.
@@ -666,7 +721,7 @@ public boolean isDone() throws ComputeException {
666721
* @return an {@code Operation} object with latest information or {@code null} if not found
667722
* @throws ComputeException upon failure
668723
*/
669-
public Operation reload(OperationOption... options) throws ComputeException {
724+
public Operation reload(OperationOption... options) {
670725
return compute.getOperation(operationId, options);
671726
}
672727

@@ -677,7 +732,7 @@ public Operation reload(OperationOption... options) throws ComputeException {
677732
* @return {@code true} if operation was deleted, {@code false} if it was not found
678733
* @throws ComputeException upon failure
679734
*/
680-
public boolean delete() throws ComputeException {
735+
public boolean delete() {
681736
return compute.deleteOperation(operationId);
682737
}
683738

gcloud-java-compute/src/main/java/com/google/cloud/compute/package-info.java

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,49 @@
2222
* <a href="https://github.com/GoogleCloudPlatform/gcloud-java/tree/master/gcloud-java-examples/src/main/java/com/google/cloud/examples/compute/snippets/CreateSnapshot.java">
2323
* CreateSnapshot.java</a>.
2424
* <pre> {@code
25-
* Compute compute = ComputeOptions.defaultInstance().service();
25+
* final Compute compute = ComputeOptions.defaultInstance().service();
2626
* DiskId diskId = DiskId.of("us-central1-a", "disk-name");
2727
* Disk disk = compute.getDisk(diskId, Compute.DiskOption.fields());
2828
* if (disk != null) {
29-
* String snapshotName = "disk-name-snapshot";
29+
* final String snapshotName = "disk-name-snapshot";
3030
* Operation operation = disk.createSnapshot(snapshotName);
31-
* while (!operation.isDone()) {
32-
* Thread.sleep(1000L);
33-
* }
34-
* if (operation.errors() == null) {
35-
* // use snapshot
36-
* Snapshot snapshot = compute.getSnapshot("disk-name-snapshot");
37-
* }
31+
* operation.whenDone(new Operation.CompletionCallback() {
32+
* public void success(Operation operation) {
33+
* // use snapshot
34+
* Snapshot snapshot = compute.getSnapshot(snapshotName);
35+
* }
36+
*
37+
* public void error(List<OperationError> errors, List<OperationWarning> warnings) {
38+
* // inspect errors
39+
* throw new RuntimeException("Snaphsot creation failed");
40+
* }
41+
* });
3842
* }}</pre>
3943
* <p>This second example shows how to create a virtual machine instance. Complete source code can
4044
* be found at
4145
* <a href="https://github.com/GoogleCloudPlatform/gcloud-java/tree/master/gcloud-java-examples/src/main/java/com/google/cloud/examples/compute/snippets/CreateInstance.java">
4246
* CreateInstance.java</a>.
4347
* <pre> {@code
44-
* Compute compute = ComputeOptions.defaultInstance().service();
48+
* final Compute compute = ComputeOptions.defaultInstance().service();
4549
* ImageId imageId = ImageId.of("debian-cloud", "debian-8-jessie-v20160329");
4650
* NetworkId networkId = NetworkId.of("default");
4751
* AttachedDisk attachedDisk = AttachedDisk.of(AttachedDisk.CreateDiskConfiguration.of(imageId));
4852
* NetworkInterface networkInterface = NetworkInterface.of(networkId);
49-
* InstanceId instanceId = InstanceId.of("us-central1-a", "instance-name");
53+
* final InstanceId instanceId = InstanceId.of("us-central1-a", "instance-name");
5054
* MachineTypeId machineTypeId = MachineTypeId.of("us-central1-a", "n1-standard-1");
5155
* Operation operation =
5256
* compute.create(InstanceInfo.of(instanceId, machineTypeId, attachedDisk, networkInterface));
53-
* while (!operation.isDone()) {
54-
* Thread.sleep(1000L);
55-
* }
56-
* if (operation.errors() == null) {
57-
* // use instance
58-
* Instance instance = compute.getInstance(instanceId);
59-
* }}</pre>
57+
* operation.whenDone(new Operation.CompletionCallback() {
58+
* public void success(Operation operation) {
59+
* // use instance
60+
* Instance instance = compute.getInstance(instanceId);
61+
* }
62+
*
63+
* public void error(List<OperationError> errors, List<OperationWarning> warnings) {
64+
* // inspect errors
65+
* throw new RuntimeException("Instance creation failed");
66+
* }
67+
* });}</pre>
6068
*
6169
* @see <a href="https://cloud.google.com/compute/">Google Cloud Compute</a>
6270
*/

0 commit comments

Comments
 (0)