Skip to content

Commit 8c1f432

Browse files
committed
work in progress
1 parent 9baa721 commit 8c1f432

8 files changed

Lines changed: 244 additions & 46 deletions

File tree

src/main/java/com/google/gcloud/AuthConfig.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public abstract class AuthConfig {
1919
private static class AppEngineAuthConfig extends AuthConfig {
2020

2121
@Override
22-
protected HttpRequestInitializer getHttpRequestInitializer(
22+
protected HttpRequestInitializer httpRequestInitializer(
2323
HttpTransport transport, Set<String> scopes) {
2424
return new AppIdentityCredential(scopes);
2525
}
@@ -36,7 +36,7 @@ public ServiceAccountAuthConfig(String account, PrivateKey privateKey) {
3636
}
3737

3838
@Override
39-
protected HttpRequestInitializer getHttpRequestInitializer(
39+
protected HttpRequestInitializer httpRequestInitializer(
4040
HttpTransport transport, Set<String> scopes) {
4141
return new GoogleCredential.Builder()
4242
.setTransport(transport)
@@ -48,7 +48,7 @@ protected HttpRequestInitializer getHttpRequestInitializer(
4848
}
4949
}
5050

51-
protected abstract HttpRequestInitializer getHttpRequestInitializer(
51+
protected abstract HttpRequestInitializer httpRequestInitializer(
5252
HttpTransport transport, Set<String> scopes);
5353

5454

@@ -60,7 +60,7 @@ public static AuthConfig createForComputeEngine() throws IOException, GeneralSec
6060
final ComputeCredential cred = getComputeCredential();
6161
return new AuthConfig() {
6262
@Override
63-
protected HttpRequestInitializer getHttpRequestInitializer(HttpTransport ts, Set<String> sc) {
63+
protected HttpRequestInitializer httpRequestInitializer(HttpTransport ts, Set<String> sc) {
6464
return cred;
6565
}
6666
};

src/main/java/com/google/gcloud/ServiceOptions.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static com.google.common.base.MoreObjects.firstNonNull;
55

66
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
7+
import com.google.api.client.http.HttpRequestInitializer;
78
import com.google.api.client.http.HttpTransport;
89
import com.google.api.client.http.javanet.NetHttpTransport;
910

@@ -63,7 +64,7 @@ protected static String getAppEngineAppId() {
6364
return System.getProperty("com.google.appengine.application.id");
6465
}
6566

66-
protected abstract static class Builder {
67+
protected abstract static class Builder<B extends Builder<B>> {
6768

6869
private String host;
6970
private HttpTransport httpTransport;
@@ -79,33 +80,37 @@ protected Builder(ServiceOptions options) {
7980

8081
protected abstract ServiceOptions build();
8182

82-
public Builder host(String host) {
83+
public B host(String host) {
8384
this.host = host;
84-
return this;
85+
return (B) this;
8586
}
8687

87-
public Builder httpTransport(HttpTransport httpTransport) {
88+
public B httpTransport(HttpTransport httpTransport) {
8889
this.httpTransport = httpTransport;
89-
return this;
90+
return (B) this;
9091
}
9192

92-
public Builder authConfig(AuthConfig authConfig) {
93+
public B authConfig(AuthConfig authConfig) {
9394
this.authConfig = authConfig;
94-
return this;
95+
return (B) this;
9596
}
9697
}
9798

98-
protected abstract Set<String> getScopes();
99+
protected abstract Set<String> scopes();
99100

100-
public String getHost() {
101+
public String host() {
101102
return host;
102103
}
103104

104-
public HttpTransport getHttpTransport() {
105+
public HttpTransport httpTransport() {
105106
return httpTransport;
106107
}
107108

108-
public AuthConfig getAuthConfig() {
109+
public AuthConfig authConfig() {
109110
return authConfig;
110111
}
112+
113+
protected HttpRequestInitializer httpRequestInitializer() {
114+
return authConfig().httpRequestInitializer(httpTransport, scopes());
115+
}
111116
}
Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,77 @@
11
package com.google.gcloud.datastore;
22

3+
import static com.google.common.base.MoreObjects.firstNonNull;
4+
5+
import com.google.api.services.datastore.client.DatastoreException;
6+
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
310
public class DatastoreServiceException extends RuntimeException {
411

512
private static final long serialVersionUID = 8170357898917041899L;
13+
private static final Map<Integer, Code> HTTP_TO_CODE = new HashMap<>();
14+
15+
private final Code code;
16+
17+
/**
18+
* An error code to represent the failure.
19+
*
20+
* @see <a href="https://cloud.google.com/datastore/docs/concepts/errors#Error_Codes">Google Cloud Datastore error codes</a>
21+
*/
22+
public enum Code {
23+
24+
ABORTED(409, true, "Request aborted"),
25+
DEADLINE_EXCEEDED(403, true, "Deadline exceeded"),
26+
UNAVAILABLE(503, true, "Could not reach service"),
27+
FAILED_PRECONDITION(412, false, "Invalid request"),
28+
INVALID_ARGUMENT(400, false, "Request parameter has an invalid value"),
29+
PERMISSION_DENIED(403, false, "Unauthorized request"),
30+
RESOURCE_EXHAUSTED(402, false, "Quota exceeded"),
31+
INTERNAL(500, false, "Server returned an error"),
32+
UNKNOWN(0, false, "Unknown failure");
633

7-
private final boolean isTransient;
34+
private final boolean isTransient;
35+
private final String msg;
836

9-
public DatastoreServiceException(boolean isTransient, String msg, Exception cause) {
10-
super(msg, cause);
11-
this.isTransient = isTransient;
37+
Code(int httpStatus, boolean isTransient, String msg) {
38+
this.isTransient = isTransient;
39+
this.msg = msg;
40+
HTTP_TO_CODE.put(httpStatus, this);
41+
}
42+
43+
/**
44+
* Returns {@code true} if this exception is transient and the same request could be retried.
45+
* For any retry it is highly recommended to apply an exponential backoff.
46+
*/
47+
public boolean isTransient() {
48+
return isTransient;
49+
}
50+
51+
DatastoreServiceException translate(DatastoreException exception) {
52+
return new DatastoreServiceException(this, exception);
53+
}
54+
}
55+
56+
public DatastoreServiceException(Code code, Exception cause) {
57+
super(code.msg, cause);
58+
this.code = code;
59+
}
60+
61+
/**
62+
* Returns the code associated with this exception.
63+
*/
64+
public Code code() {
65+
return code;
1266
}
1367

1468
/**
15-
* @return {@code true} if this exception is transient and could be safely retried.
69+
* Translate DatastoreException to DatastoreServiceException based on their
70+
* HTTP error codes. This method will always throw a new DatastoreServiceException.
71+
*
72+
* @throws DatastoreServiceException for every given DatastoreException
1673
*/
17-
public boolean isTransient() {
18-
return isTransient;
74+
static DatastoreServiceException translateAndPropagate(DatastoreException exception) {
75+
throw firstNonNull(HTTP_TO_CODE.get(exception.getCode()), Code.UNKNOWN).translate(exception);
1976
}
2077
}
Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,37 @@
11
package com.google.gcloud.datastore;
22

3+
import com.google.api.services.datastore.client.Datastore;
4+
import com.google.api.services.datastore.client.DatastoreFactory;
5+
import com.google.api.services.datastore.client.DatastoreOptions;
6+
import com.google.api.services.datastore.client.LocalDevelopmentDatastoreFactory;
37

4-
public class DatastoreServiceFactory {
58

6-
public static DatastoreService getDatastoreService(DatastoreServiceOptions options) {
7-
return new DatastoreServiceImpl(options);
9+
public interface DatastoreServiceFactory {
10+
11+
enum Mode implements DatastoreServiceFactory {
12+
13+
TESTING {
14+
15+
@Override
16+
public DatastoreService get(DatastoreServiceOptions options) {
17+
DatastoreOptions dsOptions = new DatastoreOptions.Builder()
18+
.dataset(options.dataset())
19+
.host(options.host())
20+
.build();
21+
Datastore datastore = LocalDevelopmentDatastoreFactory.get().create(dsOptions);
22+
return new DatastoreServiceImpl(options, datastore);
23+
}
24+
},
25+
26+
PROD {
27+
@Override
28+
public DatastoreService get(DatastoreServiceOptions options) {
29+
DatastoreOptions dsOptions = options.toDatastoreOptions();
30+
Datastore datastore = DatastoreFactory.get().create(dsOptions);
31+
return new DatastoreServiceImpl(options, datastore);
32+
}
33+
};
834
}
35+
36+
DatastoreService get(DatastoreServiceOptions options);
937
}

src/main/java/com/google/gcloud/datastore/DatastoreServiceImpl.java

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
package com.google.gcloud.datastore;
22

3+
import com.google.api.services.datastore.DatastoreV1;
4+
import com.google.api.services.datastore.client.Datastore;
5+
import com.google.api.services.datastore.client.DatastoreException;
6+
import com.google.common.collect.AbstractIterator;
7+
8+
import java.util.HashMap;
39
import java.util.Iterator;
10+
import java.util.Map;
411

512

613
final class DatastoreServiceImpl implements DatastoreService {
714

815
private final DatastoreServiceOptions options;
16+
private final Datastore datastore;
917

10-
DatastoreServiceImpl(DatastoreServiceOptions options) {
18+
DatastoreServiceImpl(DatastoreServiceOptions options, Datastore datastore) {
1119
this.options = options;
20+
this.datastore = datastore;
1221
}
1322

1423
@Override
@@ -35,9 +44,27 @@ public Key allocateId(PartialKey key) {
3544

3645
@Override
3746
public Iterator<Key> allocateIds(PartialKey... key) {
38-
// TODO Auto-generated method stub
39-
// Will need to populate "force" after b/18594027 is fixed.
40-
return null;
47+
DatastoreV1.AllocateIdsRequest.Builder requestPb = DatastoreV1.AllocateIdsRequest.newBuilder();
48+
for (PartialKey k : key) {
49+
requestPb.addKey(k.toPb());
50+
}
51+
// TODO(ozarov): will need to populate "force" after b/18594027 is fixed.
52+
try {
53+
DatastoreV1.AllocateIdsResponse responsePb = datastore.allocateIds(requestPb.build());
54+
final Iterator<DatastoreV1.Key> keys = responsePb.getKeyList().iterator();
55+
return new AbstractIterator<Key>() {
56+
57+
@Override
58+
protected Key computeNext() {
59+
if (keys.hasNext()) {
60+
return Key.fromPb(keys.next());
61+
}
62+
return endOfData();
63+
}
64+
};
65+
} catch (DatastoreException e) {
66+
throw DatastoreServiceException.translateAndPropagate(e);
67+
}
4168
}
4269

4370
@Override
@@ -46,29 +73,82 @@ public Entity get(Key key) {
4673
}
4774

4875
@Override
49-
public Iterator<Entity> get(Key... key) {
50-
// TODO Auto-generated method stub
51-
return null;
76+
public Iterator<Entity> get(final Key... key) {
77+
DatastoreV1.LookupRequest.Builder requestPb = DatastoreV1.LookupRequest.newBuilder();
78+
for (Key k : key) {
79+
requestPb.addKey(k.toPb());
80+
}
81+
try {
82+
DatastoreV1.LookupResponse responsePb = datastore.lookup(requestPb.build());
83+
final Map<Key, Entity> result = new HashMap<>();
84+
for (DatastoreV1.EntityResult entityResultPb : responsePb.getFoundList()) {
85+
Entity entity = Entity.fromPb(entityResultPb.getEntity());
86+
result.put(entity.key(), entity);
87+
}
88+
return new AbstractIterator<Entity>() {
89+
int index;
90+
91+
@Override
92+
protected Entity computeNext() {
93+
if (index < key.length) {
94+
return result.get(key[index++]);
95+
}
96+
return endOfData();
97+
}
98+
};
99+
} catch (DatastoreException e) {
100+
throw DatastoreServiceException.translateAndPropagate(e);
101+
}
52102
}
53103

54104
@Override
55105
public void add(Entity... entity) {
56-
// TODO Auto-generated method stub
106+
DatastoreV1.Mutation.Builder mutationPb = DatastoreV1.Mutation.newBuilder();
107+
for (Entity e : entity) {
108+
mutationPb.addInsert(e.toPb());
109+
}
110+
comitMutation(mutationPb);
111+
}
112+
113+
private void comitMutation(DatastoreV1.Mutation.Builder mutationPb) {
114+
if (options.force()) {
115+
mutationPb.setForce(true);
116+
}
117+
DatastoreV1.CommitRequest.Builder requestPb = DatastoreV1.CommitRequest.newBuilder();
118+
requestPb.setMode(DatastoreV1.CommitRequest.Mode.NON_TRANSACTIONAL);
119+
requestPb.setMutation(mutationPb.build());
120+
try {
121+
datastore.commit(requestPb.build());
122+
} catch (DatastoreException e) {
123+
throw DatastoreServiceException.translateAndPropagate(e);
124+
}
57125
}
58126

59127
@Override
60128
public void update(Entity... entity) {
61-
// TODO Auto-generated method stub
129+
DatastoreV1.Mutation.Builder mutationPb = DatastoreV1.Mutation.newBuilder();
130+
for (Entity e : entity) {
131+
mutationPb.addUpdate(e.toPb());
132+
}
133+
comitMutation(mutationPb);
62134
}
63135

64136
@Override
65137
public void put(Entity... entity) {
66-
// TODO Auto-generated method stub
138+
DatastoreV1.Mutation.Builder mutationPb = DatastoreV1.Mutation.newBuilder();
139+
for (Entity e : entity) {
140+
mutationPb.addUpsert(e.toPb());
141+
}
142+
comitMutation(mutationPb);
67143
}
68144

69145
@Override
70146
public void delete(Key... key) {
71-
// TODO Auto-generated method stub
147+
DatastoreV1.Mutation.Builder mutationPb = DatastoreV1.Mutation.newBuilder();
148+
for (Key k : key) {
149+
mutationPb.addDelete(k.toPb());
150+
}
151+
comitMutation(mutationPb);
72152
}
73153

74154
@Override
@@ -81,4 +161,8 @@ public QueryResult<PartialEntity> runQuery(Query query) {
81161
// TODO Auto-generated method stub
82162
return null;
83163
}
164+
165+
Datastore datastore() {
166+
return datastore;
167+
}
84168
}

0 commit comments

Comments
 (0)