ControlService.java [src/csip] Revision: 0904889a146754fe9a6b190735191a13b36f3796  Date: Fri Apr 01 09:14:04 MDT 2016
/*
 * $Id$
 * 
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * 2010-2013, Olaf David and others, Colorado State University.
 *
 * CSIP is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 2.1.
 *
 * CSIP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with CSIP.  If not, see <http://www.gnu.org/licenses/lgpl.txt>.
 */
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.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
     * @return
     * @throws JSONException
     * @throws Exception
     */
    @GET
    @Path("clean")
    @Produces(MediaType.APPLICATION_JSON)
    public String getClean(@Context UriInfo uriInfo) throws JSONException, Exception {
        SessionStore s = Config.getSessionStore();
        Set<String> keys = s.keys(0, 0, null, true);
        int isnull = 0;
        int removed = 0;
        int skipped = 0;
        for (String id : keys) {
            String result = remove(uriInfo, 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 suid
     * @return
     * @throws Exception
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("clean/{suid}")
    public String remove(@Context UriInfo uriInfo, @PathParam("suid") String suid) throws Exception {
        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() throws JSONException {
        Properties p = Config.getProperties();
        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);
    }


    static void updateConfig(Properties p, String key, String value) {
    }


    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(" " + 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(String inputObj) throws JSONException {
        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 {
        ModelSession session = Config.getSessionStore().getSession(suid);
        if (session == null) {
            return JSONUtils.error("suid unknown: " + suid).toString();
        }

        // check the local box first.
        for (ModelDataService.Task modelTask : Config.getModelTasks()) {
            if (modelTask.getService().getSUID().equals(suid)) {
                modelTask.cancel();
                return JSONUtils.ok(suid + " cancelled").toString();
            }
        }

        // 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);
    }

}