package cloudone.internal.nimbostratus;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import cloudone.C1Services;
import cloudone.ServiceFullName;
import cloudone.internal.ApplicationFullName;
import cloudone.internal.dto.PortInfo;
import cloudone.internal.dto.RuntimeIdAndSecCode;
import org.glassfish.jersey.gson.GsonFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Java API for rest cumulonimbus services.
*
* @author Martin Mares (martin.mares at oracle.com)
*/
public class CumulonimbusClient {
private static final Logger LOGGER = LoggerFactory.getLogger(CumulonimbusClient.class);
private static class InstanceHolder {
private static CumulonimbusClient INSTANCE = new CumulonimbusClient();
}
private final Client client;
private volatile WebTarget target;
private volatile String targetUrl;
private RuntimeIdAndSecCode registration;
private CumulonimbusClient() {
client = ClientBuilder.newClient()
.register(GsonFeature.class);
reloadWebTarget();
}
private synchronized void reloadWebTarget() {
int port = 4242; //Default value
//Currently is cumulonimbus just singleton
File dir = new File(C1Services.getInstance().getRuntimeInfo().getHomeDirectory(), "cumulonimbus");
if (dir.exists()) {
File f = new File(dir, "port.txt");
if (f.exists()) {
try (InputStream is = new FileInputStream(f)) {
byte[] buff = new byte[8];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
while ((len = is.read(buff)) > 0) {
baos.write(buff, 0, len);
}
port = Integer.parseInt(baos.toString().trim());
} catch (IOException e) {
LOGGER.warn("Can not open file with cumulonimbus port number. Set default 4242.");
} catch (NumberFormatException nfe) {
throw new RuntimeException("Can NOT parse cumulonimbus port number!");
}
} else {
LOGGER.info("Can not locate cumulonimbus port file. Use default 4242 port.");
}
} else {
LOGGER.info("Can not locate cumulonimbus configuration directory. Use default 4242.");
}
this.targetUrl = "http://localhost:" + port;
this.target = client.target(targetUrl);
}
public String getTargetUrl() {
return targetUrl;
}
private WebTarget addServiceFullName(WebTarget target, ServiceFullName name) {
if (name == null) {
name = C1Services.getInstance().getRuntimeInfo().getServiceFullName();
}
return target
.path(name.getGroupId())
.path(name.getArtifactId())
.path(name.getVersion());
}
private <T> T cumulonimbusCall(final Function<WebTarget, T> f) {
return f.apply(target);
}
public String laterApi(boolean all, Function<WebTarget, String> f) {
WebTarget t;
if (all) {
t = target.path("/later/all");
} else {
t = target.path("/later/any");
}
return f.apply(t);
}
public int reservePort(final boolean admin) throws RuntimeException {
return cumulonimbusCall(target -> {
target = target.path("/configuration/reserve-port");
if (admin) {
target = target.queryParam("scope", "admin");
}
return target
.request(MediaType.TEXT_PLAIN)
.accept(MediaType.TEXT_PLAIN)
.get(Integer.class);
});
}
public synchronized RuntimeIdAndSecCode register() throws RuntimeException {
final PortInfo portInfo = new PortInfo(C1Services.getInstance().getRuntimeInfo());
this.registration = cumulonimbusCall(target -> {
return addServiceFullName(target.path("service"), null)
.request(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.put(Entity.json(portInfo), RuntimeIdAndSecCode.class);
});
return this.registration;
}
public synchronized void unregister() throws RuntimeException {
if (registration == null) {
throw new RuntimeException("Can not unregiter service without registration.");
}
cumulonimbusCall(target -> {
return addServiceFullName(target.path("service"), null)
.path(String.valueOf(registration.getRuntimeId()))
.queryParam("seccode", registration.getSecurityCode())
.request()
.accept(MediaType.APPLICATION_JSON)
.delete();
});
registration = null;
}
public List<ApplicationFullName> getApplicationsForPath(String path, String method) throws RuntimeException {
return cumulonimbusCall(target -> {
return target.path("resource-discovery")
.queryParam("path", path)
.queryParam("method", method)
.request(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.get(new GenericType<ArrayList<ApplicationFullName>>(){});
});
}
public HashMap<Integer, PortInfo> getServicePorts(ServiceFullName serviceName) throws RuntimeException {
return cumulonimbusCall(target -> {
return addServiceFullName(target.path("service"), serviceName)
.request(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.get(new GenericType<HashMap<Integer, PortInfo>>() {});
});
}
public static CumulonimbusClient getInstance() {
return InstanceHolder.INSTANCE;
}
}