public CompletableFuture executeCommand()

in java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java [217:809]


    public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
        String command = Utils.decodeCommand(params.getCommand(), client.getNbCodeCapabilities());
        switch (command) {
            case Server.NBLS_GRAALVM_PAUSE_SCRIPT:
                ActionsManager am = DebuggerManager.getDebuggerManager().getCurrentEngine().getActionsManager();
                am.doAction("pauseInGraalScript");
                return CompletableFuture.completedFuture(true);
            case Server.NBLS_NEW_FROM_TEMPLATE:
                return LspTemplateUI.createFromTemplate("Templates", client, params);
            case Server.NBLS_NEW_PROJECT:
                return LspTemplateUI.createProject("Templates/Project", client, params);
            case Server.NBLS_BUILD_WORKSPACE: {
                final CommandProgress progressOfCompilation = new CommandProgress();
                final Lookup ctx = Lookups.singleton(progressOfCompilation);
                for (Project prj : server.openedProjects().getNow(OpenProjects.getDefault().getOpenProjects())) {
                    ActionProvider ap = prj.getLookup().lookup(ActionProvider.class);
                    if (ap != null && ap.isActionEnabled(ActionProvider.COMMAND_BUILD, Lookup.EMPTY)) {
                        ap.invokeAction(ActionProvider.COMMAND_REBUILD, ctx);
                    }
                }
                progressOfCompilation.checkStatus();
                return progressOfCompilation.getFinishFuture();
            }
            case Server.NBLS_RUN_PROJECT_ACTION: {
                // TODO: maybe a structure would be better for future compatibility / extensions, i.e. what to place in the action's context Lookup.
                List<FileObject> targets = new ArrayList<>();
                ProjectActionParams actionParams = gson.fromJson(gson.toJson(params.getArguments().get(0)), ProjectActionParams.class);
                String actionName = actionParams.getAction();
                String configName = actionParams.getConfiguration();
                boolean acceptDefault = actionParams.getFallbackDefault() == Boolean.TRUE;
                
                for (int i = 1; i < params.getArguments().size(); i++) {
                    JsonElement item = gson.fromJson(gson.toJson(params.getArguments().get(i)), JsonElement.class);                    
                    if (item.isJsonPrimitive()) {
                        String uri = item.getAsString();
                        FileObject file;
                        try {
                            file = URLMapper.findFileObject(new URL(uri));
                        } catch (MalformedURLException ex) {
                            // TODO: report an invalid parameter or ignore ?
                            continue;
                        }
                        targets.add(file);
                    }
                }
                // also forms invokeAction off the main LSP thread.
                return server.asyncOpenSelectedProjects(targets, false).thenCompose((Project[] owners) -> {
                    Map<Project, List<FileObject>> items = new LinkedHashMap<>();
                    for (int i = 0; i < owners.length; i++) {
                        if (owners[i] == null) {
                            continue;
                        }
                        items.computeIfAbsent(owners[i], (p) -> new ArrayList<>()).add(targets.get(i));
                    }
                    final CommandProgress progressOfCompilation = new CommandProgress();
                    boolean someStarted = false;
                    boolean configNotFound = false;
                    
                    for (Project prj : items.keySet()) {
                        List<Object> ctxObjects = new ArrayList<>();
                        ctxObjects.add(progressOfCompilation);
                        ctxObjects.addAll(items.get(prj));
                        if (!StringUtils.isBlank(configName)) {
                            ProjectConfigurationProvider<ProjectConfiguration> pcp = prj.getLookup().lookup(ProjectConfigurationProvider.class);
                            if (pcp != null) {
                                Optional<ProjectConfiguration> cfg = pcp.getConfigurations().stream().filter(c -> c.getDisplayName().equals(configName)).findAny();
                                if (cfg.isPresent()) {
                                    ctxObjects.add(cfg);
                                } else if (!acceptDefault) {
                                    // TODO: report ? Fail the action ? Fallback to default config ?
                                    configNotFound = true;
                                    continue;
                                }
                            }
                        }
                        // TBD: possibly include project configuration ?
                        final Lookup ctx = Lookups.fixed(ctxObjects.toArray(new Object[0]));
                        ActionProvider ap = prj.getLookup().lookup(ActionProvider.class);
                        if (ap != null && ap.isActionEnabled(actionName, ctx)) {
                            ap.invokeAction(actionName, ctx);
                            someStarted = true;
                        }
                    }
                    if (!configNotFound || !someStarted) {
                        // TODO: print a message like 'nothing to do' in the status bar ?
                        return CompletableFuture.completedFuture(false);
                    }
                    final boolean cfgNotFound = configNotFound;
                    progressOfCompilation.checkStatus();
                    return progressOfCompilation.getFinishFuture().thenApply(b -> (b == Boolean.TRUE) && cfgNotFound);
                });
            }
            case Server.NBLS_CLEAN_WORKSPACE: {
                final CommandProgress progressOfCompilation = new CommandProgress();
                final Lookup ctx = Lookups.singleton(progressOfCompilation);
                for (Project prj : server.openedProjects().getNow(OpenProjects.getDefault().getOpenProjects())) {
                    ActionProvider ap = prj.getLookup().lookup(ActionProvider.class);
                    if (ap != null && ap.isActionEnabled(ActionProvider.COMMAND_CLEAN, Lookup.EMPTY)) {
                        ap.invokeAction(ActionProvider.COMMAND_CLEAN, ctx);
                    }
                }
                progressOfCompilation.checkStatus();
                return progressOfCompilation.getFinishFuture();
            }
            case Server.NBLS_GET_ARCHIVE_FILE_CONTENT: {
                CompletableFuture<Object> future = new CompletableFuture<>();
                try {
                    String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                    FileObject file = Utils.fromUri(uri);
                    if (file != null && file.isData() && file.canRead()) {
                        future.complete(file.asText("UTF-8"));
                    }
                    future.complete(null);
                } catch (IOException ioe) {
                    future.completeExceptionally(ioe);
                }
                return future;
            }
            case Server.JAVA_GET_PROJECT_SOURCE_ROOTS: {
                String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                String type = params.getArguments().size() > 1 ? ((JsonPrimitive) params.getArguments().get(1)).getAsString() : JavaProjectConstants.SOURCES_TYPE_JAVA;
                return getSourceRoots(uri, type).thenApply(roots -> {
                    return roots.stream().map(root -> Utils.toUri(root)).collect(Collectors.toList());
                });
            }
            case Server.JAVA_GET_PROJECT_CLASSPATH: {
                String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                ClasspathInfo.PathKind kind = params.getArguments().size() > 1 ? ClasspathInfo.PathKind.valueOf(((JsonPrimitive) params.getArguments().get(1)).getAsString()) : ClasspathInfo.PathKind.COMPILE;
                boolean preferSources = params.getArguments().size() > 2 ? ((JsonPrimitive) params.getArguments().get(2)).getAsBoolean() : false;
                return getSourceRoots(uri, JavaProjectConstants.SOURCES_TYPE_JAVA).thenApply(roots -> {
                    HashSet<FileObject> cpRoots = new HashSet<>();
                    for(FileObject root : roots) {
                        for (FileObject cpRoot : ClasspathInfo.create(root).getClassPath(kind).getRoots()) {
                            FileObject[] srcRoots = preferSources ? SourceForBinaryQuery.findSourceRoots(cpRoot.toURL()).getRoots() : null;
                            if (srcRoots != null && srcRoots.length > 0) {
                                for (FileObject srcRoot : srcRoots) {
                                    cpRoots.add(srcRoot);
                                }
                            } else {
                                cpRoots.add(cpRoot);
                            }
                        }
                    }
                    return cpRoots.stream().map(fo -> Utils.toUri(fo)).collect(Collectors.toList());
                });
            }
            case Server.JAVA_GET_PROJECT_PACKAGES: {
                String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                boolean srcOnly = params.getArguments().size() > 1 ? ((JsonPrimitive) params.getArguments().get(1)).getAsBoolean() : false;
                return getSourceRoots(uri, JavaProjectConstants.SOURCES_TYPE_JAVA).thenCompose(roots -> {
                    CompletableFuture<Object> future = new CompletableFuture<>();
                    JavaSource js = JavaSource.create(ClasspathInfo.create(ClassPath.EMPTY, ClassPath.EMPTY, ClassPath.EMPTY));
                    try {
                        js.runWhenScanFinished(controller -> {
                            HashSet<String> packages = new HashSet<>();
                            EnumSet<ClassIndex.SearchScope> scope = srcOnly ? EnumSet.of(ClassIndex.SearchScope.SOURCE) : EnumSet.allOf(ClassIndex.SearchScope.class);
                            for(FileObject root : roots) {
                                packages.addAll(ClasspathInfo.create(root).getClassIndex().getPackageNames("", false, scope));
                            }
                            ArrayList<String> ret = new ArrayList<>(packages);
                            Collections.sort(ret);
                            future.complete(ret);
                        }, true);
                    } catch (IOException ex) {
                        future.completeExceptionally(ex);
                    }
                    return future;
                });
            }
            case Server.NBLS_LOAD_WORKSPACE_TESTS: {
                String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                FileObject file;
                try {
                    file = URLMapper.findFileObject(new URL(uri));
                } catch (MalformedURLException ex) {
                    Exceptions.printStackTrace(ex);
                    return CompletableFuture.completedFuture(Collections.emptyList());
                }
                if (file == null) {
                    return CompletableFuture.completedFuture(Collections.emptyList());
                }
                long t = System.currentTimeMillis();
                return server.asyncOpenFileOwner(file).thenCompose(this::getTestRoots).thenCompose(testRoots -> {
                    LOG.log(Level.INFO, "Project {2}: {0} test roots opened in {1}ms", new Object[] { testRoots.size(), (System.currentTimeMillis() - t), file});
                    BiFunction<FileObject, Collection<TestMethodController.TestMethod>, Collection<TestSuiteInfo>> f = (fo, methods) -> {
                        String url = Utils.toUri(fo);
                        Project owner = FileOwnerQuery.getOwner(fo);
                        String moduleName = owner != null ? ProjectUtils.getInformation(owner).getDisplayName(): null;
                        List<String> paths = getModuleTestPaths(owner);
                        String modulePath = firstModulePath(paths, moduleName);
                        Map<String, TestSuiteInfo> suite2infos = new LinkedHashMap<>();
                        for (TestMethodController.TestMethod testMethod : methods) {
                            TestSuiteInfo suite = suite2infos.computeIfAbsent(testMethod.getTestClassName(), name -> {
                                Position pos = testMethod.getTestClassPosition() != null ? Utils.createPosition(fo, testMethod.getTestClassPosition().getOffset()) : null;
                                return new TestSuiteInfo(name, moduleName, modulePath, url, pos != null ? new Range(pos, pos) : null, TestSuiteInfo.State.Loaded, new ArrayList<>());
                            });
                            String id = testMethod.getTestClassName() + ':' + testMethod.method().getMethodName();
                            Position startPos = testMethod.start() != null ? Utils.createPosition(fo, testMethod.start().getOffset()) : null;
                            Position endPos = testMethod.end() != null ? Utils.createPosition(fo, testMethod.end().getOffset()) : startPos;
                            Range range = startPos != null ? new Range(startPos, endPos) : null;
                            suite.getTests().add(new TestSuiteInfo.TestCaseInfo(id, testMethod.method().getMethodName(), url, range, TestSuiteInfo.State.Loaded, null));
                        }
                        return suite2infos.values();
                    };
                    testMethodsListener.compareAndSet(null, (fo, methods) -> {
                        try {
                            for (TestSuiteInfo testSuiteInfo : f.apply(fo, methods)) {
                                client.notifyTestProgress(new TestProgressParams(Utils.toUri(fo), testSuiteInfo));
                            }
                        } catch (Exception e) {
                            Logger.getLogger(WorkspaceServiceImpl.class.getName()).severe(e.getMessage());
                            Exceptions.printStackTrace(e);
                            testMethodsListener.set(null);
                        }
                    });
                    if (openProjectsListener.compareAndSet(null, (evt) -> {
                        if ("openProjects".equals(evt.getPropertyName())) {
                            JavaSource js = JavaSource.create(ClasspathInfo.create(ClassPath.EMPTY, ClassPath.EMPTY, ClassPath.EMPTY));
                            try {
                                js.runWhenScanFinished(controller -> {
                                    List<Project> old = Arrays.asList((Project[]) evt.getOldValue());
                                    for (Project p : (Project[])evt.getNewValue()) {
                                        if (!old.contains(p)) {
                                            getTestRoots(p).thenAccept(tr -> {
                                                for (Entry<FileObject, Collection<TestMethodController.TestMethod>> entry : TestMethodFinder.findTestMethods(tr, testMethodsListener.get()).entrySet()) {
                                                    for (TestSuiteInfo tsi : f.apply(entry.getKey(), entry.getValue())) {
                                                        client.notifyTestProgress(new TestProgressParams(Utils.toUri(entry.getKey()), tsi));
                                                    }
                                                }
                                            });
                                        }
                                    }
                                }, true);
                            } catch (IOException ex) {
                            }
                        }
                    })) {
                        OpenProjects.getDefault().addPropertyChangeListener(WeakListeners.propertyChange(openProjectsListener.get(), OpenProjects.getDefault()));
                    }
                    CompletableFuture<Object> future = new CompletableFuture<>();
                    JavaSource js = JavaSource.create(ClasspathInfo.create(ClassPath.EMPTY, ClassPath.EMPTY, ClassPath.EMPTY));
                    try {
                        js.runWhenScanFinished(controller -> {
                            Map<FileObject, Collection<TestMethodController.TestMethod>> testMethods = TestMethodFinder.findTestMethods(testRoots, testMethodsListener.get());
                            Collection<TestSuiteInfo> suites = new ArrayList<>(testMethods.size());
                            for (Entry<FileObject, Collection<TestMethodController.TestMethod>> entry : testMethods.entrySet()) {
                                suites.addAll(f.apply(entry.getKey(), entry.getValue()));
                            }
                            future.complete(suites);
                        }, true);
                    } catch (IOException ex) {
                        future.completeExceptionally(ex);
                    }
                    return future;
                });
            }
            case Server.NBLS_RESOLVE_STACKTRACE_LOCATION: {
                CompletableFuture<Object> future = new CompletableFuture<>();
                try {
                    if (params.getArguments().size() >= 3) {
                        String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                        String methodName = ((JsonPrimitive) params.getArguments().get(1)).getAsString();
                        String fileName = ((JsonPrimitive) params.getArguments().get(2)).getAsString();
                        FileObject fo = Utils.fromUri(uri);
                        if (fo != null) {
                            ClassPath classPath = ClassPathSupport.createProxyClassPath(new ClassPath[] {
                                ClassPath.getClassPath(fo, ClassPath.EXECUTE),
                                ClassPath.getClassPath(fo, ClassPath.BOOT)
                            });
                            String name = fileName.substring(0, fileName.lastIndexOf('.'));
                            String packageName = methodName.substring(0, methodName.indexOf(name)).replace('.', '/');
                            String resourceName = packageName + name + ".class";
                            List<FileObject> resources = classPath.findAllResources(resourceName);
                            if (resources != null) {
                                for (FileObject resource : resources) {
                                    FileObject root = classPath.findOwnerRoot(resource);
                                    if (root != null) {
                                        URL url = URLMapper.findURL(root, URLMapper.INTERNAL);
                                        SourceForBinaryQuery.Result res = SourceForBinaryQuery.findSourceRoots(url);
                                        FileObject[] rootz = res.getRoots();
                                        for (int i = 0; i < rootz.length; i++) {
                                            String path = packageName + fileName;
                                            FileObject sourceFo = rootz[i].getFileObject(path);
                                            if (sourceFo != null) {
                                                future.complete(Utils.toUri(sourceFo));
                                                return future;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    future.complete(null);
                } catch (IOException ex) {
                    future.completeExceptionally(ex);
                }
                return future;
            }
            case Server.JAVA_SUPER_IMPLEMENTATION:
                String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                Position pos = gson.fromJson(gson.toJson(params.getArguments().get(1)), Position.class);
                return (CompletableFuture)((TextDocumentServiceImpl)server.getTextDocumentService()).superImplementations(uri, pos);
            case Server.NBLS_FIND_PROJECT_CONFIGURATIONS: {
                String fileUri = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                
                FileObject file;
                try {
                    file = URLMapper.findFileObject(new URL(fileUri));
                } catch (MalformedURLException ex) {
                    Exceptions.printStackTrace(ex);
                    return CompletableFuture.completedFuture(Collections.emptyList());
                }

                return findProjectConfigurations(file);
            }
            case Server.JAVA_FIND_DEBUG_ATTACH_CONFIGURATIONS: {
                return AttachConfigurations.findConnectors(client.getNbCodeCapabilities());
            }
            case Server.JAVA_FIND_DEBUG_PROCESS_TO_ATTACH: {
                return AttachConfigurations.findProcessAttachTo(client);
            }
            case Server.NATIVE_IMAGE_FIND_DEBUG_PROCESS_TO_ATTACH: {
                return AttachNativeConfigurations.findProcessAttachTo(client);
            }
            case Server.NBLS_PROJECT_CONFIGURATION_COMPLETION: {
                // We expect one, two or three arguments.
                // The first argument is always the URI of the launch.json file.
                // When not more arguments are provided, all available configurations ought to be provided.
                // When only a second argument is present, it's a map of the current attributes in a configuration,
                // and additional attributes valid in that particular configuration ought to be provided.
                // When a third argument is present, it's an attribute name whose possible values ought to be provided.
                List<Object> arguments = params.getArguments();
                Collection<? extends LaunchConfigurationCompletion> configurations = Lookup.getDefault()
                                                                                           .lookupAll(LaunchConfigurationCompletion.Factory.class)
                                                                                           .stream()
                                                                                           .map(f -> f.createLaunchConfigurationCompletion(client.getNbCodeCapabilities()))
                                                                                           .collect(Collectors.toList());
                List<CompletableFuture<List<CompletionItem>>> completionFutures;
                String configUri = ((JsonPrimitive) arguments.get(0)).getAsString();
                Supplier<CompletableFuture<Project>> projectSupplier = () -> {
                    FileObject file;
                    try {
                        file = URLMapper.findFileObject(new URL(configUri));
                    } catch (MalformedURLException ex) {
                        Exceptions.printStackTrace(ex);
                        return CompletableFuture.completedFuture(null);
                    }
                    return server.asyncOpenFileOwner(file);
                };
                switch (arguments.size()) {
                    case 1:
                        completionFutures = configurations.stream().map(c -> c.configurations(projectSupplier)).collect(Collectors.toList());
                        break;
                    case 2:
                        Map<String, Object> attributes = attributesMap((JsonObject) arguments.get(1));
                        completionFutures = configurations.stream().map(c -> c.attributes(projectSupplier, attributes)).collect(Collectors.toList());
                        break;
                    case 3:
                        attributes = attributesMap((JsonObject) arguments.get(1));
                        String attribute = ((JsonPrimitive) arguments.get(2)).getAsString();
                        completionFutures = configurations.stream().map(c -> c.attributeValues(projectSupplier, attributes, attribute)).collect(Collectors.toList());
                        break;
                    default:
                        StringBuilder classes = new StringBuilder();
                        for (int i = 0; i < arguments.size(); i++) {
                            classes.append(arguments.get(i).getClass().toString());
                        }
                        throw new IllegalStateException("Wrong arguments("+arguments.size()+"): " + arguments + ", classes = " + classes);  // NOI18N
                }
                CompletableFuture<List<CompletionItem>> joinedFuture = CompletableFuture.allOf(completionFutures.toArray(new CompletableFuture[0]))
                        .thenApply(avoid -> completionFutures.stream().flatMap(c -> c.join().stream()).collect(Collectors.toList()));
                return (CompletableFuture<Object>) (CompletableFuture<?>) joinedFuture;
            }
            case Server.NBLS_PROJECT_RESOLVE_PROJECT_PROBLEMS: {
                final CompletableFuture<Object> result = new CompletableFuture<>();
                List<Object> arguments = params.getArguments();
                if (!arguments.isEmpty()) {
                    String fileStr = ((JsonPrimitive) arguments.get(0)).getAsString();
                    FileObject file;
                    try {
                        file = URLMapper.findFileObject(URI.create(fileStr).toURL());
                    } catch (MalformedURLException ex) {
                        result.completeExceptionally(ex);
                        return result;
                    }
                    Project project = FileOwnerQuery.getOwner(file);
                    if (project != null) {
                        ProjectProblemsProvider ppp = project.getLookup().lookup(ProjectProblemsProvider.class);
                        if (ppp != null) {
                            Collection<? extends ProjectProblemsProvider.ProjectProblem> problems = ppp.getProblems();
                            if (!problems.isEmpty()) {
                                WORKER.post(() -> {
                                    List<Pair<ProjectProblemsProvider.ProjectProblem, Future<ProjectProblemsProvider.Result>>> resolvers = new LinkedList<>();
                                    for (ProjectProblemsProvider.ProjectProblem problem : ppp.getProblems()) {
                                        if (problem.isResolvable()) {
                                            resolvers.add(Pair.of(problem, problem.resolve()));
                                        } else {
                                            DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(problem.getDescription(), NotifyDescriptor.Message.ERROR_MESSAGE));
                                        }
                                    }
                                    if (!resolvers.isEmpty()) {
                                        for (Pair<ProjectProblemsProvider.ProjectProblem, Future<ProjectProblemsProvider.Result>> resolver : resolvers) {
                                            try {
                                                if (!resolver.second().get().isResolved()) {
                                                    String message = resolver.second().get().getMessage();
                                                    if (message != null) {
                                                        DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(message, NotifyDescriptor.Message.ERROR_MESSAGE));
                                                    }
                                                }
                                            } catch (ExecutionException ex) {
                                                result.completeExceptionally(ex.getCause());
                                            } catch (InterruptedException ex) {
                                                result.complete(false);
                                                break;
                                            }
                                        }
                                    }
                                    if (!result.isDone()) {
                                        result.complete(true);
                                    }
                                });
                            }
                        }
                    }
                } else {
                    result.completeExceptionally(new IllegalStateException("Expecting file URL as an argument to " + command));
                }
                return result;
            }
            case Server.NBLS_CLEAR_PROJECT_CACHES: {
                // politely clear project manager's cache of "no project" answers
                ProjectManager.getDefault().clearNonProjectCache();
                // impolitely clean the project-based traversal's cache, so any affiliation of intermediate folders will disappear
                ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class);
                CompletableFuture<Boolean> result = new CompletableFuture<>();
                try {
                    Class queryImpl = Class.forName("org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation", true, loader); // NOI18N
                    Method resetMethod = queryImpl.getMethod("reset"); // NOI18N
                    resetMethod.invoke(null);
                    result.complete(true);
                } catch (ReflectiveOperationException ex) {
                    result.completeExceptionally(ex);
                }
                // and finally, let's refresh everything we had opened:
                for (FileObject f : server.getAcceptedWorkspaceFolders()) {
                    f.refresh();
                }
                for (Project p : OpenProjects.getDefault().getOpenProjects()) {
                    p.getProjectDirectory().refresh();
                }
                return (CompletableFuture<Object>) (CompletableFuture<?>)result;
            }
            
            case Server.NBLS_PROJECT_INFO: {
                final CompletableFuture<Object> result = new CompletableFuture<>();
                List<Object> arguments = params.getArguments();
                if (arguments.size() < 1) {
                    result.completeExceptionally(new IllegalArgumentException("Expecting URL or URL[] as an argument to " + command));
                    return result;
                }
                Object o = arguments.get(0);
                URL[] locations = null;
                if (o instanceof JsonArray) {
                    List<URL> locs = new ArrayList<>();
                    JsonArray a = (JsonArray)o;
                    a.forEach((e) -> {
                        if (e instanceof JsonPrimitive) {
                            String s = ((JsonPrimitive)e).getAsString();
                            try {
                                locs.add(new URL(s));
                            } catch (MalformedURLException ex) {
                                throw new IllegalArgumentException("Illegal location: " + s);
                            }
                        }
                    });
                    locations = locs.toArray(new URL[0]);
                } else if (o instanceof JsonPrimitive) {
                    String s = ((JsonPrimitive)o).getAsString();
                    try {
                        locations = new URL[] { new URL(s) };
                    } catch (MalformedURLException ex) {
                        throw new IllegalArgumentException("Illegal location: " + s);
                    }
                }
                if (locations == null || locations.length == 0) {
                    result.completeExceptionally(new IllegalArgumentException("Expecting URL or URL[] as an argument to " + command));
                    return result;
                }
                boolean projectStructure = false;
                boolean actions = false;
                boolean recursive = false;
                
                if (arguments.size() > 1) {
                    Object a2 = arguments.get(1);
                    if (a2 instanceof JsonObject) {
                        JsonObject options = (JsonObject)a2;
                        projectStructure = getOption(options, "projectStructure", false); // NOI18N
                        actions = getOption(options, "actions", false); // NOI18N
                        recursive = getOption(options, "recursive", false); // NOI18N
                    }
                }
                return (CompletableFuture<Object>)(CompletableFuture<?>)new ProjectInfoWorker(locations, projectStructure, recursive, actions).process();
            }
            case Server.JAVA_ENABLE_PREVIEW: {
                String source = ((JsonPrimitive) params.getArguments().get(0)).getAsString();
                String newSourceLevel = params.getArguments().size() > 1 ? ((JsonPrimitive) params.getArguments().get(1)).getAsString()
                                                                         : null;
                FileObject file;
                try {
                    file = URLMapper.findFileObject(new URL(source));
                    if (file != null) {
                        for (Factory factory : Lookup.getDefault().lookupAll(Factory.class)) {
                            PreviewEnabler enabler = factory.enablerFor(file);
                            if (enabler != null) {
                                enabler.enablePreview(newSourceLevel);
                                break;
                            }
                        }
                    }
                } catch (Exception ex) {
                    Exceptions.printStackTrace(ex);
                    return CompletableFuture.completedFuture(Collections.emptyList());
                }
                return CompletableFuture.completedFuture(true);
            }
            case Server.NBLS_DOCUMENT_SYMBOLS: {
                List<DocumentSymbol> result = new ArrayList<>();
                try {
                    List<Object> arguments = params.getArguments();
                    String source = ((JsonPrimitive) arguments.get(0)).getAsString();
                    String query = arguments.size() > 1 ? ((JsonPrimitive)arguments.get(1)).getAsString() : "";
                    FileObject file = Utils.fromUri(source);
                    Document rawDoc = server.getOpenedDocuments().getDocument(source);
                    if (file != null && rawDoc instanceof StyledDocument) {
                        StyledDocument doc = (StyledDocument)rawDoc;
                        for (StructureProvider structureProvider : MimeLookup.getLookup(DocumentUtilities.getMimeType(doc)).lookupAll(StructureProvider.class)) {
                            if (structureProvider != null) {
                                List<StructureElement> structureElements = structureProvider.getStructure(doc);
                                if (!structureElements.isEmpty()) {
                                    for (StructureElement structureElement : structureElements) {
                                        if (structureElement.getName().startsWith(query)) {
                                            DocumentSymbol ds = TextDocumentServiceImpl.structureElement2DocumentSymbol(doc, structureElement);
                                            if (ds != null) {
                                                result.add(ds);
                                            }
                                        }
                                    }
                                };
                            }
                        }
                    }
                } catch (Exception ex) {
                    Exceptions.printStackTrace(ex);
                    return CompletableFuture.completedFuture(Collections.emptyList());
                }
                return CompletableFuture.completedFuture(result);
            }
            case Server.NBLS_GET_DIAGNOSTICS: {
                    List<Object> arguments = params.getArguments();
                    String source = ((JsonPrimitive) arguments.get(0)).getAsString();
                    EnumSet<ErrorProvider.Kind> s;
                    if (arguments.size() > 1 && arguments.get(1) instanceof JsonArray) {
                        s = EnumSet.noneOf(ErrorProvider.Kind.class);
                        for (JsonElement jse : ((JsonArray)arguments.get(1))) {
                            if (jse instanceof JsonPrimitive) {
                                ErrorProvider.Kind k = ErrorProvider.Kind.valueOf(jse.getAsString());
                                s.add(k);
                            }
                        }
                    } else {
                        s = EnumSet.allOf(ErrorProvider.Kind.class);
                    }
                    return (CompletableFuture<Object>)(CompletableFuture)((TextDocumentServiceImpl)server.getTextDocumentService()).computeDiagnostics(source, s);
            }
            case Server.NBLS_GET_SERVER_DIRECTORIES: {
                JsonObject o = new JsonObject();
                o.addProperty("userdir", Places.getUserDirectory().toString());
                o.addProperty("dirs", System.getProperty("netbeans.dirs"));
                o.addProperty("extra.dirs", System.getProperty("netbeans.extra.dirs"));
                o.addProperty("cache", Places.getCacheDirectory().toString());
                o.addProperty("config", FileUtil.toFile(FileUtil.getConfigRoot()).toString());
                return CompletableFuture.completedFuture(o);
            }
            default:
                for (CodeActionsProvider codeActionsProvider : Lookup.getDefault().lookupAll(CodeActionsProvider.class)) {
                    if (codeActionsProvider.getCommands().contains(command)) {
                        return codeActionsProvider.processCommand(client, command, params.getArguments());
                    }
                }
        }
        throw new UnsupportedOperationException("Command not supported: " + params.getCommand());
    }