Skip to content

Commit 052010e

Browse files
committed
Renamed core project
1 parent 910d36e commit 052010e

File tree

10 files changed

+787
-0
lines changed

10 files changed

+787
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
project_description = "Java admin client for Redis Enterprise"
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
package com.redis.enterprise;
2+
3+
import java.io.IOException;
4+
import java.net.URI;
5+
import java.net.URISyntaxException;
6+
import java.security.GeneralSecurityException;
7+
import java.time.Duration;
8+
import java.util.List;
9+
10+
import javax.net.ssl.SSLContext;
11+
12+
import org.apache.hc.client5.http.HttpResponseException;
13+
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
14+
import org.apache.hc.client5.http.classic.methods.HttpDelete;
15+
import org.apache.hc.client5.http.classic.methods.HttpGet;
16+
import org.apache.hc.client5.http.classic.methods.HttpPost;
17+
import org.apache.hc.client5.http.entity.mime.ByteArrayBody;
18+
import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
19+
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
20+
import org.apache.hc.client5.http.impl.auth.BasicScheme;
21+
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
22+
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
23+
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
24+
import org.apache.hc.client5.http.impl.classic.HttpClients;
25+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
26+
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
27+
import org.apache.hc.client5.http.protocol.HttpClientContext;
28+
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
29+
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
30+
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
31+
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
32+
import org.apache.hc.core5.http.ClassicHttpRequest;
33+
import org.apache.hc.core5.http.ContentType;
34+
import org.apache.hc.core5.http.HttpHeaders;
35+
import org.apache.hc.core5.http.HttpHost;
36+
import org.apache.hc.core5.http.HttpStatus;
37+
import org.apache.hc.core5.http.ParseException;
38+
import org.apache.hc.core5.http.io.entity.EntityUtils;
39+
import org.apache.hc.core5.http.io.entity.StringEntity;
40+
import org.apache.hc.core5.ssl.SSLContexts;
41+
import org.awaitility.Awaitility;
42+
import org.slf4j.Logger;
43+
import org.slf4j.LoggerFactory;
44+
45+
import com.fasterxml.jackson.databind.DeserializationFeature;
46+
import com.fasterxml.jackson.databind.JavaType;
47+
import com.fasterxml.jackson.databind.ObjectMapper;
48+
import com.fasterxml.jackson.databind.type.CollectionType;
49+
import com.fasterxml.jackson.databind.type.SimpleType;
50+
import com.redis.enterprise.rest.Action;
51+
import com.redis.enterprise.rest.Bootstrap;
52+
import com.redis.enterprise.rest.Command;
53+
import com.redis.enterprise.rest.CommandResponse;
54+
import com.redis.enterprise.rest.Database;
55+
import com.redis.enterprise.rest.Module;
56+
import com.redis.enterprise.rest.ModuleInstallResponse;
57+
58+
public class Admin implements AutoCloseable {
59+
60+
private static final Logger log = LoggerFactory.getLogger(Admin.class);
61+
62+
public static final String CONTENT_TYPE_JSON = "application/json";
63+
public static final String V1 = "/v1/";
64+
public static final String V2 = "/v2/";
65+
public static final String DEFAULT_PROTOCOL = "https";
66+
public static final String DEFAULT_HOST = "localhost";
67+
public static final int DEFAULT_PORT = 9443;
68+
public static final String BOOTSTRAP = "bootstrap";
69+
public static final String ACTIONS = "actions";
70+
public static final String MODULES = "modules";
71+
public static final String BDBS = "bdbs";
72+
public static final String COMMAND = "command";
73+
private static final CharSequence PATH_SEPARATOR = "/";
74+
75+
private final ObjectMapper objectMapper = new ObjectMapper()
76+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
77+
private final UsernamePasswordCredentials credentials;
78+
private final CloseableHttpClient client;
79+
private String protocol = DEFAULT_PROTOCOL;
80+
private String host = DEFAULT_HOST;
81+
private int port = DEFAULT_PORT;
82+
83+
public Admin(String userName, final char[] password) throws GeneralSecurityException {
84+
this.credentials = new UsernamePasswordCredentials(userName, password);
85+
SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(new TrustAllStrategy()).build();
86+
SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create()
87+
.setSslContext(sslcontext).setHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
88+
HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
89+
.setSSLSocketFactory(sslSocketFactory).build();
90+
HttpClientBuilder clientBuilder = HttpClients.custom();
91+
clientBuilder.setConnectionManager(cm);
92+
this.client = clientBuilder.build();
93+
}
94+
95+
@Override
96+
public void close() throws Exception {
97+
client.close();
98+
}
99+
100+
public void setHost(String host) {
101+
this.host = host;
102+
}
103+
104+
public void setProtocol(String protocol) {
105+
this.protocol = protocol;
106+
}
107+
108+
public void setPort(int port) {
109+
this.port = port;
110+
}
111+
112+
private static String v1(String... segments) {
113+
return join(V1, segments);
114+
}
115+
116+
private static String v2(String... segments) {
117+
return join(V2, segments);
118+
}
119+
120+
private static String join(String path, String[] segments) {
121+
return path + String.join(PATH_SEPARATOR, segments);
122+
}
123+
124+
private URI uri(String path) {
125+
try {
126+
return new URI(protocol, null, host, port, path, null, null);
127+
} catch (URISyntaxException x) {
128+
throw new IllegalArgumentException(x.getMessage(), x);
129+
}
130+
}
131+
132+
private <T> T get(String path, Class<T> type) throws ParseException, IOException {
133+
return get(path, SimpleType.constructUnsafe(type));
134+
}
135+
136+
private <T> T get(String path, JavaType type) throws ParseException, IOException {
137+
return read(new HttpGet(uri(path)), type, HttpStatus.SC_OK);
138+
}
139+
140+
private <T> T delete(String path, Class<T> type) throws ParseException, IOException {
141+
return delete(path, SimpleType.constructUnsafe(type));
142+
}
143+
144+
private <T> T delete(String path, JavaType type) throws ParseException, IOException {
145+
return read(new HttpDelete(uri(path)), type, HttpStatus.SC_OK);
146+
}
147+
148+
private <T> T post(String path, Object request, Class<T> responseType) throws ParseException, IOException {
149+
return post(path, request, SimpleType.constructUnsafe(responseType));
150+
}
151+
152+
private <T> T post(String path, Object request, JavaType responseType) throws ParseException, IOException {
153+
HttpPost post = new HttpPost(uri(path));
154+
String json = objectMapper.writeValueAsString(request);
155+
post.setEntity(new StringEntity(json));
156+
return read(post, responseType, HttpStatus.SC_OK);
157+
}
158+
159+
private <T> T read(ClassicHttpRequest request, Class<T> type, int successCode) throws ParseException, IOException {
160+
return read(request, SimpleType.constructUnsafe(type), successCode);
161+
}
162+
163+
private <T> T read(ClassicHttpRequest request, JavaType type, int successCode) throws IOException, ParseException {
164+
request.setHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_JSON);
165+
HttpHost target = new HttpHost(protocol, host, port);
166+
HttpClientContext localContext = HttpClientContext.create();
167+
if (credentials != null) {
168+
BasicScheme basicAuth = new BasicScheme();
169+
basicAuth.initPreemptive(credentials);
170+
localContext.resetAuthExchange(target, basicAuth);
171+
}
172+
CloseableHttpResponse response = client.execute(request, localContext);
173+
if (response.getCode() == successCode) {
174+
return objectMapper.readValue(EntityUtils.toString(response.getEntity()), type);
175+
}
176+
throw new HttpResponseException(response.getCode(), response.getReasonPhrase());
177+
}
178+
179+
public List<Module> getModules() throws ParseException, IOException {
180+
CollectionType type = objectMapper.getTypeFactory().constructCollectionType(List.class, Module.class);
181+
return get(v1(MODULES), type);
182+
}
183+
184+
public Database createDatabase(Database database) throws ParseException, IOException {
185+
Database response = post(v1(BDBS), database, Database.class);
186+
long uid = response.getUid();
187+
Awaitility.await().until(() -> {
188+
Command command = new Command();
189+
command.setCommand("PING");
190+
try {
191+
return executeCommand(uid, command).getResponse().asBoolean();
192+
} catch (HttpResponseException e) {
193+
log.info("PING unsuccessful, retrying...");
194+
return false;
195+
}
196+
});
197+
return response;
198+
}
199+
200+
public List<Database> getDatabases() throws ParseException, IOException {
201+
CollectionType type = objectMapper.getTypeFactory().constructCollectionType(List.class, Database.class);
202+
return get(v1(BDBS), type);
203+
}
204+
205+
public void deleteDatabase(long uid) {
206+
Awaitility.await().timeout(Duration.ofSeconds(30)).pollInterval(Duration.ofSeconds(1)).until(() -> {
207+
try {
208+
delete(v1(BDBS, String.valueOf(uid)), Database.class);
209+
return true;
210+
} catch (HttpResponseException e) {
211+
if (e.getStatusCode() == HttpStatus.SC_CONFLICT) {
212+
log.info("Could not delete database {}, retrying...", uid);
213+
return false;
214+
}
215+
throw e;
216+
}
217+
});
218+
}
219+
220+
public ModuleInstallResponse installModule(String filename, byte[] bytes) throws ParseException, IOException {
221+
HttpPost post = new HttpPost(uri(v2(MODULES)));
222+
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
223+
builder.setMode(HttpMultipartMode.STRICT);
224+
builder.addPart("module", new ByteArrayBody(bytes, ContentType.MULTIPART_FORM_DATA, filename));
225+
post.setEntity(builder.build());
226+
return read(post, ModuleInstallResponse.class, HttpStatus.SC_ACCEPTED);
227+
}
228+
229+
public Bootstrap getBootstrap() throws ParseException, IOException {
230+
return get(v1(BOOTSTRAP), Bootstrap.class);
231+
}
232+
233+
public Action getAction(String uid) throws ParseException, IOException {
234+
return get(v1(ACTIONS, uid), Action.class);
235+
}
236+
237+
public CommandResponse executeCommand(long bdb, Command command) throws ParseException, IOException {
238+
return post(v1(BDBS, String.valueOf(bdb), COMMAND), command, CommandResponse.class);
239+
}
240+
241+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.redis.enterprise.rest;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
6+
@JsonIgnoreProperties(ignoreUnknown = true)
7+
public class Action {
8+
9+
private String actionUID;
10+
private String moduleUID;
11+
private String name;
12+
private String progress;
13+
private String status;
14+
private String taskID;
15+
16+
public String getActionUID() {
17+
return actionUID;
18+
}
19+
20+
@JsonProperty("action_uid")
21+
public void setActionUID(String actionUID) {
22+
this.actionUID = actionUID;
23+
}
24+
25+
public String getModuleUID() {
26+
return moduleUID;
27+
}
28+
29+
@JsonProperty("module_uid")
30+
public void setModuleUID(String moduleUID) {
31+
this.moduleUID = moduleUID;
32+
}
33+
34+
public String getName() {
35+
return name;
36+
}
37+
38+
public void setName(String name) {
39+
this.name = name;
40+
}
41+
42+
public String getProgress() {
43+
return progress;
44+
}
45+
46+
public void setProgress(String progress) {
47+
this.progress = progress;
48+
}
49+
50+
public String getStatus() {
51+
return status;
52+
}
53+
54+
public void setStatus(String status) {
55+
this.status = status;
56+
}
57+
58+
public String getTaskID() {
59+
return taskID;
60+
}
61+
62+
@JsonProperty("task_id")
63+
public void setTaskID(String taskID) {
64+
this.taskID = taskID;
65+
}
66+
67+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.redis.enterprise.rest;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
6+
@JsonIgnoreProperties(ignoreUnknown = true)
7+
public class Bootstrap {
8+
9+
private Status status;
10+
11+
public Status getStatus() {
12+
return status;
13+
}
14+
15+
@JsonProperty("bootstrap_status")
16+
public void setStatus(Status status) {
17+
this.status = status;
18+
}
19+
20+
@JsonIgnoreProperties(ignoreUnknown = true)
21+
public static class Status {
22+
23+
private String state;
24+
25+
public String getState() {
26+
return state;
27+
}
28+
29+
public void setState(String state) {
30+
this.state = state;
31+
}
32+
33+
}
34+
35+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.redis.enterprise.rest;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import com.fasterxml.jackson.annotation.JsonInclude;
7+
8+
@JsonInclude(JsonInclude.Include.NON_NULL)
9+
public class Command {
10+
11+
private String command;
12+
private List<String> args = new ArrayList<>();
13+
14+
public String getCommand() {
15+
return command;
16+
}
17+
18+
public void setCommand(String command) {
19+
this.command = command;
20+
}
21+
22+
public List<String> getArgs() {
23+
return args;
24+
}
25+
26+
public void setArgs(List<String> args) {
27+
this.args = args;
28+
}
29+
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.redis.enterprise.rest;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
5+
public class CommandResponse {
6+
7+
private JsonNode response;
8+
9+
public JsonNode getResponse() {
10+
return response;
11+
}
12+
13+
public void setResponse(JsonNode response) {
14+
this.response = response;
15+
}
16+
17+
}

0 commit comments

Comments
 (0)