Search in sources :

Example 6 with RestServiceException

use of au.gov.asd.tac.constellation.webserver.restapi.RestServiceException in project constellation by constellation-app.

the class RunPlugins method callService.

@Override
public void callService(final PluginParameters parameters, InputStream in, OutputStream out) throws IOException {
    final String graphId = parameters.getStringValue(GRAPH_ID_PARAMETER_ID);
    final Graph graph = graphId == null ? RestUtilities.getActiveGraph() : GraphNode.getGraph(graphId);
    if (graph == null) {
        throw new RestServiceException(HTTP_UNPROCESSABLE_ENTITY, "No graph with id " + graphId);
    }
    final String runStyle = parameters.getStringValue(RUN_IN_PARAMETER_ID);
    if (!RUN_STYLE_SERIES.equals(runStyle) && !RUN_STYLE_PARALLEL.equals(runStyle)) {
        final String msg = String.format("%s must be '%s' or '%s'", RUN_IN_PARAMETER_ID, RUN_STYLE_SERIES, RUN_STYLE_PARALLEL);
        throw new RestServiceException(HTTP_UNPROCESSABLE_ENTITY, msg);
    }
    // First, collect all the plugins and their optional arguments.
    // 
    final ObjectMapper mapper = new ObjectMapper();
    final JsonNode json = mapper.readTree(in);
    if (!json.isArray()) {
        final String msg = String.format("Argument for %s must be a list", NAME);
        throw new RestServiceException(HTTP_UNPROCESSABLE_ENTITY, msg);
    }
    final ConcurrentLinkedQueue<PluginError> errorQueue = new ConcurrentLinkedQueue<>();
    final ArrayNode pluginList = (ArrayNode) json;
    final List<PluginInstance> pluginInstances = new ArrayList<>();
    pluginList.forEach(pluginItem -> {
        if (!pluginItem.has(PLUGIN_NAME) || !pluginItem.get(PLUGIN_NAME).isTextual()) {
            final String msg = String.format("Each plugin argument must have %s", PLUGIN_NAME);
            throw new RestServiceException(HTTP_UNPROCESSABLE_ENTITY, msg);
        }
        final String pluginName = pluginItem.get(PLUGIN_NAME).textValue();
        final Plugin plugin = PluginRegistry.get(pluginName);
        final PluginParameters pluginParameters = plugin.createParameters();
        if (pluginParameters != null && pluginItem.has(PLUGIN_ARGS)) {
            final ObjectNode pluginArgs = (ObjectNode) pluginItem.get(PLUGIN_ARGS);
            RestServiceUtilities.parametersFromJson(pluginArgs, pluginParameters);
        }
        pluginInstances.add(new PluginInstance(graph, plugin, pluginParameters, errorQueue));
    });
    // 
    if (runStyle.equals(RUN_STYLE_SERIES)) {
        pluginInstances.forEach(PluginInstance::run);
    } else {
        final List<Thread> pluginThreads = new ArrayList<>();
        pluginInstances.forEach(pi -> {
            final Thread thread = new Thread(pi, pi.plugin.getName());
            pluginThreads.add(thread);
            thread.start();
        });
        pluginThreads.forEach(thread -> {
            try {
                thread.join();
            } catch (final InterruptedException ex) {
                thread.interrupt();
                errorQueue.add(new PluginError(String.format("Thread %s", thread.getName()), ex));
            }
        });
    }
    // The plugins have finished, so look at the error queue to see if anything
    // didn't work. If there are errors, pass them back.
    // 
    final StringBuilder buf = new StringBuilder();
    while (!errorQueue.isEmpty()) {
        buf.append(errorQueue.remove().toString());
    }
    if (buf.length() > 0) {
        throw new RestServiceException(buf.toString());
    }
}
Also used : ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) RestServiceException(au.gov.asd.tac.constellation.webserver.restapi.RestServiceException) Graph(au.gov.asd.tac.constellation.graph.Graph) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) PluginParameters(au.gov.asd.tac.constellation.plugins.parameters.PluginParameters) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) Plugin(au.gov.asd.tac.constellation.plugins.Plugin)

Example 7 with RestServiceException

use of au.gov.asd.tac.constellation.webserver.restapi.RestServiceException in project constellation by constellation-app.

the class RestServiceServlet method callService.

private void callService(final HttpMethod httpMethod, final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
    // Which service is being called?
    // 
    final String serviceName = request.getPathInfo().substring(1);
    // Get an instance of the service (if it exists).
    // 
    final RestService rs = RestServiceRegistry.get(serviceName, httpMethod);
    // Convert the arguments in the URL of the request to PluginParameters.
    // 
    final PluginParameters parameters = rs.createParameters();
    final Map<String, String[]> paramMap = request.getParameterMap();
    paramMap.entrySet().forEach(entry -> {
        final String parameterName = entry.getKey();
        if (parameters.hasParameter(parameterName)) {
            final PluginParameter<?> param = parameters.getParameters().get(parameterName);
            if (entry.getValue().length == 1) {
                param.setStringValue(entry.getValue()[0]);
            } else {
                throw new RestServiceException("Service parameters do not accept multiple values");
            }
        } else {
            throw new RestServiceException(String.format("Service '%s' has no parameter '%s'", serviceName, parameterName));
        }
    });
    // 
    try {
        response.setContentType(rs.getMimeType());
        response.setStatus(HttpServletResponse.SC_OK);
        rs.callService(parameters, request.getInputStream(), response.getOutputStream());
    } catch (final RestServiceException ex) {
        throw ex;
    } catch (final IOException | RuntimeException ex) {
        throw new ServletException(ex);
    }
}
Also used : RestServiceException(au.gov.asd.tac.constellation.webserver.restapi.RestServiceException) ServletException(jakarta.servlet.ServletException) PluginParameters(au.gov.asd.tac.constellation.plugins.parameters.PluginParameters) IOException(java.io.IOException) RestService(au.gov.asd.tac.constellation.webserver.restapi.RestService)

Example 8 with RestServiceException

use of au.gov.asd.tac.constellation.webserver.restapi.RestServiceException in project constellation by constellation-app.

the class SetGraphValues method callService.

@Override
public void callService(final PluginParameters parameters, InputStream in, OutputStream out) throws IOException {
    final String graphId = parameters.getStringValue(GRAPH_ID_PARAMETER_ID);
    final Graph graph = graphId == null ? RestUtilities.getActiveGraph() : GraphNode.getGraph(graphId);
    if (graph == null) {
        throw new RestServiceException(HTTP_UNPROCESSABLE_ENTITY, "No graph with id " + graphId);
    }
    // We want to read a JSON document that looks like:
    // 
    // {"columns":["A","B"],"data":[[1,"a"]]}
    // 
    // which is what is output by pandas.to_json(..., orient="split').
    // (We ignore the index array.)
    final ObjectMapper mapper = new ObjectMapper();
    final JsonNode json = mapper.readTree(in);
    if (!json.hasNonNull(COLUMNS) || !json.get(COLUMNS).isArray()) {
        throw new RestServiceException(HTTP_UNPROCESSABLE_ENTITY, "Could not find columns object containing column names");
    }
    if (!json.hasNonNull("data") || !json.get("data").isArray()) {
        throw new RestServiceException(HTTP_UNPROCESSABLE_ENTITY, "Could not find data object containing data rows");
    }
    final ArrayNode columns = (ArrayNode) json.get(COLUMNS);
    final ArrayNode data = (ArrayNode) json.get("data");
    // Do we have one and only one row of data?
    if (data.size() != 1) {
        throw new RestServiceException("Must have one row of data");
    }
    final ArrayNode row = (ArrayNode) data.get(0);
    // Do the number of column headers and the number of data elements in the row match?
    if (columns.size() != row.size()) {
        throw new RestServiceException("Column names do not match data row");
    }
    setGraphAttributes(graph, columns, row);
}
Also used : RestServiceException(au.gov.asd.tac.constellation.webserver.restapi.RestServiceException) Graph(au.gov.asd.tac.constellation.graph.Graph) JsonNode(com.fasterxml.jackson.databind.JsonNode) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Example 9 with RestServiceException

use of au.gov.asd.tac.constellation.webserver.restapi.RestServiceException in project constellation by constellation-app.

the class SetGraphValues method setGraphAttributes.

private static void setGraphAttributes(final Graph graph, final ArrayNode columns, final ArrayNode row) {
    final Plugin p = new SetGraphAttributesFromRestApiPlugin(columns, row);
    final PluginExecution pe = PluginExecution.withPlugin(p);
    try {
        pe.executeNow(graph);
    } catch (final InterruptedException ex) {
        Thread.currentThread().interrupt();
        throw new RestServiceException(ex);
    } catch (final PluginException ex) {
        throw new RestServiceException(ex);
    }
}
Also used : RestServiceException(au.gov.asd.tac.constellation.webserver.restapi.RestServiceException) PluginExecution(au.gov.asd.tac.constellation.plugins.PluginExecution) PluginException(au.gov.asd.tac.constellation.plugins.PluginException) SimpleEditPlugin(au.gov.asd.tac.constellation.plugins.templates.SimpleEditPlugin) Plugin(au.gov.asd.tac.constellation.plugins.Plugin)

Example 10 with RestServiceException

use of au.gov.asd.tac.constellation.webserver.restapi.RestServiceException in project constellation by constellation-app.

the class FileListener method run.

/**
 * Run the file listener thread.
 * <p>
 * Poll the listener directory looking for the REQUEST_JSON file. It assumed
 * that the client has already written the CONTENT_IN file if required.
 * <p>
 * When REQUEST_JSON is found, read and extract the verb + endpoint + path +
 * args. Call the multi-level switch statement that figures out what to do.
 * Some of these will write CONTENT_OUT. Ensure that CONTENT_IN is deleted
 * when we've finished with it. Ensure that REQUEST_JSON is deleted when
 * we're finished with it. Last of all, write the RESPONSE_JSON file: this
 * is what the client will be polling on. An empty JSON document implies
 * success. A JSON document with the "error" key is failure, with the
 * explanation in the value. The client will delete RESPONSE_JSON and
 * CONTENT_OUT.
 */
@Override
public void run() {
    // Download the Python REST client if enabled.
    final Preferences prefs = NbPreferences.forModule(ApplicationPreferenceKeys.class);
    final boolean pythonRestClientDownload = prefs.getBoolean(ApplicationPreferenceKeys.PYTHON_REST_CLIENT_DOWNLOAD, ApplicationPreferenceKeys.PYTHON_REST_CLIENT_DOWNLOAD_DEFAULT);
    if (pythonRestClientDownload) {
        WebServer.downloadPythonClient();
    }
    StatusDisplayer.getDefault().setStatusText(String.format("Starting file listener in directory %s", restPath));
    running = true;
    // We start the poll sleep time at MIN_POLL_SLEEP.
    // If the listener doesn't find any files, the sleep time will slowly get longer up to MAX_POLL_SLEEP,
    // so the filesystem doesn't get pounded as much.
    // When a request is found, the poll sleep time is reset to MIN_POLL_SLEEP.
    long pollSleep = MIN_POLL_SLEEP;
    try {
        while (running) {
            final String[] files = restPath.toFile().list();
            for (final String f : files) {
                if (f.equals(REQUEST_JSON)) {
                    // If any other files are required, write this file last, so the other files are already present.
                    LOGGER.info(String.format("Found REST file %s", f));
                    final Path p = restPath.resolve(f);
                    JsonNode json = null;
                    try (final InputStream in = new FileInputStream(p.toFile())) {
                        final ObjectMapper mapper = new ObjectMapper();
                        json = mapper.readTree(in);
                    } catch (final IOException ex) {
                        response(ex.getMessage());
                    }
                    try {
                        Files.delete(p);
                    } catch (final IOException ex) {
                        LOGGER.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
                    }
                    if (json != null) {
                        // If content (JSON or otherwise) is required, it gets delivered in a separate CONTENT_DATA file.
                        if (json.hasNonNull("verb") && json.hasNonNull(ENDPOINT) && json.hasNonNull("path")) {
                            final String verb = json.get("verb").textValue();
                            final String endpoint = json.get(ENDPOINT).textValue();
                            final String path = json.get("path").textValue();
                            final JsonNode args = json.get("args");
                            try {
                                // Display the incoming REST request to provide some confidence to the user and debugging for the developer :-).
                                final String msg = String.format("File REST API: %s %s %s", verb, endpoint, path);
                                StatusDisplayer.getDefault().setStatusText(msg);
                                parseAndExecute(verb, endpoint, path, args);
                                response();
                            } catch (final RestServiceException ex) {
                                response(ex.getMessage());
                            } catch (final Exception ex) {
                                response(ex.getMessage());
                                LOGGER.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
                            }
                        } else {
                            response("Request must contain verb + endpoint + path");
                        }
                    }
                    // Reset the poll sleep after a successful request,
                    // since we're obviously being used.
                    pollSleep = MIN_POLL_SLEEP;
                }
            }
            // Slowly sneak the poll sleep time up to a maximum.
            pollSleep = Math.min(pollSleep + 1, MAX_POLL_SLEEP);
            Thread.sleep(pollSleep);
        }
    } catch (final InterruptedException ex) {
        Thread.currentThread().interrupt();
        stop();
        LOGGER.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
    }
    StatusDisplayer.getDefault().setStatusText(String.format("Stopped file listener in directory %s", restPath));
}
Also used : Path(java.nio.file.Path) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) JsonNode(com.fasterxml.jackson.databind.JsonNode) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) RestServiceException(au.gov.asd.tac.constellation.webserver.restapi.RestServiceException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) RestServiceException(au.gov.asd.tac.constellation.webserver.restapi.RestServiceException) Preferences(java.util.prefs.Preferences) NbPreferences(org.openide.util.NbPreferences) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Aggregations

RestServiceException (au.gov.asd.tac.constellation.webserver.restapi.RestServiceException)19 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)12 Graph (au.gov.asd.tac.constellation.graph.Graph)10 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)8 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)7 Plugin (au.gov.asd.tac.constellation.plugins.Plugin)5 PluginParameters (au.gov.asd.tac.constellation.plugins.parameters.PluginParameters)5 JsonNode (com.fasterxml.jackson.databind.JsonNode)5 IOException (java.io.IOException)4 ReadableGraph (au.gov.asd.tac.constellation.graph.ReadableGraph)3 PluginException (au.gov.asd.tac.constellation.plugins.PluginException)3 RestService (au.gov.asd.tac.constellation.webserver.restapi.RestService)3 GraphNode (au.gov.asd.tac.constellation.graph.node.GraphNode)2 GraphRecordStore (au.gov.asd.tac.constellation.graph.processing.GraphRecordStore)2 SimpleEditPlugin (au.gov.asd.tac.constellation.plugins.templates.SimpleEditPlugin)2 HandleIoProgress (au.gov.asd.tac.constellation.utilities.gui.HandleIoProgress)2 HttpMethod (au.gov.asd.tac.constellation.webserver.restapi.RestServiceUtilities.HttpMethod)2 FileNotFoundException (java.io.FileNotFoundException)2 StoreGraph (au.gov.asd.tac.constellation.graph.StoreGraph)1 GraphJsonReader (au.gov.asd.tac.constellation.graph.file.io.GraphJsonReader)1