Skip to content

Commit 1855733

Browse files
committed
Added batch concept supporting list zones calls only.
1 parent 17442b0 commit 1855733

9 files changed

Lines changed: 466 additions & 9 deletions

File tree

gcloud-java-dns/src/main/java/com/google/gcloud/dns/Dns.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,4 +533,19 @@ ChangeRequest getChangeRequest(String zoneName, String changeRequestId,
533533
* @see <a href="https://cloud.google.com/dns/api/v1/changes/list">Cloud DNS Chages: list</a>
534534
*/
535535
Page<ChangeRequest> listChangeRequests(String zoneName, ChangeRequestListOption... options);
536+
537+
/**
538+
* Submits a {@code batch} for processing to the Google Cloud DNS. The operations in the batch
539+
* will be called using a single HTTP request. For each successfully executed operation, its
540+
* {@link DnsBatch.Callback#success(Object, DnsBatch.Request)} callback method will be invoked.
541+
* For each operation which returned an error, its {@link DnsBatch.Callback#error(DnsException,
542+
* DnsBatch.Request)} callback method will be invoked.
543+
*/
544+
void submitBatch(DnsBatch batch);
545+
546+
/**
547+
* Initiates a new empty batch ready to be populated with service calls, which will use this
548+
* {@code Dns} instance when submitted for processing to Google Cloud DNS.
549+
*/
550+
DnsBatch batch();
536551
}
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.gcloud.dns;
18+
19+
import com.google.gcloud.Page;
20+
21+
import java.util.LinkedHashMap;
22+
import java.util.Map;
23+
24+
/**
25+
* A batch of operations to be submitted to Google Cloud DNS using a single HTTP request.
26+
*/
27+
public class DnsBatch {
28+
29+
private Map<Request, Callback> requests = new LinkedHashMap<>();
30+
private Dns dns;
31+
32+
/**
33+
* An interface for the callback which will be invoked when the operation has been executed. The
34+
* parameter {@code <T>} represents the type of the result of the operation and thus depends on
35+
* the {@link DnsBatch.Request} that this call back belongs to and it should be as follows:
36+
*
37+
* <ul>
38+
* <li>{@link Zone} for creating and getting a zone</li>
39+
* <li>{@link Boolean} for deleting a zone</li>
40+
* <li>{@link ChangeRequest} for creating and getting a change request</li>
41+
* <li>{@link ProjectInfo} for getting a project</li>
42+
* <li>{@code Page<Zone>} for listing zones</li>
43+
* <li>{@code Page<DnsRecord>} for listing {@link DnsRecord}s inside a zone</li>
44+
* <li>{@code Page<ChangeRequest>} for listing {@link ChangeRequest}s for a zone</li>
45+
* </ul>
46+
*/
47+
public interface Callback<T> {
48+
/**
49+
* A method which will be called if the {@link DnsBatch.Request} succeeds. See the {@link
50+
* Callback} documentation for details on type {@code T}.
51+
*
52+
* @param output the result of the operation
53+
* @param request the request which succeeded
54+
*/
55+
void success(T output, DnsBatch.Request request);
56+
57+
/**
58+
* A method which will be called if the {@link DnsBatch.Request} fails.
59+
*
60+
* @param ex the error
61+
* @param request the request which failed
62+
*/
63+
void error(DnsException ex, DnsBatch.Request request);
64+
}
65+
66+
/**
67+
* An operation to be submitted to Google Cloud DNS within this batch. Only an subset of the class
68+
* attributes appropriate for the represented operation is initialized. Refer to the class method
69+
* and attribute documentation for the specific fields.
70+
*/
71+
public static class Request {
72+
73+
private final String zoneName;
74+
private final String changeId;
75+
private final ChangeRequest changeRequest;
76+
private final ZoneInfo zoneInfo;
77+
private final Operation operation;
78+
private final AbstractOption[] options;
79+
80+
private Request(RequestBuilder builder) {
81+
this.zoneName = builder.zoneName;
82+
this.changeId = builder.changeId;
83+
this.changeRequest = builder.changeRequest;
84+
this.zoneInfo = builder.zoneInfo;
85+
this.operation = builder.operation;
86+
this.options = builder.options;
87+
}
88+
89+
private static RequestBuilder builder(Operation operation, AbstractOption... options) {
90+
return new RequestBuilder(operation, options);
91+
}
92+
93+
/**
94+
* Returns the name of the zone to which the operation is applied. This field is initialized for
95+
* zone create, get and delete operation, and listing DNS records and changes within a zone.
96+
* Returns {@code null} in other cases.
97+
*/
98+
public String zoneName() {
99+
return zoneName;
100+
}
101+
102+
/**
103+
* Returns the id of the change request which is being retrieved. Getting a change request is
104+
* the only operation when this attribute is initialized. The method returns {@code null} in the
105+
* remaining cases.
106+
*/
107+
public String changeId() {
108+
return changeId;
109+
}
110+
111+
/**
112+
* Returns the change request which is being created. Creating a change request is the only
113+
* operation when this attribute is initialized. The method returns {@code null} in the
114+
* remaining cases.
115+
*/
116+
public ChangeRequest changeRequest() {
117+
return changeRequest;
118+
}
119+
120+
/**
121+
* Returns the zone which is being created. Creating a zone is the only operation when this
122+
* attribute is initialized. The method returns {@code null} in the remaining cases.
123+
*/
124+
public ZoneInfo zoneInfo() {
125+
return zoneInfo;
126+
}
127+
128+
/**
129+
* Returns the type of the operation represented by this {@link DnsBatch.Request}. This field is
130+
* always initialized.
131+
*/
132+
public Operation operation() {
133+
return operation;
134+
}
135+
136+
/**
137+
* Returns options provided to the operation. Returns an empty array if no options were
138+
* provided.
139+
*/
140+
public AbstractOption[] options() {
141+
return options == null ? new AbstractOption[0] : options;
142+
}
143+
}
144+
145+
static class RequestBuilder {
146+
private final AbstractOption[] options;
147+
private String zoneName;
148+
private String changeId;
149+
private ChangeRequest changeRequest;
150+
private ZoneInfo zoneInfo;
151+
private final Operation operation;
152+
153+
RequestBuilder(Operation operation, AbstractOption... options) {
154+
this.operation = operation;
155+
this.options = options;
156+
}
157+
158+
RequestBuilder zoneName(String zoneName) {
159+
this.zoneName = zoneName;
160+
return this;
161+
}
162+
163+
RequestBuilder changeId(String changeId) {
164+
this.changeId = changeId;
165+
return this;
166+
}
167+
168+
RequestBuilder changeRequest(ChangeRequest changeRequest) {
169+
this.changeRequest = changeRequest;
170+
return this;
171+
}
172+
173+
RequestBuilder zoneInfo(ZoneInfo zoneInfo) {
174+
this.zoneInfo = zoneInfo;
175+
return this;
176+
}
177+
178+
Request build() {
179+
return new Request(this);
180+
}
181+
}
182+
183+
/**
184+
* Represents the type of the batch operation.
185+
*/
186+
public enum Operation {
187+
CREATE_ZONE,
188+
DELETE_ZONE,
189+
GET_ZONE,
190+
LIST_ZONES,
191+
APPLY_CHANGE_REQUEST,
192+
GET_CHANGE_REQUEST,
193+
LIST_CHANGES_REQUESTS,
194+
LIST_DNS_RECORDS
195+
}
196+
197+
DnsBatch(Dns dns) {
198+
this.dns = dns;
199+
}
200+
201+
public Dns service() {
202+
return dns;
203+
}
204+
205+
Map<Request, Callback> requests() {
206+
return requests;
207+
}
208+
209+
/**
210+
* Adds a {@code DnsBatch.Request} represeting the list zones operation to this batch. The request
211+
* will not have initialized any fields except for the operation type and options (if provided).
212+
* The {@code callback} will receive a page of {@link Zone}s upon success of the request. The
213+
* {@code options} can be used to restrict the fields returned or provide page size limits in the
214+
* same way as for {@link Dns#listZones(Dns.ZoneListOption...)}.
215+
*/
216+
public DnsBatch listZones(Callback<Page<Zone>> callback, Dns.ZoneListOption... options) {
217+
Request request = Request.builder(Operation.LIST_ZONES, options).build();
218+
requests.put(request, callback);
219+
return this;
220+
}
221+
222+
// todo(mderka) add the rest of the operations
223+
224+
/**
225+
* Submits this batch for processing using a single HTTP request. This will invoke all callbacks
226+
* for the invidual {@link DnsBatch.Request}s contained in this batch.
227+
*/
228+
public void submit() {
229+
dns.submitBatch(this);
230+
}
231+
}

gcloud-java-dns/src/main/java/com/google/gcloud/dns/DnsException.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.gcloud.dns;
1818

19+
import com.google.api.client.googleapis.json.GoogleJsonError;
1920
import com.google.common.collect.ImmutableSet;
2021
import com.google.gcloud.BaseServiceException;
2122
import com.google.gcloud.RetryHelper.RetryHelperException;
@@ -43,6 +44,10 @@ public DnsException(IOException exception) {
4344
super(exception, true);
4445
}
4546

47+
public DnsException(GoogleJsonError error) {
48+
super(error, true);
49+
}
50+
4651
private DnsException(int code, String message) {
4752
super(code, message, null, true);
4853
}

gcloud-java-dns/src/main/java/com/google/gcloud/dns/DnsImpl.java

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@
2121
import static com.google.gcloud.RetryHelper.runWithRetries;
2222
import static com.google.gcloud.dns.ChangeRequest.fromPb;
2323

24+
import com.google.api.client.googleapis.batch.BatchRequest;
25+
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
26+
import com.google.api.client.googleapis.json.GoogleJsonError;
27+
import com.google.api.client.http.HttpHeaders;
2428
import com.google.api.services.dns.model.Change;
2529
import com.google.api.services.dns.model.ManagedZone;
30+
import com.google.api.services.dns.model.ManagedZonesListResponse;
2631
import com.google.api.services.dns.model.ResourceRecordSet;
2732
import com.google.common.base.Function;
2833
import com.google.common.collect.ImmutableList;
@@ -35,6 +40,7 @@
3540
import com.google.gcloud.RetryHelper;
3641
import com.google.gcloud.dns.spi.DnsRpc;
3742

43+
import java.io.IOException;
3844
import java.util.Map;
3945
import java.util.concurrent.Callable;
4046

@@ -309,11 +315,86 @@ public com.google.api.services.dns.model.Change call() {
309315
}
310316
}
311317

318+
@Override
319+
public void submitBatch(DnsBatch toSubmit) {
320+
try {
321+
BatchRequest batchRequest = prepareBatch(toSubmit);
322+
batchRequest.execute();
323+
} catch (IOException ex) {
324+
throw new DnsException(ex);
325+
}
326+
}
327+
328+
/**
329+
* Since {@code BatchRequest} is a final class, it cannot be mocked with easy mock and the call of
330+
* {@code execute()} cannot be tested. Thus, most of the functionality of {@link
331+
* #submitBatch(DnsBatch)} is extracted to this method which does not make the call so it does not
332+
* communicate with the service.
333+
*/
334+
BatchRequest prepareBatch(DnsBatch toSubmit) throws IOException {
335+
BatchRequest batch = null;
336+
for (Map.Entry<DnsBatch.Request, DnsBatch.Callback> entry : toSubmit.requests().entrySet()) {
337+
DnsBatch.Request request = entry.getKey();
338+
DnsBatch.Callback callback = entry.getValue();
339+
switch (request.operation()) {
340+
case LIST_ZONES:
341+
JsonBatchCallback rpcCallback = listZonesCallback(callback, request);
342+
batch =
343+
dnsRpc.enqueueListZones(batch, request, rpcCallback, optionMap(request.options()));
344+
break;
345+
default:
346+
// todo(mderka) implement the rest of the operations
347+
throw new UnsupportedOperationException("Not implemented yet");
348+
}
349+
}
350+
return batch;
351+
}
352+
353+
@Override
354+
public DnsBatch batch() {
355+
return new DnsBatch(this);
356+
}
357+
358+
private JsonBatchCallback listZonesCallback(final DnsBatch.Callback callback,
359+
final DnsBatch.Request request) {
360+
return new JsonBatchCallback<ManagedZonesListResponse>() {
361+
@Override
362+
public void onFailure(GoogleJsonError error, HttpHeaders httpHeaders) {
363+
if (callback != null) {
364+
callback.error(new DnsException(error), request);
365+
}
366+
}
367+
368+
@Override
369+
public void onSuccess(ManagedZonesListResponse zoneList, HttpHeaders httpHeaders) {
370+
if (callback != null) {
371+
DnsRpc.ListResult<ManagedZone> listResult =
372+
DnsRpc.ListResult.of(zoneList.getNextPageToken(), zoneList.getManagedZones());
373+
String cursor = listResult.pageToken();
374+
Iterable<Zone> zones = listResult.results() == null ? ImmutableList.<Zone>of()
375+
: Iterables.transform(listResult.results(), new Function<ManagedZone, Zone>() {
376+
@Override
377+
public Zone apply(ManagedZone managedZone) {
378+
return new Zone(options().service(),
379+
new ZoneInfo.BuilderImpl(ZoneInfo.fromPb(managedZone)));
380+
}
381+
}
382+
);
383+
Page<Zone> page = new PageImpl<>(
384+
new ZonePageFetcher(options(), cursor, optionMap(request.options())), cursor, zones);
385+
callback.success(page, request);
386+
}
387+
}
388+
};
389+
}
390+
312391
private Map<DnsRpc.Option, ?> optionMap(AbstractOption... options) {
313392
Map<DnsRpc.Option, Object> temp = Maps.newEnumMap(DnsRpc.Option.class);
314-
for (AbstractOption option : options) {
315-
Object prev = temp.put(option.rpcOption(), option.value());
316-
checkArgument(prev == null, "Duplicate option %s", option);
393+
if (options != null) {
394+
for (AbstractOption option : options) {
395+
Object prev = temp.put(option.rpcOption(), option.value());
396+
checkArgument(prev == null, "Duplicate option %s", option);
397+
}
317398
}
318399
return ImmutableMap.copyOf(temp);
319400
}

gcloud-java-dns/src/main/java/com/google/gcloud/dns/ZoneInfo.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import static com.google.common.base.Preconditions.checkNotNull;
2020

21+
import com.google.api.services.dns.model.ManagedZone;
22+
import com.google.common.base.Function;
2123
import com.google.common.base.MoreObjects;
2224
import com.google.common.collect.ImmutableList;
2325
import com.google.common.collect.Lists;

0 commit comments

Comments
 (0)