ControlService.java [src/csip] Revision: d5970d7c0e30454d24a80dc6a55dd59e3bcbc398 Date: Sat Apr 15 07:53:13 MDT 2017
/*
* $Id$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* a Model-as-a-Service framework, API and application suite.
*
* 2012-2017, Olaf David and others, OMSLab, Colorado State University.
*
* OMSLab licenses this file to you under the MIT license.
* See the LICENSE file in the project root for more information.
*/
package csip;
import csip.Config.SessionStore;
import csip.utils.*;
import java.io.*;
import java.text.DateFormat;
import java.util.*;
import java.util.logging.*;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.client.*;
import javax.ws.rs.core.*;
import org.apache.commons.io.*;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
/**
* ControlService. Use services in this class to control the backend.
*
* @author od
*/
@Path("c")
public class ControlService {
static final Logger LOG = Logger.getLogger(ControlService.class.getName());
/**
* Clean up the whole session store.
*
* @param uriInfo
* @param req
* @return
* @throws JSONException
* @throws Exception
*/
@GET
@Path("clean")
@Produces(MediaType.APPLICATION_JSON)
public String getClean(@Context UriInfo uriInfo, @Context HttpServletRequest req) throws JSONException, Exception {
Config.checkRemoteAccessACL(req);
SessionStore s = Config.getSessionStore();
Set<String> keys = s.keys(0, Integer.MAX_VALUE, null, true);
int isnull = 0;
int removed = 0;
int skipped = 0;
for (String id : keys) {
String result = remove(uriInfo, req, id);
JSONObject r = new JSONObject(result);
if (r.has("isnull")) {
isnull++;
} else if (r.has("removed")) {
removed++;
} else if (r.has("skipped")) {
skipped++;
}
}
JSONObject o = new JSONObject();
o.put("sessions.total", keys.size());
o.put("sessions.removed", removed);
o.put("sessions.isnull", isnull);
o.put("sessions.skipped", skipped);
return o.toString(4);
}
/**
* Remove the session if expired. cleanup also the workspace and results.
*
* @param uriInfo
* @param req
* @param suid
* @return
* @throws Exception
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("clean/{suid}")
public String remove(@Context UriInfo uriInfo, @Context HttpServletRequest req, @PathParam("suid") String suid) throws Exception {
Config.checkRemoteAccessACL(req);
ModelSession session = Config.getSessionStore().getSession(suid);
JSONObject o = new JSONObject();
if (session == null) {
o.put("isnull", 1);
return o.toString();
}
if (session.getNodeIP().equals(Services.LOCAL_IP_ADDR)) {
DateFormat df = Dates.newISOFormat();
String now = df.format(new Date());
String exp = session.getExpDate();
if (exp.compareTo(now) < 0) { // check is zombie that is passt expiration
File res = Services.getResultsDir(suid);
if (res.exists()) {
FileUtils.deleteQuietly(res);
}
File work = Services.getWorkDir(suid);
if (work.exists()) {
FileUtils.deleteQuietly(work);
}
Config.getSessionStore().removeSession(suid);
o.put("removed", 1);
return o.toString();
}
o.put("skipped", 1);
return o.toString();
} else {
String redirect = Services.replaceHostinURI(uriInfo.getBaseUri(), session.getNodeIP());
LOG.info("Redirect query to: " + redirect + "c/clean/" + suid);
javax.ws.rs.client.Client client = ClientBuilder.newClient();
WebTarget service = client.target(redirect + "c/clean/" + suid);
Response response = service.request(MediaType.APPLICATION_JSON).get();
return response.readEntity(String.class);
}
}
/**
* Get the Configuration as JSON.
*
* @return
* @throws JSONException
*/
@GET
@Path("conf")
@Produces(MediaType.APPLICATION_JSON)
public String getJSON(@Context UriInfo uriInfo, @Context HttpServletRequest req) throws JSONException {
Config.checkRemoteAccessACL(req);
Properties p = Config.getMergedProperties();
Map<Object, Object> m = new TreeMap<>();
for (Object key : p.keySet()) {
String key_ = key.toString();
String val = p.get(key).toString();
val = val.replaceAll("password=.+[;]?", "password=****;");
if (key_.toLowerCase().contains("password")) {
val = "****";
}
m.put(key_, val);
}
JSONObject theconfig = new JSONObject(m);
Collection<Config.PostgresChunk> pcs = Config.getPostgresChunks();
// Add PGChunks to output if they exist...
if ((pcs != null) && (pcs.size() > 0)) {
int i = 1;
for (Config.PostgresChunk ch : pcs) {
theconfig.put("pgdb" + i, ch.getJSON());
i++;
}
}
return theconfig.toString(2);
}
// update from properties, this is for silent property update.
static void updateConfig(Properties p1) {
if (p1.isEmpty()) {
return;
}
Properties p = Config.getProperties();
synchronized (p) {
for (String key : p1.stringPropertyNames()) {
String val = p1.getProperty(key);
LOG.info("Set Config: " + key + " = " + val);
p.setProperty(key, val);
}
Config.update();
}
}
// update from YAML, this is for silent property update.
static void updateConfig(Map<String, String> p1) {
if (p1.isEmpty()) {
return;
}
Properties p = Config.getProperties();
synchronized (p) {
for (String key : p1.keySet()) {
String val = p1.get(key);
if (val != null) {
LOG.info("Config => " + key + " = " + val);
p.setProperty(key, val);
}
}
Config.update();
}
}
static String updateConfig(String inputObj) throws JSONException {
Properties p = Config.getProperties();
Collection<Config.PostgresChunk> pcs = Config.getPostgresChunks();
synchronized (p) {
try {
JSONObject o = new JSONObject(inputObj);
Iterator i = o.keys();
while (i.hasNext()) {
String key = i.next().toString();
if (key.trim().equals("#") || key.trim().equals("//") || key.toLowerCase().startsWith("note")) {
continue;
}
LOG.info(" Set Config: " + key + " = " + o.getString(key));
// pg dbs go into the list
if ((key.length() > 4) && (key.startsWith("pgdb")) && (Integer.parseInt(key.substring(4))) > 0) {
JSONObject pgsvr = o.getJSONObject(key);
String name = pgsvr.getString("name");
double minLong = pgsvr.getDouble("minLong");
double maxLong = pgsvr.getDouble("maxLong");
Config.PostgresChunk newchunk = new Config.PostgresChunk(name, minLong, maxLong);
if (!pcs.contains(newchunk)) {
pcs.add(newchunk);
} else {
pcs.remove(newchunk);
pcs.add(newchunk);
}
LOG.info("adding " + name + " for " + minLong + " to " + maxLong);
} else {
// all other items go into properties collection
p.setProperty(key, o.getString(key));
}
}
} catch (JSONException | NumberFormatException ex) {
LOG.log(Level.WARNING, null, ex);
return "Error: " + ex.getMessage();
}
Config.update();
}
LOG.log(Level.INFO, "config complete");
JSONObject theconfig = new JSONObject(new TreeMap<>(p));
// Add PGChunks to output if they exist...
if ((pcs != null) && (pcs.size() > 0)) {
int i = 1;
for (Config.PostgresChunk ch : pcs) {
theconfig.put("pgdb" + i, ch.getJSON());
i++;
}
}
return theconfig.toString(2);
}
/**
* Change the configuration.
*
* @param inputObj
* @return
* @throws JSONException
*/
@POST
@Path("conf")
@Consumes(MediaType.APPLICATION_JSON)
public String putJSON(@Context UriInfo uriInfo, @Context HttpServletRequest req, String inputObj) throws JSONException {
LOG.log(Level.INFO, "HTTP/POST {0}", uriInfo.getRequestUri().toString() + " " + inputObj);
Config.checkRemoteAccessACL(req);
return updateConfig(inputObj);
}
/**
* Cancel the request.
*
* @param uriInfo
* @param suid
* @return
* @throws JSONException
*/
@GET
@Path("cancel/{suid}")
@Produces(MediaType.APPLICATION_JSON)
public String cancel(@Context UriInfo uriInfo, @PathParam("suid") String suid) throws Exception {
LOG.log(Level.INFO, "HTTP/GET {0}", uriInfo.getRequestUri().toString());
ModelSession session = Config.getSessionStore().getSession(suid);
if (session == null) {
return JSONUtils.error("suid unknown: " + suid).toString();
}
if (session.getNodeIP().equals(Services.LOCAL_IP_ADDR)) {
// check the local box first.
for (ModelDataService.Task modelTask : Config.getModelTasks()) {
if (modelTask.getService().getSUID().equals(suid)) {
modelTask.cancel();
LOG.log(Level.INFO, "canceled " + suid);
return JSONUtils.ok(suid + " canceled").toString();
}
}
LOG.log(Level.WARNING, " not found to cancel: " + suid);
return JSONUtils.error("suid unknown: " + suid).toString();
} else {
// redrection here
// where is that session?
String redirect = Services.replaceHostinURI(uriInfo.getBaseUri(), session.getNodeIP());
javax.ws.rs.client.Client client = ClientBuilder.newClient();
WebTarget service = client.target(UriBuilder.fromUri(redirect + "c/cancel/" + suid).build());
return service.request().get().readEntity(String.class);
}
}
@GET
@Path("cleanresults")
@Produces(MediaType.APPLICATION_JSON)
public String dropResults(@Context UriInfo uriInfo) {
LOG.log(Level.INFO, "HTTP/GET {0}", uriInfo.getRequestUri().toString());
Config.getResultStore().purge();
return JSONUtils.ok("purged").toString();
}
}