From 4d6de9f41c64d520935e70ed0d58336dbbe89232 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Fri, 31 Jan 2020 09:42:41 +0100 Subject: [PATCH] improve file observer mechanism to work with multiple files --- .../java/AbstractFileToProjectCache.java | 6 +- .../util/SimpleServerFileObserver.java | 14 +-- .../util/SimpleWorkspaceService.java | 49 +++++----- .../commons/util/BasicFileObserver.java | 76 ++++++++++----- .../ide/vscode/commons/util/FileObserver.java | 16 +-- .../vscode/boot/app/SpringSymbolIndex.java | 97 ++++++++++++++----- .../java/utils/SpringIndexerJavaContext.java | 2 +- .../AdHocSpringPropertyIndexProvider.java | 19 +++- .../boot/java/value/test/MockProjects.java | 19 ++-- 9 files changed, 200 insertions(+), 98 deletions(-) diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractFileToProjectCache.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractFileToProjectCache.java index 1f5adfdae..1d5dbe27a 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractFileToProjectCache.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractFileToProjectCache.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -54,8 +54,8 @@ public abstract class AbstractFileToProjectCache

extends protected void attachListeners(File file, P project) { super.attachListeners(file, project); List globPattern = Arrays.asList(file.toString().replace(File.separator, "/")); - subscriptions.add(getFileObserver().onFileChanged(globPattern, (uri) -> performUpdate(project, asyncUpdate, true))); - subscriptions.add(getFileObserver().onFileDeleted(globPattern, (uri) -> { + subscriptions.add(getFileObserver().onFilesChanged(globPattern, (uris) -> performUpdate(project, asyncUpdate, true))); + subscriptions.add(getFileObserver().onFilesDeleted(globPattern, (uris) -> { cache.invalidate(file); notifyProjectDeleted(project); dispose(); diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleServerFileObserver.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleServerFileObserver.java index 340b28eab..f19fabfa9 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleServerFileObserver.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleServerFileObserver.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -41,22 +41,22 @@ public class SimpleServerFileObserver extends BasicFileObserver { } @Override - public String onFileCreated(List globPattern, Consumer handler) { - String subscriptionId = super.onFileCreated(globPattern, handler); + public String onFilesCreated(List globPattern, Consumer handler) { + String subscriptionId = super.onFilesCreated(globPattern, handler); subscribe(subscriptionId, globPattern, FileSystemWatcher.CREATE); return subscriptionId; } @Override - public String onFileChanged(List globPattern, Consumer handler) { - String subscriptionId = super.onFileChanged(globPattern, handler); + public String onFilesChanged(List globPattern, Consumer handler) { + String subscriptionId = super.onFilesChanged(globPattern, handler); subscribe(subscriptionId, globPattern, FileSystemWatcher.CHANGE); return subscriptionId; } @Override - public String onFileDeleted(List globPattern, Consumer handler) { - String subscriptionId = super.onFileDeleted(globPattern, handler); + public String onFilesDeleted(List globPattern, Consumer handler) { + String subscriptionId = super.onFilesDeleted(globPattern, handler); subscribe(subscriptionId, globPattern, FileSystemWatcher.DELETE); return subscriptionId; } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java index 56814edc0..4da85e833 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java @@ -13,14 +13,18 @@ package org.springframework.ide.vscode.commons.languageserver.util; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import java.util.stream.Collectors; import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.DidChangeWatchedFilesParams; import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams; import org.eclipse.lsp4j.ExecuteCommandParams; +import org.eclipse.lsp4j.FileChangeType; +import org.eclipse.lsp4j.FileEvent; import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.WorkspaceFolder; import org.eclipse.lsp4j.WorkspaceFoldersChangeEvent; @@ -31,7 +35,6 @@ import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.util.Assert; import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.FileObserver; -import org.springframework.ide.vscode.commons.util.Log; import com.google.common.collect.ImmutableList; import com.google.gson.JsonElement; @@ -78,29 +81,31 @@ public class SimpleWorkspaceService implements WorkspaceService { @Override public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { - params.getChanges().forEach(event -> { - try { - String uri = event.getUri(); - if (uri != null) { - switch (event.getType()) { - case Created: - fileObserver.notifyFileCreated(uri); - break; - case Changed: - fileObserver.notifyFileChanged(uri); - break; - case Deleted: - fileObserver.notifyFileDeleted(uri); - break; - default: - Log.log("Uknown file change type '" + event.getType() + "' for file: " + uri); - break; - } + try { + Map> collect = + params.getChanges().stream().filter(event -> event.getUri() != null).collect(Collectors.groupingBy(FileEvent::getType)); + + for (FileChangeType type : collect.keySet()) { + String[] docURIs = collect.get(type).stream().map(event -> event.getUri()).toArray(String[]::new); + + switch (type) { + case Created: + fileObserver.notifyFilesCreated(docURIs); + break; + case Changed: + fileObserver.notifyFilesChanged(docURIs); + break; + case Deleted: + fileObserver.notifyFilesDeleted(docURIs); + break; + default: + log.warn("Uknown file change type '" + type + "' for files: " + docURIs); + break; } - } catch (Throwable t) { - Log.log(t); } - }); + } catch (Throwable t) { + log.warn("problem occurred while dispatching file event", t); + } } @Override diff --git a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/BasicFileObserver.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/BasicFileObserver.java index 234b8cbcc..29b4a1e91 100644 --- a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/BasicFileObserver.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/BasicFileObserver.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,9 +12,9 @@ package org.springframework.ide.vscode.commons.util; import java.net.URI; import java.nio.file.FileSystems; -import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; @@ -24,8 +24,6 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.ImmutablePair; -import reactor.core.Disposable; - /** * Basic implementation of File Observer interface * @@ -34,22 +32,22 @@ import reactor.core.Disposable; */ public class BasicFileObserver implements FileObserver { - protected ConcurrentHashMap, Consumer>> createRegistry = new ConcurrentHashMap<>(); - protected ConcurrentHashMap, Consumer>> deleteRegistry = new ConcurrentHashMap<>(); - protected ConcurrentHashMap, Consumer>> changeRegistry = new ConcurrentHashMap<>(); + protected ConcurrentHashMap, Consumer>> createRegistry = new ConcurrentHashMap<>(); + protected ConcurrentHashMap, Consumer>> deleteRegistry = new ConcurrentHashMap<>(); + protected ConcurrentHashMap, Consumer>> changeRegistry = new ConcurrentHashMap<>(); @Override - public String onFileCreated(List globPattern, Consumer handler) { + public String onFilesCreated(List globPattern, Consumer handler) { return registerFileListener(createRegistry, globPattern, handler); } @Override - public String onFileChanged(List globPattern, Consumer handler) { + public String onFilesChanged(List globPattern, Consumer handler) { return registerFileListener(changeRegistry, globPattern, handler); } @Override - public String onFileDeleted(List globPattern, Consumer handler) { + public String onFilesDeleted(List globPattern, Consumer handler) { return registerFileListener(deleteRegistry, globPattern, handler); } @@ -67,34 +65,66 @@ public class BasicFileObserver implements FileObserver { return false; } - private static String registerFileListener(Map, Consumer>> registry, List globPattern, Consumer handler) { + private static String registerFileListener(Map, Consumer>> registry, List globPattern, Consumer handler) { String subscriptionId = UUID.randomUUID().toString(); registry.put(subscriptionId, ImmutablePair.of(globPattern.stream().map(g -> FileSystems.getDefault().getPathMatcher("glob:" + g)).collect(Collectors.toList()), handler)); return subscriptionId; } final public void notifyFileCreated(String uri) { - notify(createRegistry, uri); + notify(createRegistry, new String[] {uri}); + } + + final public void notifyFilesCreated(String[] uris) { + notify(createRegistry, uris); } final public void notifyFileChanged(String uri) { - notify(changeRegistry, uri); + notify(changeRegistry, new String[] {uri}); + } + + final public void notifyFilesChanged(String[] uris) { + notify(changeRegistry, uris); } final public void notifyFileDeleted(String uri) { - notify(deleteRegistry, uri); + notify(deleteRegistry, new String[] {uri}); } - private static void notify(Map, Consumer>> registry, String uri) { - Path path = Paths.get(URI.create(uri)); + final public void notifyFilesDeleted(String[] uris) { + notify(deleteRegistry, uris); + } + + private static void notify(Map, Consumer>> registry, String[] uris) { +// Path path = Paths.get(URI.create(uris)); +// registry.values().stream() +// .filter(pair -> pair.left.stream() +// .filter(matcher -> +// matcher.matches(path) +// ) +// .findFirst() +// .isPresent()) +// .forEach(pair -> pair.right.accept(uris)); +// registry.values().stream() - .filter(pair -> pair.left.stream() - .filter(matcher -> - matcher.matches(path) - ) - .findFirst() - .isPresent()) - .forEach(pair -> pair.right.accept(uri)); + + // create for each consumer with multiple pattern patchers a pair that contains the pair + an array of matching doc URIs + .map(pair -> ImmutablePair.of( + pair, + + // this creates an array of those doc URIs that match at least to one of those pattern matchers + Arrays.stream(uris) + .filter(uri -> + + // keep only URIs for which a matcher succeeds + pair.left.stream() + .filter(matcher -> matcher.matches(Paths.get(URI.create(uri)))) + .findFirst() + .isPresent()) + .toArray(String[]::new))) + + // then call the accept method of each consumer with the generated array of doc URIs + .forEach(superPair -> superPair.left.right.accept(superPair.right)); } } diff --git a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/FileObserver.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/FileObserver.java index 9790550b3..5d0c484be 100644 --- a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/FileObserver.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/FileObserver.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -23,19 +23,19 @@ import reactor.core.Disposable; */ public interface FileObserver { - String onFileCreated(List globPattern, Consumer handler); + String onFilesCreated(List globPattern, Consumer handler); - String onFileChanged(List globPattern, Consumer handler); + String onFilesChanged(List globPattern, Consumer handler); - String onFileDeleted(List globPattern, Consumer handler); + String onFilesDeleted(List globPattern, Consumer handler); boolean unsubscribe(String subscriptionId); - default Disposable onAnyChange(List globPattern, Consumer handler) { + default Disposable onAnyChange(List globPattern, Consumer handler) { String[] ids = { - onFileChanged(globPattern, handler), - onFileCreated(globPattern, handler), - onFileDeleted(globPattern, handler) + onFilesChanged(globPattern, handler), + onFilesCreated(globPattern, handler), + onFilesDeleted(globPattern, handler) }; return () -> { for (String id : ids) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java index fc025d141..9630ede41 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java @@ -194,14 +194,14 @@ public class SpringSymbolIndex implements InitializingBean { public void serverInitialized() { List globPattern = Arrays.asList(springIndexerJava.getFileWatchPatterns()); - getWorkspaceService().getFileObserver().onFileDeleted(globPattern, (file) -> { - deleteDocument(new TextDocumentIdentifier(file).getUri()); + getWorkspaceService().getFileObserver().onFilesDeleted(globPattern, (files) -> { + deleteDocuments(files); }); - getWorkspaceService().getFileObserver().onFileCreated(globPattern, (file) -> { - createDocument(new TextDocumentIdentifier(file).getUri()); + getWorkspaceService().getFileObserver().onFilesCreated(globPattern, (files) -> { + createDocuments(files); }); - getWorkspaceService().getFileObserver().onFileChanged(globPattern, (file) -> { - updateDocument(new TextDocumentIdentifier(file).getUri(), null, "file changed"); + getWorkspaceService().getFileObserver().onFilesChanged(globPattern, (files) -> { + updateDocuments(files, "file changed"); }); } @@ -227,17 +227,17 @@ public class SpringSymbolIndex implements InitializingBean { private void addXmlFileListeners(List globPattern) { removeXmlFileListeners(); - watchXMLDeleteRegistration = getWorkspaceService().getFileObserver().onFileDeleted(globPattern, - (file) -> { - deleteDocument(new TextDocumentIdentifier(file).getUri()); + watchXMLDeleteRegistration = getWorkspaceService().getFileObserver().onFilesDeleted(globPattern, + (files) -> { + deleteDocuments(files); }); - watchXMLCreatedRegistration = getWorkspaceService().getFileObserver().onFileCreated(globPattern, - (file) -> { - createDocument(new TextDocumentIdentifier(file).getUri()); + watchXMLCreatedRegistration = getWorkspaceService().getFileObserver().onFilesCreated(globPattern, + (files) -> { + createDocuments(files); }); - watchXMLChangedRegistration = getWorkspaceService().getFileObserver().onFileChanged(globPattern, - (file) -> { - updateDocument(new TextDocumentIdentifier(file).getUri(), null, "xml changed"); + watchXMLChangedRegistration = getWorkspaceService().getFileObserver().onFilesChanged(globPattern, + (files) -> { + updateDocuments(files, "xml changed"); }); } @@ -346,6 +346,32 @@ public class SpringSymbolIndex implements InitializingBean { } } + public CompletableFuture createDocuments(String[] docURIs) { + synchronized(this) { + List> futures = new ArrayList<>(); + + for (SpringIndexer indexer : this.indexers) { + String[] interestingDocs = getDocumentsInterestingForIndexer(indexer, docURIs); + Map projectsForDocs = getProjectsForDocs(interestingDocs); + Map> projectMapping = getProjectMapping(projectsForDocs); + + for (IJavaProject project : projectMapping.keySet()) { + List docs = projectMapping.get(project); + + try { + UpdatedDoc[] updatedDocs = docs.stream().map(doc -> createUpdatedDoc(doc, null)).toArray(UpdatedDoc[]::new); + futures.add(updateItems(project, updatedDocs, indexer)); + } + catch (Exception e) { + log.error("{}", e); + } + } + } + + return CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()])); + } + } + private JavaProjectFinder projectFinder() { return params.projectFinder; } @@ -454,7 +480,7 @@ public class SpringSymbolIndex implements InitializingBean { try { Optional maybeProject = projectFinder().find(new TextDocumentIdentifier(deletedDocURI)); if (maybeProject.isPresent()) { - DeleteItem deleteItem = new DeleteItem(maybeProject.get(), deletedDocURI, this.indexers); + DeleteItems deleteItem = new DeleteItems(maybeProject.get(), new String[] {deletedDocURI}, this.indexers); return CompletableFuture.runAsync(deleteItem, this.updateQueue); } } @@ -467,6 +493,30 @@ public class SpringSymbolIndex implements InitializingBean { return null; } + public CompletableFuture deleteDocuments(String[] deletedDocURIs) { + synchronized(this) { + try { + List> futures = new ArrayList<>(); + + Map projectsForDocs = getProjectsForDocs(deletedDocURIs); + Map> projectMapping = getProjectMapping(projectsForDocs); + + for (IJavaProject project : projectMapping.keySet()) { + List docURIs = projectMapping.get(project); + + DeleteItems deleteItems = new DeleteItems(project, (String[]) docURIs.toArray(new String[docURIs.size()]), this.indexers); + futures.add(CompletableFuture.runAsync(deleteItems, this.updateQueue)); + } + + return CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()])); + } + catch (Exception e) { + log.error("", e); + return Futures.error(e); + } + } + } + public List getAllSymbols(String query) { if (query != null && query.length() > 0) { synchronized(this.symbols) { @@ -651,24 +701,27 @@ public class SpringSymbolIndex implements InitializingBean { }, this.updateQueue); } - private class DeleteItem implements Runnable { + private class DeleteItems implements Runnable { - private final String docURI; + private final String[] docURIs; private final IJavaProject project; private final SpringIndexer[] indexer; - public DeleteItem(IJavaProject project, String docURI, SpringIndexer[] indexer) { + public DeleteItems(IJavaProject project, String[] docURIs, SpringIndexer[] indexer) { this.project = project; - this.docURI = docURI; + this.docURIs = docURIs; this.indexer = indexer; } @Override public void run() { try { - removeSymbolsByDoc(project, docURI); + for (String doc : this.docURIs) { + removeSymbolsByDoc(project, doc); + } + for (SpringIndexer index : this.indexer) { - index.removeFiles(project, new String[] {docURI}); + index.removeFiles(project, docURIs); } } catch (Exception e) { log.error("{}", e); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java index 18fcf026c..0d2e4147c 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2019 Pivotal, Inc. + * Copyright (c) 2017, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java index 1f7ad557b..dcf3afefb 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,7 +15,9 @@ import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.util.HashSet; import java.util.Properties; +import java.util.Set; import java.util.concurrent.ExecutionException; import org.eclipse.lsp4j.TextDocumentIdentifier; @@ -63,11 +65,20 @@ public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyInd "**/application.properties", "**/application.yml" ), changed -> { - log.debug("File changed: {}", changed); - projectFinder.find(new TextDocumentIdentifier(changed)).ifPresent(project -> { + log.debug("Files changed: {}", (Object[])changed); + + Set affectedProjects = new HashSet<>(); + for (String docURI : changed) { + projectFinder.find(new TextDocumentIdentifier(docURI)).ifPresent(project -> { + affectedProjects.add(project); + }); + } + + for (IJavaProject project : affectedProjects) { log.debug("=> Project changed: {}", project.getElementName()); indexes.invalidate(project); - }); + } + }); } if (documents!=null) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java index 28d400d64..69111014c 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2019 Pivotal, Inc. + * Copyright (c) 2018, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -204,13 +204,16 @@ public class MockProjects { } private static class FileListener { + final PathMatcher matcher; - final Consumer handler; - FileListener(List globPatterns, Consumer listener) { + final Consumer handler; + + FileListener(List globPatterns, Consumer listener) { super(); this.matcher = buildPathMatcher(globPatterns); this.handler = listener; } + private PathMatcher buildPathMatcher(List globPatterns) { if (globPatterns.size()==0) { return path -> true; @@ -241,7 +244,7 @@ public class MockProjects { final Map change_listeners = new HashMap<>(); final Map delete_listeners = new HashMap<>(); - private String add(Map listeners, List globPatterns, Consumer handler) { + private String add(Map listeners, List globPatterns, Consumer handler) { String id = ""+idGen.incrementAndGet(); synchronized (listeners) { listeners.put(id, new FileListener(globPatterns, handler)); @@ -262,25 +265,25 @@ public class MockProjects { synchronized (listeners) { for (FileListener l : listeners.values()) { if (l.matcher.matches(path)) { - l.handler.accept(target.toURI().toString()); + l.handler.accept(new String[] {target.toURI().toString()}); } } } } @Override - public String onFileCreated(List globPattern, Consumer handler) { + public String onFilesCreated(List globPattern, Consumer handler) { return add(create_listeners, globPattern, handler); } @Override - public String onFileChanged(List globPattern, Consumer handler) { + public String onFilesChanged(List globPattern, Consumer handler) { return add(change_listeners, globPattern, handler); } @Override - public String onFileDeleted(List globPattern, Consumer handler) { + public String onFilesDeleted(List globPattern, Consumer handler) { return add(delete_listeners, globPattern, handler); }