/
StdCouchDbInstance.java
243 lines (213 loc) · 7.48 KB
/
StdCouchDbInstance.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package org.ektorp.impl;
import static java.lang.String.*;
import java.io.*;
import java.util.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.ektorp.*;
import org.ektorp.http.*;
import org.ektorp.util.*;
import org.slf4j.*;
/**
*
* @author henrik lundgren
*
*/
public class StdCouchDbInstance implements CouchDbInstance {
private final static Logger LOG = LoggerFactory.getLogger(StdCouchDbInstance.class);
private final static TypeReference<List<String>> STRING_LIST_TYPE_DEF = new TypeReference<List<String>>() {};
private final HttpClient client;
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
private final ObjectMapperFactory objectMapperFactory;
public StdCouchDbInstance(HttpClient client) {
this(client, new StdObjectMapperFactory());
}
public StdCouchDbInstance(HttpClient client, ObjectMapperFactory of) {
Assert.notNull(client, "HttpClient may not be null");
Assert.notNull(of, "ObjectMapperFactory may not be null");
this.client = client;
this.restTemplate = new RestTemplate(client);
this.objectMapper = of.createObjectMapper();
this.objectMapperFactory = of;
}
public ObjectMapperFactory getObjectMapperFactory() {
return objectMapperFactory;
}
public void createDatabase(String path) {
createDatabase(DbPath.fromString(path));
}
public void createDatabase(DbPath db) {
if (!createDatabaseIfNotExists(db)) {
throw new DbAccessException(format("A database with path %s already exists", db.getPath()));
}
}
public boolean createDatabaseIfNotExists(String path) {
return createDatabaseIfNotExists(DbPath.fromString(path));
}
public boolean createDatabaseIfNotExists(final DbPath db) {
boolean databaseAlreadyExists = checkIfDbExists(db);
if (databaseAlreadyExists) {
return false;
}
LOG.debug("creating db path: {}", db.getPath());
return restTemplate.put(db.getPath(), new StdResponseHandler<Boolean>() {
@Override
public Boolean error(HttpResponse hr) {
if (hr.getCode() == HttpStatus.PRECONDITION_FAILED) {
// 412 indicates existing database
// see http://docs.couchdb.org/en/latest/api/database/common.html#put--db
LOG.debug("database at db path {} already exists.", db.getPath());
return false;
}
throw StdResponseHandler.createDbAccessException(hr);
}
@Override
public Boolean success(HttpResponse hr) throws Exception {
return checkResponseBodyOkAndReturnDefaultValue(hr, true, objectMapper);
}
});
}
public void deleteDatabase(String path) {
Assert.notNull(path);
restTemplate.delete(DbPath.fromString(path).getPath());
}
@Override
public boolean checkIfDbExists(String path) {
return checkIfDbExists(DbPath.fromString(path));
}
@Override
public boolean checkIfDbExists(DbPath db) {
return restTemplate.head(db.getPath(), new StdResponseHandler<Boolean>() {
@Override
public Boolean error(HttpResponse hr) {
if(hr.getCode() == HttpStatus.NOT_FOUND) {
// only 404 is a valid response, anything else is an error
// see http://docs.couchdb.org/en/latest/api/database/common.html#head--db
return false;
}
throw StdResponseHandler.createDbAccessException(hr);
}
@Override
public Boolean success(HttpResponse hr) throws Exception {
return true;
}
});
}
public List<String> getAllDatabases() {
return restTemplate.get("/_all_dbs", new StdResponseHandler<List<String>>(){
@Override
public List<String> success(HttpResponse hr) throws Exception {
return objectMapper.readValue(hr.getContent(), STRING_LIST_TYPE_DEF);
}
});
}
public ReplicationStatus replicate(ReplicationCommand cmd) {
try {
return restTemplate.post("/_replicate", objectMapper.writeValueAsString(cmd), new StdResponseHandler<ReplicationStatus>() {
@Override
public ReplicationStatus success(HttpResponse hr)
throws Exception {
return objectMapper.readValue(hr.getContent(), ReplicationStatus.class);
}
});
} catch (IOException e) {
throw Exceptions.propagate(e);
}
}
public HttpClient getConnection() {
return client;
}
public CouchDbConnector createConnector(String path,
boolean createIfNotExists) {
CouchDbConnector db = new StdCouchDbConnector(path, this, objectMapperFactory);
if (createIfNotExists) db.createDatabaseIfNotExists();
return db;
}
@Override
public CouchDbConnector getReplicatorConnector()
{
return createConnector("_replicator", false);
}
@Override
public <T> T getConfiguration(final Class<T> c) {
return getConfiguration(c, null, null);
}
@Override
public <T> T getConfiguration(final Class<T> c, String section) {
return getConfiguration(c, section, null);
}
@Override
public <T> T getConfiguration(final Class<T> c, String section, String key) {
Assert.notNull(c, "Class may not be null");
String url = "/_config";
if(section != null) {
url = url + "/" + section;
if(key != null) {
url = url + "/" + key;
}
}
return restTemplate.get(url,
new StdResponseHandler<T>() {
@Override
public T success(HttpResponse hr) throws Exception {
return objectMapper.readValue(hr.getContent(), c);
}
});
}
@Override
public String getConfiguration(String section, String key) {
return getConfiguration(String.class, section, key);
}
@Override
public String setConfiguration(String section, String key, String value) {
Assert.notNull(section, "Section may not be null");
Assert.notNull(key, "Key may not be null");
String url = "/_config/" + section + "/" + key;
String content;
try {
content = objectMapper.writeValueAsString(value);
} catch (JsonProcessingException e) {
throw Exceptions.propagate(e);
}
return restTemplate.put(url, content,
new StdResponseHandler<String>() {
@Override
public String success(HttpResponse hr) throws Exception {
return objectMapper.readValue(hr.getContent(), String.class);
}
});
}
@Override
public String deleteConfiguration(String section, String key) {
Assert.notNull(section, "Section may not be null");
Assert.notNull(key, "Key may not be null");
String url = "/_config/" + section + "/" + key;
return restTemplate.delete(url,
new StdResponseHandler<String>() {
@Override
public String success(HttpResponse hr) throws Exception {
return objectMapper.readValue(hr.getContent(), String.class);
}
});
}
@Override
public Collection<ActiveTask> getActiveTasks() {
String url = "/_active_tasks";
List<StdActiveTask> tasks = restTemplate.get(url,
new StdResponseHandler<List<StdActiveTask>>() {
@Override
public List<StdActiveTask> success(HttpResponse hr) throws Exception {
return objectMapper.readValue(hr.getContent(), new TypeReference<List<StdActiveTask>>() {});
}
});
// We have to copy the list here because Java lacks covariance (i.e. we can't just return
// the List<StdActiveTask> because it's not a Collection<ActiveTask>).
Collection<ActiveTask> ret = new ArrayList<ActiveTask>();
for (StdActiveTask task : tasks) {
ret.add(task);
}
return ret;
}
}