com.twosigma.beaker.core.rest.UtilRest.java Source code

Java tutorial

Introduction

Here is the source code for com.twosigma.beaker.core.rest.UtilRest.java

Source

/*
 *  Copyright 2014 TWO SIGMA OPEN SOURCE, LLC
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.twosigma.beaker.core.rest;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.twosigma.beaker.core.module.config.BeakerConfig;
import com.twosigma.beaker.shared.module.util.GeneralUtils;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

/**
 * RESTful API for general utilities
 */
@Path("util")
@Produces(MediaType.APPLICATION_JSON)
@Singleton
public class UtilRest {

    private final BeakerConfig bkConfig;
    private final GeneralUtils utils;

    @Inject
    public UtilRest(BeakerConfig bkConfig, GeneralUtils generalUtils) {
        this.bkConfig = bkConfig;
        this.utils = generalUtils;
        resetConfig();
    }

    @GET
    @Path("whoami")
    @Produces(MediaType.TEXT_PLAIN)
    public String whoami(@Context HttpServletRequest request) {
        return "\"" + System.getProperty("user.name") + "\"";
    }

    @GET
    @Path("getVersionInfo")
    @Produces(MediaType.APPLICATION_JSON)
    public String getVersionInfo(@Context HttpServletRequest request) {
        return "{\"buildTime\": \"" + this.bkConfig.getBuildTime() + "\"," + " \"version\":\""
                + this.bkConfig.getVersion() + "\"}";
    }

    @GET
    @Path("allStackTraces")
    public List<Map<String, Object>> getAllStackTraces() {
        List<Map<String, Object>> out = new ArrayList<>();
        Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();

        for (Thread t : allStackTraces.keySet()) {
            Map<String, Object> map = new HashMap<>();
            map.put("thread", t);
            map.put("stackTraces", allStackTraces.get(t));
            out.add(map);
        }

        return out;
    }

    private static String clean(String js) {
        // Remove slash-star comments. This regexp is not correct
        // since it removes comments that are in a string
        // constant. Should really parse. This is why we don't remove
        // double-slash comments, because they are likely to appear
        // (think http://). XXX
        js = js.replaceAll("/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/", "");
        int i, j;
        String tripleQuote = "\"\"\"";
        while ((i = js.indexOf(tripleQuote)) > 0) {
            if ((j = js.indexOf(tripleQuote, i + 1)) < 0) {
                break;
            }
            String pre = js.substring(0, i);
            String lines = js.substring(i + 3, j);
            String post = js.substring(j + 3);
            lines = lines.replaceAll("\n", "\\\\n");
            js = pre + "\"" + lines + "\"" + post;
        }
        return js;
    }

    @GET
    @Path("getDefaultNotebook")
    @Produces(MediaType.TEXT_PLAIN)
    public String getDefaultNotebook() {
        final String defaultNotebookUrl = this.bkConfig.getDefaultNotebookUrl();

        // TODO, assume the url is a file path for now.
        java.nio.file.Path defaultNotebookFile = Paths.get(defaultNotebookUrl);
        String content = this.utils.readFile(defaultNotebookFile);
        if (content == null) {
            System.out.println("Warning, default notebook is empty");
            return "";
        }

        return clean(content);
    }

    /**
     * This function returns a Boolean setting as string. If the setting is null in the preference,
     * it will use the setting in the config, otherwise, what is set in preference is used.
     * @param settingsListName
     * @param configs
     * @param prefs
     * @return
     */
    private static String mergeBooleanSetting(String settingName, JSONObject configs, JSONObject prefs) {
        Boolean sc = (Boolean) configs.get(settingName);
        Boolean sp = (Boolean) prefs.get(settingName);
        Boolean s = (sp != null) ? sp : sc;
        String setting = null;
        if (s != null) {
            if (s.equals(Boolean.TRUE)) {
                setting = "true";
            } else if (s.equals(Boolean.FALSE)) {
                setting = "false";
            }
        }
        return setting;
    }

    /**
     * This function returns a list of settings from the result of merging setting gotten from
     * both the config and preference files and having to-remove items specified in the preference
     * file removed
     * @param settingsListName
     * @param configs
     * @param prefs
     * @return
     */
    private static final String TO_REMOVE_PREFIX = "remove--";

    private static Set<String> mergeListSetting(String settingsListName, JSONObject configs, JSONObject prefs) {
        Set<String> settings = new LinkedHashSet<>();
        Set<String> settingsToRemove = new HashSet<>();
        { // settings from config
            JSONArray s = (JSONArray) configs.get(settingsListName);
            if (s != null) {
                @SuppressWarnings("unchecked")
                Iterator<String> iterator = s.iterator();
                while (iterator.hasNext()) {
                    settings.add(iterator.next());
                }
            }
        }
        { // settings from preference
            JSONArray s = (JSONArray) prefs.get(settingsListName);
            if (s != null) {
                @SuppressWarnings("unchecked")
                Iterator<String> iterator = s.iterator();
                while (iterator.hasNext()) {
                    settings.add(iterator.next());
                }
            }
        }
        { // to-remove settings from preference
            JSONArray s = (JSONArray) prefs.get(TO_REMOVE_PREFIX + settingsListName);
            if (s != null) {
                @SuppressWarnings("unchecked")
                Iterator<String> iterator = s.iterator();
                while (iterator.hasNext()) {
                    settingsToRemove.add(iterator.next());
                }
            }
        }
        settings.removeAll(settingsToRemove);
        return settings;
    }

    private void resetConfig() {
        final String configFileUrl = this.bkConfig.getConfigFileUrl();
        final String preferenceFileUrl = this.bkConfig.getPreferenceFileUrl();

        // TODO, assume the url is a file path for now.
        java.nio.file.Path configFile = Paths.get(configFileUrl);
        java.nio.file.Path preferenceFile = Paths.get(preferenceFileUrl);
        try {
            JSONParser parser = new JSONParser();
            JSONObject configJsonObject = (JSONObject) parser.parse(this.utils.readFile(configFile));
            JSONObject preferenceJsonObject = (JSONObject) parser.parse(this.utils.readFile(preferenceFile));

            String isAllowTracking = mergeBooleanSetting("allow-anonymous-usage-tracking", configJsonObject,
                    preferenceJsonObject);
            setAllowAnonymousTracking(isAllowTracking);

            String isUseAdvancedMode = mergeBooleanSetting("advanced-mode", configJsonObject, preferenceJsonObject);
            setUseAdvancedMode(isUseAdvancedMode);

            this.initPlugins.addAll(mergeListSetting("init", configJsonObject, preferenceJsonObject));
            this.controlPanelMenuPlugins
                    .addAll(mergeListSetting("control-panel-menu-plugins", configJsonObject, preferenceJsonObject));
            this.menuPlugins
                    .addAll(mergeListSetting("notebook-app-menu-plugins", configJsonObject, preferenceJsonObject));
            this.cellMenuPlugins
                    .addAll(mergeListSetting("notebook-cell-menu-plugins", configJsonObject, preferenceJsonObject));

        } catch (ParseException e) {
            throw new RuntimeException("failed getting beaker configurations from config file", e);
        }
    }

    private Boolean isAllowAnonymousTracking = null;

    @POST
    @Path("setAllowAnonymousTracking")
    public void setAllowAnonymousTracking(@FormParam("allow") String allow) {

        if (allow == null) {
            this.isAllowAnonymousTracking = null;
        } else if (allow.equals("true")) {
            this.isAllowAnonymousTracking = Boolean.TRUE;
        } else if (allow.equals("false")) {
            this.isAllowAnonymousTracking = Boolean.FALSE;
        } else {
            this.isAllowAnonymousTracking = null;
        }
        final String preferenceFileUrl = this.bkConfig.getPreferenceFileUrl();

        // TODO, assume the url is a file path for now.
        java.nio.file.Path preferenceFile = Paths.get(preferenceFileUrl);
        try {
            ObjectMapper om = new ObjectMapper();
            TypeReference readType = new TypeReference<HashMap<String, Object>>() {
            };
            Map<String, Object> prefs = om.readValue(preferenceFile.toFile(), readType);
            Boolean oldValue = (Boolean) prefs.get("allow-anonymous-usage-tracking");
            // If value changed, write it to the file too
            if ((this.isAllowAnonymousTracking == null && oldValue != null)
                    || (this.isAllowAnonymousTracking != null
                            && !(this.isAllowAnonymousTracking.equals(oldValue)))) {
                prefs.put("allow-anonymous-usage-tracking", this.isAllowAnonymousTracking);
                om.writerWithDefaultPrettyPrinter().writeValue(preferenceFile.toFile(), prefs);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @GET
    @Path("isAllowAnonymousTracking")
    public Boolean isAllowAnonymousTracking() {
        return this.isAllowAnonymousTracking;
    }

    private Boolean isUseAdvancedMode = null;

    @POST
    @Path("setUseAdvancedMode")
    public void setUseAdvancedMode(@FormParam("advancedmode") String advancedMode) {

        if (advancedMode == null) {
            this.isUseAdvancedMode = null;
        } else if (advancedMode.equals("true")) {
            this.isUseAdvancedMode = Boolean.TRUE;
        } else if (advancedMode.equals("false")) {
            this.isUseAdvancedMode = Boolean.FALSE;
        } else {
            this.isUseAdvancedMode = null;
        }
        final String preferenceFileUrl = this.bkConfig.getPreferenceFileUrl();

        // TODO, assume the url is a file path for now.
        java.nio.file.Path preferenceFile = Paths.get(preferenceFileUrl);
        try {
            ObjectMapper om = new ObjectMapper();
            TypeReference readType = new TypeReference<HashMap<String, Object>>() {
            };
            Map<String, Object> prefs = om.readValue(preferenceFile.toFile(), readType);
            Boolean oldValue = (Boolean) prefs.get("advanced-mode");
            // If value changed, write it to the file too
            if ((this.isUseAdvancedMode == null && oldValue != null)
                    || (this.isUseAdvancedMode != null && !(this.isUseAdvancedMode.equals(oldValue)))) {
                prefs.put("advanced-mode", this.isUseAdvancedMode);
                om.writerWithDefaultPrettyPrinter().writeValue(preferenceFile.toFile(), prefs);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @GET
    @Path("isUseAdvancedMode")
    public Boolean isUseAdvancedMode() {
        return this.isUseAdvancedMode;
    }

    /* Init Plugins */
    private final Set<String> initPlugins = new LinkedHashSet<>();

    @GET
    @Path("getInitPlugins")
    public Set<String> getInitPlugins() {
        return this.initPlugins;
    }

    /* bkApp Menu Plugins */
    private final Set<String> menuPlugins = new LinkedHashSet<>();

    @POST
    @Path("addMenuPlugin")
    public void addMenuPlugin(@FormParam("url") String urlAsString) {
        this.menuPlugins.add(urlAsString);
    }

    @GET
    @Path("getMenuPlugins")
    public Set<String> getMenuPlugins() {
        return this.menuPlugins;
    }

    /* bkControl Menu Plugins */
    private final Set<String> controlPanelMenuPlugins = new LinkedHashSet<>();

    @POST
    @Path("addControlMenuPlugin")
    public void addControlPanelMenuPlugin(@FormParam("url") String urlAsString) {
        this.controlPanelMenuPlugins.add(urlAsString);
    }

    @GET
    @Path("getControlPanelMenuPlugins")
    public Set<String> getControlPanelMenuPlugins() {
        return this.controlPanelMenuPlugins;
    }

    /* bkCell Menu Plugins */
    private final Set<String> cellMenuPlugins = new LinkedHashSet<>();

    @POST
    @Path("addCellMenuPlugin")
    public void addCellMenuPlugin(String p) {
        this.cellMenuPlugins.add(p);
    }

    @GET
    @Path("getCellMenuPlugins")
    public Set<String> getCellMenuPlugins() {
        return this.cellMenuPlugins;
    }

    @GET
    @Path("getMainPage")
    @Produces(MediaType.TEXT_HTML)
    public String getMainPage(@Context HttpServletRequest request) {
        String data = utils.readFile(bkConfig.getMainPageFileName());
        data = data.replace("URL-HASH-TO-REPLACE", bkConfig.getHash());
        return data;
    }

    @GET
    @Path("getPluginPrefs")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getPluginPrefs() {
        return bkConfig.getPluginPrefs();
    }

    @POST
    @Path("setPluginPrefs")
    public void setPluginPrefs(JSONObject pluginPrefs) {
        // Merge pluginPrefs into prefs, and save the file, like the above methods do.
        bkConfig.setPluginPrefs(pluginPrefs);
    }

}