diff --git a/dashboard/src/app/workspaces/create-workspace/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts b/dashboard/src/app/workspaces/create-workspace/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts index 0682267e0df..5346e403687 100644 --- a/dashboard/src/app/workspaces/create-workspace/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts +++ b/dashboard/src/app/workspaces/create-workspace/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts @@ -108,12 +108,19 @@ export class ImportGithubProjectController { * The list of selected repositories. */ private selectedRepositories: Array; + /** + * Keycloak auth service. + */ + private keycloakAuth: any; /** * Default constructor that is using resource * @ngInject for Dependency injection */ - constructor ($q: ng.IQService, $mdDialog: ng.material.IDialogService, $location: ng.ILocationService, $browser: ng.IBrowserService, $scope: ng.IScope, githubPopup: any, cheBranding: CheBranding, githubOrganizationNameResolver: any, importGithubProjectService: ImportGithubProjectService, cheListHelperFactory: che.widget.ICheListHelperFactory, addImportProjectService: AddImportProjectService) { + constructor ($q: ng.IQService, $mdDialog: ng.material.IDialogService, $location: ng.ILocationService, + $browser: ng.IBrowserService, $scope: ng.IScope, githubPopup: any, cheBranding: CheBranding, + githubOrganizationNameResolver: any, importGithubProjectService: ImportGithubProjectService, + cheListHelperFactory: che.widget.ICheListHelperFactory, addImportProjectService: AddImportProjectService, keycloakAuth: any) { this.$q = $q; this.$mdDialog = $mdDialog; this.$location = $location; @@ -123,6 +130,7 @@ export class ImportGithubProjectController { this.githubOrganizationNameResolver = githubOrganizationNameResolver; this.resolveOrganizationName = this.githubOrganizationNameResolver.resolve; this.addImportProjectService = addImportProjectService; + this.keycloakAuth = keycloakAuth; this.importGithubProjectService = importGithubProjectService; this.productName = cheBranding.getName(); @@ -209,6 +217,24 @@ export class ImportGithubProjectController { return; } + if (this.keycloakAuth.isPresent) { + this.keycloakAuth.keycloak.updateToken(5).success(() => { + let token = '&token=' + this.keycloakAuth.keycloak.token; + this.openGithubPopup(token); + }).error(() => { + this.keycloakAuth.keycloak.login(); + }); + } else { + this.openGithubPopup(''); + } + } + + /** + * Opens Github popup. + * + * @param {string} token + */ + openGithubPopup(token: string): void { const redirectUrl = this.$location.protocol() + '://' + this.$location.host() + ':' + this.$location.port() @@ -218,6 +244,7 @@ export class ImportGithubProjectController { + '?oauth_provider=github' + '&scope=' + ['user', 'repo', 'write:public_key'].join(',') + '&userId=' + this.importGithubProjectService.getCurrentUserId() + + token + '&redirect_after_login=' + redirectUrl, { diff --git a/dashboard/src/components/github/github-service.ts b/dashboard/src/components/github/github-service.ts index 52eea7b731f..30681d44c0c 100644 --- a/dashboard/src/components/github/github-service.ts +++ b/dashboard/src/components/github/github-service.ts @@ -82,7 +82,7 @@ export class GitHubService { } catch (error) { } - if (popupWindow.closed) { + if (popupWindow && popupWindow.closed) { $interval.cancel(polling); deferred.reject({data: 'Authorization Failed'}); } diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakEnvironmentInitalizationFilter.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakEnvironmentInitalizationFilter.java index 81f5fbfe1c9..afe827a33dd 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakEnvironmentInitalizationFilter.java +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakEnvironmentInitalizationFilter.java @@ -17,6 +17,7 @@ import io.jsonwebtoken.Jwt; import java.io.IOException; import java.security.Principal; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; import javax.servlet.FilterChain; @@ -107,19 +108,30 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha private User getOrCreateUser(String id, String email, String username) throws ServerException, ConflictException { - try { - return userManager.getById(id); - } catch (NotFoundException e) { + Optional user = getUser(id); + if (!user.isPresent()) { synchronized (this) { - final UserImpl cheUser = new UserImpl(id, email, username, generate("", 12), emptyList()); - try { - return userManager.create(cheUser, false); - } catch (ConflictException ex) { - cheUser.setName(generate(cheUser.getName(), 4)); - return userManager.create(cheUser, false); + user = getUser(id); + if (!user.isPresent()) { + final UserImpl cheUser = new UserImpl(id, email, username, generate("", 12), emptyList()); + try { + return userManager.create(cheUser, false); + } catch (ConflictException ex) { + cheUser.setName(generate(cheUser.getName(), 4)); + return userManager.create(cheUser, false); + } } } } + return user.get(); + } + + private Optional getUser(String id) throws ServerException { + try { + return Optional.of(userManager.getById(id)); + } catch (NotFoundException e) { + return Optional.empty(); + } } private HttpServletRequest addUserInRequest( diff --git a/plugins/plugin-java-debugger/che-plugin-java-debugger-server/src/test/java/org/eclipse/che/plugin/jdb/server/util/ProjectApiUtils.java b/plugins/plugin-java-debugger/che-plugin-java-debugger-server/src/test/java/org/eclipse/che/plugin/jdb/server/util/ProjectApiUtils.java index 3a4b161a553..05855377841 100644 --- a/plugins/plugin-java-debugger/che-plugin-java-debugger-server/src/test/java/org/eclipse/che/plugin/jdb/server/util/ProjectApiUtils.java +++ b/plugins/plugin-java-debugger/che-plugin-java-debugger-server/src/test/java/org/eclipse/che/plugin/jdb/server/util/ProjectApiUtils.java @@ -31,7 +31,6 @@ import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider; @@ -91,8 +90,6 @@ private static void init() throws Exception { ProjectImporterRegistry importerRegistry = new ProjectImporterRegistry(new HashSet<>()); FileWatcherNotificationHandler fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider); - FileTreeWatcher fileTreeWatcher = - new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler); ProjectManager projectManager = new ProjectManager( vfsProvider, @@ -102,7 +99,6 @@ private static void init() throws Exception { projectHandlerRegistry, importerRegistry, fileWatcherNotificationHandler, - fileTreeWatcher, workspaceHolder, mock(FileWatcherManager.class)); @@ -121,6 +117,7 @@ private static void init() throws Exception { } private static class TestWorkspaceHolder extends WorkspaceProjectsSyncer { + private List projects; TestWorkspaceHolder(List projects) { diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/rest/JavaFormatterServiceTest.java b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/rest/JavaFormatterServiceTest.java index 4a0f9d2e50b..2204f2604fc 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/rest/JavaFormatterServiceTest.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/rest/JavaFormatterServiceTest.java @@ -39,7 +39,6 @@ import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider; @@ -60,6 +59,7 @@ /** Test for the java formatter service. */ @Listeners(value = {MockitoTestNGListener.class}) public class JavaFormatterServiceTest { + private static final String FORMATTER_CONTENT = "\n" + "\n" @@ -109,8 +109,6 @@ protected void initProjectApi() throws Exception { ProjectImporterRegistry importerRegistry = new ProjectImporterRegistry(new HashSet<>()); FileWatcherNotificationHandler fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider); - FileTreeWatcher fileTreeWatcher = - new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler); projectManager = new ProjectManager( vfsProvider, @@ -120,7 +118,6 @@ protected void initProjectApi() throws Exception { projectHandlerRegistry, importerRegistry, fileWatcherNotificationHandler, - fileTreeWatcher, workspaceHolder, mock(FileWatcherManager.class)); @@ -243,6 +240,7 @@ private void checkProjectFormatterFile() throws IOException { } private static class TestWorkspaceHolder extends WorkspaceProjectsSyncer { + private List projects; TestWorkspaceHolder() { diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java index 6e6b2a68986..9ff39a66abf 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java @@ -34,7 +34,6 @@ import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider; @@ -55,6 +54,7 @@ /** @author Valeriy Svydenko */ public abstract class BaseTest { + private static final String wsPath = BaseTest.class.getResource("/projects").getFile(); private static final String INDEX_PATH = "target/fs_index"; @@ -70,7 +70,9 @@ protected void initProjectApi() throws Exception { TestWorkspaceHolder workspaceHolder = new TestWorkspaceHolder(); - if (root == null) root = new File(wsPath); + if (root == null) { + root = new File(wsPath); + } if (root.exists()) { IoUtil.deleteRecursive(root); @@ -109,9 +111,6 @@ protected void initProjectApi() throws Exception { ProjectImporterRegistry importerRegistry = new ProjectImporterRegistry(new HashSet<>()); FileWatcherNotificationHandler fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider); - FileTreeWatcher fileTreeWatcher = - new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler); - projectManager = new ProjectManager( vfsProvider, @@ -121,7 +120,6 @@ protected void initProjectApi() throws Exception { projectHandlerRegistry, importerRegistry, fileWatcherNotificationHandler, - fileTreeWatcher, new TestWorkspaceHolder(new ArrayList<>()), mock(FileWatcherManager.class)); diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/BaseTest.java b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/BaseTest.java index cb18c172562..f1117e19e68 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/BaseTest.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/BaseTest.java @@ -40,7 +40,6 @@ import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider; @@ -83,7 +82,6 @@ public abstract class BaseTest { protected LocalVirtualFileSystemProvider vfsProvider; protected ProjectRegistry projectRegistry; protected FileWatcherNotificationHandler fileWatcherNotificationHandler; - protected FileTreeWatcher fileTreeWatcher; protected ProjectTypeRegistry projectTypeRegistry; protected ProjectHandlerRegistry projectHandlerRegistry; protected ProjectImporterRegistry importerRegistry; @@ -111,7 +109,9 @@ protected void initProjectApi() throws Exception { mavenServerManager = new MavenServerManager(mavenServerPath); workspaceHolder = new TestWorkspaceHolder(); - if (root == null) root = new File(wsPath); + if (root == null) { + root = new File(wsPath); + } if (root.exists()) { IoUtil.deleteRecursive(root); @@ -149,7 +149,6 @@ protected void initProjectApi() throws Exception { importerRegistry = new ProjectImporterRegistry(new HashSet<>()); fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider); - fileTreeWatcher = new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler); pm = new ProjectManager( @@ -160,7 +159,6 @@ protected void initProjectApi() throws Exception { projectHandlerRegistry, importerRegistry, fileWatcherNotificationHandler, - fileTreeWatcher, new TestWorkspaceHolder(new ArrayList<>()), mock(FileWatcherManager.class)); diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/BaseTest.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/BaseTest.java index 9045719610d..8b1e2d5a8b2 100644 --- a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/BaseTest.java +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/BaseTest.java @@ -32,7 +32,6 @@ import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider; @@ -69,7 +68,6 @@ public abstract class BaseTest { protected LocalVirtualFileSystemProvider vfsProvider; protected ProjectRegistry projectRegistry; protected FileWatcherNotificationHandler fileWatcherNotificationHandler; - protected FileTreeWatcher fileTreeWatcher; protected ProjectTypeRegistry projectTypeRegistry; protected ProjectHandlerRegistry projectHandlerRegistry; protected ProjectImporterRegistry importerRegistry; @@ -131,7 +129,6 @@ protected void initProjectApi() throws Exception { importerRegistry = new ProjectImporterRegistry(new HashSet<>()); fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider); - fileTreeWatcher = new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler); pm = new ProjectManager( @@ -142,7 +139,6 @@ protected void initProjectApi() throws Exception { projectHandlerRegistry, importerRegistry, fileWatcherNotificationHandler, - fileTreeWatcher, new TestWorkspaceHolder(new ArrayList<>()), Mockito.mock(FileWatcherManager.class)); diff --git a/pom.xml b/pom.xml index 1da2dc4054d..25f4afbf6fa 100644 --- a/pom.xml +++ b/pom.xml @@ -819,7 +819,7 @@ org.eclipse.che.multiuser che-multiuser-personal-account - ${project.version} + ${che.version} org.eclipse.che.multiuser diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java index 18917dfd4a6..8da68a9cfa1 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java @@ -55,7 +55,6 @@ import org.eclipse.che.api.vfs.VirtualFile; import org.eclipse.che.api.vfs.VirtualFileSystem; import org.eclipse.che.api.vfs.VirtualFileSystemProvider; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationListener; import org.eclipse.che.api.vfs.search.Searcher; @@ -81,7 +80,6 @@ public class ProjectManager { private final ProjectRegistry projectRegistry; private final ProjectHandlerRegistry handlers; private final ProjectImporterRegistry importers; - private final FileTreeWatcher fileWatcher; private final FileWatcherNotificationHandler fileWatchNotifier; private final ExecutorService executor; private final WorkspaceProjectsSyncer workspaceProjectsHolder; @@ -98,7 +96,6 @@ public ProjectManager( ProjectHandlerRegistry handlers, ProjectImporterRegistry importers, FileWatcherNotificationHandler fileWatcherNotificationHandler, - FileTreeWatcher fileTreeWatcher, WorkspaceProjectsSyncer workspaceProjectsHolder, FileWatcherManager fileWatcherManager) throws ServerException { @@ -109,7 +106,6 @@ public ProjectManager( this.handlers = handlers; this.importers = importers; this.fileWatchNotifier = fileWatcherNotificationHandler; - this.fileWatcher = fileTreeWatcher; this.workspaceProjectsHolder = workspaceProjectsHolder; this.fileWatcherManager = fileWatcherManager; @@ -164,12 +160,6 @@ public void onFileWatcherEvent(VirtualFile virtualFile, FileWatcherEventType eve } }; fileWatchNotifier.addNotificationListener(defaultListener); - try { - fileWatcher.startup(); - } catch (IOException e) { - LOG.error(e.getMessage(), e); - fileWatchNotifier.removeNotificationListener(defaultListener); - } } @PreDestroy @@ -198,13 +188,9 @@ public void removeWatchListener(FileWatcherNotificationListener listener) { fileWatchNotifier.removeNotificationListener(listener); } - public void addWatchExcludeMatcher(PathMatcher matcher) { - fileWatcher.addExcludeMatcher(matcher); - } + public void addWatchExcludeMatcher(PathMatcher matcher) {} - public void removeWatchExcludeMatcher(PathMatcher matcher) { - fileWatcher.removeExcludeMatcher(matcher); - } + public void removeWatchExcludeMatcher(PathMatcher matcher) {} /** * @return all the projects diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/DefaultFileWatcherNotificationHandler.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/DefaultFileWatcherNotificationHandler.java index a8bc21d76d0..b690cbbd05c 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/DefaultFileWatcherNotificationHandler.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/DefaultFileWatcherNotificationHandler.java @@ -27,6 +27,7 @@ @Singleton public class DefaultFileWatcherNotificationHandler implements FileWatcherNotificationHandler { + private static final Logger LOG = LoggerFactory.getLogger(DefaultFileWatcherNotificationHandler.class); @@ -93,6 +94,7 @@ private VirtualFile convertToVirtualFile(File root, String subPath, boolean isDi } private static class DeletedLocalVirtualFile extends LocalVirtualFile { + private final boolean isDir; DeletedLocalVirtualFile( diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcher.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcher.java deleted file mode 100644 index 321dc5ba493..00000000000 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcher.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.vfs.impl.file; - -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; -import static com.google.common.collect.Sets.newLinkedHashSet; -import static java.nio.file.FileVisitResult.CONTINUE; -import static java.nio.file.Files.getLastModifiedTime; -import static java.nio.file.LinkOption.NOFOLLOW_LINKS; -import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; -import static java.nio.file.StandardWatchEventKinds.OVERFLOW; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.CREATED; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.DELETED; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.MODIFIED; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.io.File; -import java.io.IOException; -import java.nio.file.ClosedWatchServiceException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.WatchEvent; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicBoolean; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType; -import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class FileTreeWatcher { - private static final Logger LOG = LoggerFactory.getLogger(FileTreeWatcher.class); - - private static final long EVENT_PROCESS_TIMEOUT_SEC = 2; - - private final File watchRoot; - private final Path watchRootPath; - private final Map watchedDirectories; - private final List excludePatterns; - private final FileWatcherNotificationHandler fileWatcherNotificationHandler; - private final ExecutorService executor; - private final AtomicBoolean running; - private WatchService watchService; - private WatchEvent.Modifier[] watchEventModifiers; - - @Inject - public FileTreeWatcher( - @Named("che.user.workspaces.storage") File watchRoot, - @Named("vfs.index_filter_matcher") Set excludePatterns, - FileWatcherNotificationHandler fileWatcherNotificationHandler) { - watchEventModifiers = new WatchEvent.Modifier[0]; - this.watchRoot = toCanonicalFile(watchRoot); - this.watchRootPath = this.watchRoot.toPath(); - this.excludePatterns = newArrayList(excludePatterns); - this.fileWatcherNotificationHandler = fileWatcherNotificationHandler; - - ThreadFactory threadFactory = - new ThreadFactoryBuilder() - .setDaemon(true) - .setUncaughtExceptionHandler(LoggingUncaughtExceptionHandler.getInstance()) - .setNameFormat("FileTreeWatcher-%d") - .build(); - executor = Executors.newSingleThreadExecutor(threadFactory); - running = new AtomicBoolean(); - watchedDirectories = newHashMap(); - } - - private static File toCanonicalFile(File file) { - try { - return file.getCanonicalFile(); - } catch (IOException e) { - throw new IllegalArgumentException(e.getMessage(), e); - } - } - - public void startup() throws IOException { - watchService = FileSystems.getDefault().newWatchService(); - if (isPollingWatchService(watchService)) { - watchEventModifiers = new WatchEvent.Modifier[] {createSensitivityWatchEventModifier()}; - } - running.set(true); - walkTreeAndSetupWatches(watchRootPath); - executor.execute(new WatchEventTask()); - fileWatcherNotificationHandler.started(watchRoot); - } - - private boolean isPollingWatchService(WatchService watchService) { - return "sun.nio.fs.PollingWatchService".equals(watchService.getClass().getName()); - } - - private WatchEvent.Modifier createSensitivityWatchEventModifier() { - try { - Class aModifierEnum = Class.forName("com.sun.nio.file.SensitivityWatchEventModifier"); - Object[] sensitivityEnumConstants = aModifierEnum.getEnumConstants(); - return (WatchEvent.Modifier) sensitivityEnumConstants[0]; - } catch (Exception e) { - LOG.warn("Can't create 'com.sun.nio.file.SensitivityWatchEventModifier'", e); - } - return null; - } - - public void shutdown() { - boolean interrupted = false; - executor.shutdown(); - try { - if (!executor.awaitTermination(3, SECONDS)) { - executor.shutdownNow(); - if (!executor.awaitTermination(3, SECONDS)) { - LOG.warn("Unable terminate Executor"); - } - } - } catch (InterruptedException e) { - interrupted = true; - executor.shutdownNow(); - } - - try { - walkTreeAndRemoveWatches(watchRootPath); - } catch (IOException e) { - LOG.warn(e.getMessage()); - } - - try { - watchService.close(); - } catch (IOException e) { - LOG.warn(e.getMessage()); - } - - if (interrupted) { - Thread.currentThread().interrupt(); - } - } - - public void addExcludeMatcher(PathMatcher exclude) { - this.excludePatterns.add(exclude); - } - - public void removeExcludeMatcher(PathMatcher exclude) { - this.excludePatterns.remove(exclude); - } - - private void walkTreeAndSetupWatches(Path root) throws IOException { - Files.walkFileTree( - root, - new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) - throws IOException { - Path relativePath = watchRootPath.relativize(dir); - if (shouldNotify(relativePath)) { - setupDirectoryWatcher(dir); - } - return CONTINUE; - } - }); - } - - private boolean shouldNotify(Path subPath) { - for (PathMatcher excludePattern : excludePatterns) { - if (excludePattern.matches(subPath)) { - return false; - } - } - return true; - } - - private void walkTreeAndRemoveWatches(Path root) throws IOException { - Files.walkFileTree( - root, - new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) - throws IOException { - cancelDirectoryWatcher(dir); - return CONTINUE; - } - }); - } - - private void walkTreeAndFireCreatedEvents(Path root) throws IOException { - Files.walkFileTree( - root, - new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) - throws IOException { - if (!dir.equals(root)) { - fireWatchEvent(CREATED, dir, true); - } - return CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - fireWatchEvent(CREATED, file, false); - return CONTINUE; - } - }); - } - - private void setupDirectoryWatcher(Path directory) throws IOException { - if (watchedDirectories.get(directory) == null) { - WatchKey watchKey = - directory.register( - watchService, - new WatchEvent.Kind[] {ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY, OVERFLOW}, - watchEventModifiers); - WatchedDirectory watchedDirectory = new WatchedDirectory(directory, watchKey); - try (DirectoryStream entries = Files.newDirectoryStream(directory)) { - for (Path entry : entries) { - watchedDirectory.addItem( - new DirectoryItem( - entry.getFileName(), Files.isDirectory(entry), getLastModifiedInMillis(entry))); - - if (Files.isDirectory(entry)) { - setupDirectoryWatcher(entry); - } - } - } - watchedDirectories.put(directory, watchedDirectory); - } - } - - private void cancelDirectoryWatcher(Path path) { - WatchedDirectory watchedDirectory = watchedDirectories.remove(path); - if (watchedDirectory != null) { - watchedDirectory.getWatchKey().cancel(); - } - } - - private class WatchEventTask implements Runnable { - final Set pendingEvents = newLinkedHashSet(); - - @Override - public void run() { - while (running.get()) { - try { - WatchKey watchKey; - if (pendingEvents.isEmpty()) { - watchKey = watchService.take(); - } else { - watchKey = watchService.poll(EVENT_PROCESS_TIMEOUT_SEC, SECONDS); - if (watchKey == null) { - processPendingEvents(pendingEvents); - pendingEvents.clear(); - } - } - if (watchKey != null) { - pendingEvents.add(new PendingEvent((Path) watchKey.watchable())); - watchKey.pollEvents(); - watchKey.reset(); - } - } catch (InterruptedException | ClosedWatchServiceException e) { - running.set(false); - } catch (Throwable e) { - running.set(false); - fileWatcherNotificationHandler.errorOccurred(watchRoot, e); - } - } - } - } - - private void processPendingEvents(Collection pendingEvents) throws IOException { - for (PendingEvent pendingEvent : pendingEvents) { - Path eventDirectoryPath = pendingEvent.getPath(); - WatchedDirectory watchedDirectory = watchedDirectories.get(eventDirectoryPath); - if (watchedDirectory == null) { - continue; - } - if (Files.exists(eventDirectoryPath)) { - boolean isModifiedNotYetReported = true; - - final int hitCounter = watchedDirectory.incrementHitCounter(); - try (DirectoryStream entries = Files.newDirectoryStream(eventDirectoryPath)) { - for (Path fsItem : entries) { - DirectoryItem directoryItem = watchedDirectory.getItem(fsItem.getFileName()); - if (directoryItem == null) { - try { - boolean directory = Files.isDirectory(fsItem); - directoryItem = - new DirectoryItem( - fsItem.getFileName(), directory, getLastModifiedInMillis(fsItem)); - watchedDirectory.addItem(directoryItem); - if (isModifiedNotYetReported) { - isModifiedNotYetReported = false; - fireWatchEvent(MODIFIED, eventDirectoryPath, true); - } - fireWatchEvent(CREATED, fsItem, directoryItem.isDirectory()); - if (directory) { - walkTreeAndFireCreatedEvents(fsItem); - setupDirectoryWatcher(fsItem); - } - } catch (IOException ignored) { - } - } else { - long lastModified; - try { - lastModified = getLastModifiedInMillis(fsItem); - } catch (IOException ignored) { - continue; - } - if (lastModified != directoryItem.getLastModified() && Files.isRegularFile(fsItem)) { - fireWatchEvent(MODIFIED, fsItem, false); - } - directoryItem.touch(lastModified); - directoryItem.updateHitCounter(hitCounter); - } - } - } - - for (Iterator iterator = watchedDirectory.getItems().iterator(); - iterator.hasNext(); - ) { - DirectoryItem directoryItem = iterator.next(); - if (hitCounter != directoryItem.getHitCount()) { - iterator.remove(); - if (isModifiedNotYetReported) { - isModifiedNotYetReported = false; - fireWatchEvent(MODIFIED, eventDirectoryPath, true); - } - fireWatchEvent( - DELETED, - eventDirectoryPath.resolve(directoryItem.getName()), - directoryItem.isDirectory()); - } - } - } else { - for (DirectoryItem directoryItem : watchedDirectory.getItems()) { - fireWatchEvent( - DELETED, - eventDirectoryPath.resolve(directoryItem.getName()), - directoryItem.isDirectory()); - } - watchedDirectories.remove(eventDirectoryPath); - } - } - } - - private void fireWatchEvent(FileWatcherEventType eventType, Path eventPath, boolean isDirectory) { - Path relativePath = watchRootPath.relativize(eventPath); - if (shouldNotify(relativePath)) { - fileWatcherNotificationHandler.handleFileWatcherEvent( - eventType, watchRoot, relativePath.toString(), isDirectory); - } - } - - private long getLastModifiedInMillis(Path path) throws IOException { - return getLastModifiedTime(path, NOFOLLOW_LINKS).toMillis(); - } - - static class PendingEvent { - final Path path; - - PendingEvent(Path path) { - this.path = path; - } - - Path getPath() { - return path; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o instanceof PendingEvent) { - PendingEvent other = (PendingEvent) o; - return Objects.equals(path, other.path); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hashCode(path); - } - } - - static class WatchedDirectory { - final Path path; - final WatchKey watchKey; - final List items; - int hitCounter; - - WatchedDirectory(Path path, WatchKey watchKey) { - this.path = path; - this.watchKey = watchKey; - items = newArrayList(); - } - - WatchKey getWatchKey() { - return watchKey; - } - - Path getPath() { - return path; - } - - DirectoryItem getItem(Path name) { - for (DirectoryItem item : items) { - if (item.getName().equals(name)) { - return item; - } - } - return null; - } - - void addItem(DirectoryItem item) { - item.updateHitCounter(this.hitCounter); - items.add(item); - } - - List getItems() { - return items; - } - - int incrementHitCounter() { - return ++hitCounter; - } - } - - static class DirectoryItem { - final Path name; - final boolean directory; - long lastModified; - int hitCounter; - - DirectoryItem(Path name, boolean directory, long lastModified) { - this.name = name; - this.directory = directory; - this.lastModified = lastModified; - } - - long getLastModified() { - return lastModified; - } - - Path getName() { - return name; - } - - boolean isDirectory() { - return directory; - } - - void touch(long lastModified) { - this.lastModified = lastModified; - } - - int getHitCount() { - return hitCounter; - } - - void updateHitCounter(int hitCounter) { - this.hitCounter = hitCounter; - } - } -} diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ExtensionCasesTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ExtensionCasesTest.java index d3ef9156d60..e831e6a891a 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ExtensionCasesTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ExtensionCasesTest.java @@ -72,7 +72,6 @@ public void setUp() throws Exception { projectHandlerRegistry, null, fileWatcherNotificationHandler, - fileTreeWatcher, workspaceHolder, fileWatcherManager); pm.initWatcher(); diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerReadTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerReadTest.java index a0e30e69e1b..f20ff8fc3a7 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerReadTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerReadTest.java @@ -84,7 +84,6 @@ public void setUp() throws Exception { projectHandlerRegistry, null, fileWatcherNotificationHandler, - fileTreeWatcher, workspaceHolder, fileWatcherManager); pm.initWatcher(); diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java index 5f19ff7167c..cf9640afc8f 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java @@ -99,7 +99,6 @@ import org.eclipse.che.api.vfs.Path; import org.eclipse.che.api.vfs.VirtualFile; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider; @@ -250,9 +249,6 @@ public void setUp() throws Exception { FileWatcherNotificationHandler fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider); - FileTreeWatcher fileTreeWatcher = - new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler); - pm = new ProjectManager( vfsProvider, @@ -262,7 +258,6 @@ public void setUp() throws Exception { phRegistry, importerRegistry, fileWatcherNotificationHandler, - fileTreeWatcher, workspaceHolder, fileWatcherManager); pm.initWatcher(); diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java index be6f039aa53..567ebdd11f4 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java @@ -34,7 +34,6 @@ import org.eclipse.che.api.project.server.type.ValueProviderFactory; import org.eclipse.che.api.project.server.type.ValueStorageException; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; -import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider; @@ -63,8 +62,6 @@ public class WsAgentTestBase { protected FileWatcherNotificationHandler fileWatcherNotificationHandler; - protected FileTreeWatcher fileTreeWatcher; - protected ProjectTypeRegistry projectTypeRegistry; protected ProjectHandlerRegistry projectHandlerRegistry; @@ -116,7 +113,6 @@ public void setUp() throws Exception { this.importerRegistry = new ProjectImporterRegistry(new HashSet<>()); fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider); - fileTreeWatcher = new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler); fileWatcherManager = mock(FileWatcherManager.class); workspaceSyncCommunication = mock(WorkspaceSyncCommunication.class); TestWorkspaceHolder wsHolder = new TestWorkspaceHolder(); @@ -130,7 +126,6 @@ public void setUp() throws Exception { projectHandlerRegistry, importerRegistry, fileWatcherNotificationHandler, - fileTreeWatcher, wsHolder, fileWatcherManager); pm.initWatcher(); diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcherMassiveIoOperationTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcherMassiveIoOperationTest.java deleted file mode 100644 index 3cc79d56457..00000000000 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcherMassiveIoOperationTest.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.vfs.impl.file; - -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Sets.newHashSet; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.CREATED; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.DELETED; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.MODIFIED; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.File; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; -import org.eclipse.che.commons.lang.IoUtil; -import org.eclipse.che.commons.lang.NameGenerator; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -public class FileTreeWatcherMassiveIoOperationTest { - private FileTreeWatcher fileTreeWatcher; - private File testDirectory; - private FileWatcherTestTree fileWatcherTestTree; - - @Before - public void setUp() throws Exception { - File targetDir = - new File(Thread.currentThread().getContextClassLoader().getResource(".").getPath()) - .getParentFile(); - testDirectory = new File(targetDir, NameGenerator.generate("watcher-", 4)); - assertTrue(testDirectory.mkdir()); - fileWatcherTestTree = new FileWatcherTestTree(testDirectory); - } - - @After - public void tearDown() throws Exception { - if (fileTreeWatcher != null) { - fileTreeWatcher.shutdown(); - } - IoUtil.deleteRecursive(testDirectory); - } - - @Test - public void watchesTreeCreation() throws Exception { - FileWatcherNotificationHandler notificationListener = aNotificationListener(); - fileTreeWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationListener); - fileTreeWatcher.startup(); - Thread.sleep(500); - - List allFilesAndDirs = fileWatcherTestTree.createTree("", 7, 5); - - Thread.sleep(5000); - - verify(notificationListener, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor createdEvents = ArgumentCaptor.forClass(String.class); - verify(notificationListener, times(allFilesAndDirs.size())) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), createdEvents.capture(), anyBoolean()); - assertThatCollectionsContainsSameItemsOrFailWithDiff( - createdEvents.getAllValues(), allFilesAndDirs); - } - - @Test - public void watchesTreeDeletion() throws Exception { - List allFilesAndDirs = fileWatcherTestTree.createTree("", 7, 5); - Thread.sleep(100); - - FileWatcherNotificationHandler notificationListener = aNotificationListener(); - fileTreeWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationListener); - fileTreeWatcher.startup(); - Thread.sleep(5000); - - assertTrue(fileWatcherTestTree.delete("")); - - Thread.sleep(5000); - - verify(notificationListener, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(CREATED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor deletedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationListener, times(allFilesAndDirs.size())) - .handleFileWatcherEvent( - eq(DELETED), eq(testDirectory), deletedEvents.capture(), anyBoolean()); - assertThatCollectionsContainsSameItemsOrFailWithDiff( - deletedEvents.getAllValues(), allFilesAndDirs); - } - - @Test - public void watchesUpdatesAllFilesInTree() throws Exception { - fileWatcherTestTree.createTree("", 7, 5); - Thread.sleep(100); - - FileWatcherNotificationHandler notificationListener = aNotificationListener(); - fileTreeWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationListener); - fileTreeWatcher.startup(); - Thread.sleep(5000); - - List updated = fileWatcherTestTree.findAllFilesInTree(""); - - for (String file : updated) { - fileWatcherTestTree.updateFile(file); - } - - Thread.sleep(5000); - - verify(notificationListener, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(CREATED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor updatedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationListener, times(updated.size())) - .handleFileWatcherEvent( - eq(MODIFIED), eq(testDirectory), updatedEvents.capture(), anyBoolean()); - assertThatCollectionsContainsSameItemsOrFailWithDiff(updatedEvents.getAllValues(), updated); - } - - @Test - public void watchesUpdatesFilesInTree() throws Exception { - fileWatcherTestTree.createTree("", 7, 5); - Thread.sleep(100); - - FileWatcherNotificationHandler notificationListener = aNotificationListener(); - fileTreeWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationListener); - fileTreeWatcher.startup(); - Thread.sleep(5000); - - List updated = - fileWatcherTestTree - .findAllFilesInTree("") - .stream() - .filter(path -> path.hashCode() % 2 == 0) - .collect(Collectors.toList()); - - for (String file : updated) { - fileWatcherTestTree.updateFile(file); - } - - Thread.sleep(5000); - - verify(notificationListener, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(CREATED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationListener, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor updatedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationListener, times(updated.size())) - .handleFileWatcherEvent( - eq(MODIFIED), eq(testDirectory), updatedEvents.capture(), anyBoolean()); - assertThatCollectionsContainsSameItemsOrFailWithDiff(updatedEvents.getAllValues(), updated); - } - - @Test - public void watchesMixedActionsInTree() throws Exception { - fileWatcherTestTree.createTree("", 7, 5); - Thread.sleep(100); - - FileWatcherNotificationHandler notificationListener = aNotificationListener(); - fileTreeWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationListener); - fileTreeWatcher.startup(); - Thread.sleep(5000); - - List allFiles = fileWatcherTestTree.findAllFilesInTree(""); - List updated = newArrayList(allFiles.subList(0, allFiles.size() / 2)); - List deleted = newArrayList(allFiles.subList(allFiles.size() / 2, allFiles.size())); - List directories = fileWatcherTestTree.findAllDirectoriesInTree(""); - List created = newArrayList(); - - for (String directory : directories) { - created.add(fileWatcherTestTree.createFile(directory)); - } - - for (String file : deleted) { - fileWatcherTestTree.delete(file); - } - - Thread.sleep(5000); - - updated.addAll(created.subList(0, created.size() / 2)); - for (String file : updated) { - fileWatcherTestTree.updateFile(file); - } - - Thread.sleep(5000); - - verify(notificationListener, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - - ArgumentCaptor eventsCaptor = ArgumentCaptor.forClass(String.class); - verify(notificationListener, times(deleted.size())) - .handleFileWatcherEvent( - eq(DELETED), eq(testDirectory), eventsCaptor.capture(), anyBoolean()); - assertThatCollectionsContainsSameItemsOrFailWithDiff(eventsCaptor.getAllValues(), deleted); - - eventsCaptor = ArgumentCaptor.forClass(String.class); - verify(notificationListener, times(updated.size())) - .handleFileWatcherEvent( - eq(MODIFIED), eq(testDirectory), eventsCaptor.capture(), anyBoolean()); - assertThatCollectionsContainsSameItemsOrFailWithDiff(eventsCaptor.getAllValues(), updated); - - eventsCaptor = ArgumentCaptor.forClass(String.class); - verify(notificationListener, times(created.size())) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), eventsCaptor.capture(), anyBoolean()); - assertThatCollectionsContainsSameItemsOrFailWithDiff(eventsCaptor.getAllValues(), created); - } - - private FileWatcherNotificationHandler aNotificationListener() { - return mock(FileWatcherNotificationHandler.class); - } - - private void assertThatCollectionsContainsSameItemsOrFailWithDiff( - Collection actual, Collection expected) { - List missed = newArrayList(expected); - List extra = newArrayList(actual); - missed.removeAll(actual); - extra.removeAll(expected); - if (missed.isEmpty() && extra.isEmpty()) { - return; - } - StringBuilder message = new StringBuilder(); - if (missed.size() > 0) { - message.append("\n>>> Expected items:\n").append(missed).append('\n').append("but missed\n"); - } - if (extra.size() > 0) { - message - .append("\n>>> Items:\n") - .append(extra) - .append('\n') - .append("not expected but found\n"); - } - fail(message.toString()); - } -} diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcherTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcherTest.java deleted file mode 100644 index 19f364199ee..00000000000 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcherTest.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.vfs.impl.file; - -import static com.google.common.collect.Sets.newHashSet; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.CREATED; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.DELETED; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.MODIFIED; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.File; -import java.nio.file.FileSystems; -import java.nio.file.PathMatcher; -import java.util.List; -import java.util.Set; -import org.eclipse.che.commons.lang.IoUtil; -import org.eclipse.che.commons.lang.NameGenerator; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -public class FileTreeWatcherTest { - private File testDirectory; - private FileTreeWatcher fileWatcher; - private FileWatcherTestTree fileWatcherTestTree; - - @Before - public void setUp() throws Exception { - File targetDir = - new File(Thread.currentThread().getContextClassLoader().getResource(".").getPath()) - .getParentFile(); - testDirectory = new File(targetDir, NameGenerator.generate("watcher-", 4)); - assertTrue(testDirectory.mkdir()); - fileWatcherTestTree = new FileWatcherTestTree(testDirectory); - } - - @After - public void tearDown() throws Exception { - if (fileWatcher != null) { - fileWatcher.shutdown(); - } - IoUtil.deleteRecursive(testDirectory); - } - - @Test - public void watchesCreate() throws Exception { - fileWatcherTestTree.createDirectory("", "watched"); - - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - Set created = - newHashSet( - fileWatcherTestTree.createDirectory(""), - fileWatcherTestTree.createFile(""), - fileWatcherTestTree.createDirectory("watched"), - fileWatcherTestTree.createFile("watched")); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor createdEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(4)) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), createdEvents.capture(), anyBoolean()); - assertEquals(newHashSet(created), newHashSet(createdEvents.getAllValues())); - } - - @Test - public void watchesCreateDirectoryStructure() throws Exception { - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - List created = fileWatcherTestTree.createTree("", 2, 2); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor createdEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(4)) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), createdEvents.capture(), anyBoolean()); - assertEquals(newHashSet(created), newHashSet(createdEvents.getAllValues())); - } - - @Test - public void watchesCreatedSubDirectoriesRecursively() throws Exception { - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - final String first = fileWatcherTestTree.createDirectory("", "first"); - final String second = fileWatcherTestTree.createDirectory(first, "second"); - final String file = fileWatcherTestTree.createFile(second); - - Thread.sleep(5000); - - fileWatcherTestTree.updateFile(file); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - - verify(notificationHandler, times(3)) - .handleFileWatcherEvent(eq(CREATED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor modifiedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler) - .handleFileWatcherEvent( - eq(MODIFIED), eq(testDirectory), modifiedEvents.capture(), anyBoolean()); - assertEquals(newHashSet(file), newHashSet(modifiedEvents.getAllValues())); - } - - @Test - public void watchesCreateDirectoryAndStartsWatchingNewlyCreatedDirectory() throws Exception { - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - String directory = fileWatcherTestTree.createDirectory(""); - - Thread.sleep(5000); - - String file = fileWatcherTestTree.createFile(directory); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor createdEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(2)) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), createdEvents.capture(), anyBoolean()); - assertEquals(newHashSet(directory, file), newHashSet(createdEvents.getAllValues())); - } - - @Test - public void watchesUpdate() throws Exception { - fileWatcherTestTree.createDirectory("", "watched"); - String notifiedFile1 = fileWatcherTestTree.createFile(""); - String notifiedFile2 = fileWatcherTestTree.createFile("watched"); - Set updated = newHashSet(notifiedFile1, notifiedFile2); - - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(1000); - - fileWatcherTestTree.updateFile(notifiedFile1); - fileWatcherTestTree.updateFile(notifiedFile2); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(CREATED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor updatedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(2)) - .handleFileWatcherEvent( - eq(MODIFIED), eq(testDirectory), updatedEvents.capture(), anyBoolean()); - assertEquals(updated, newHashSet(updatedEvents.getAllValues())); - } - - @Test - public void watchesFolderModifiedOnDelete() throws Exception { - final String watchedDir = fileWatcherTestTree.createDirectory("", "watched"); - final String notifiedFile = fileWatcherTestTree.createFile("watched"); - final Set deleted = newHashSet(notifiedFile); - final Set modified = newHashSet(watchedDir); - - final FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(1000); - - fileWatcherTestTree.delete(notifiedFile); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - - final ArgumentCaptor deletedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(1)) - .handleFileWatcherEvent( - eq(DELETED), eq(testDirectory), deletedEvents.capture(), anyBoolean()); - assertEquals(deleted, newHashSet(deletedEvents.getAllValues())); - - final ArgumentCaptor modifiedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(1)) - .handleFileWatcherEvent( - eq(MODIFIED), eq(testDirectory), modifiedEvents.capture(), anyBoolean()); - assertEquals(modified, newHashSet(modifiedEvents.getAllValues())); - } - - @Test - public void watchesFolderModifiedOnCreate() throws Exception { - final String watchedDir = fileWatcherTestTree.createDirectory("", "watched"); - final Set modified = newHashSet(watchedDir); - - final FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(1000); - - final String notifiedFile = fileWatcherTestTree.createFile("watched"); - final Set created = newHashSet(notifiedFile); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - - final ArgumentCaptor deletedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(1)) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), deletedEvents.capture(), anyBoolean()); - assertEquals(created, newHashSet(deletedEvents.getAllValues())); - - final ArgumentCaptor modifiedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(1)) - .handleFileWatcherEvent( - eq(MODIFIED), eq(testDirectory), modifiedEvents.capture(), anyBoolean()); - assertEquals(modified, newHashSet(modifiedEvents.getAllValues())); - } - - @Test - public void watchesDelete() throws Exception { - fileWatcherTestTree.createDirectory("", "watched"); - String deletedDir1 = fileWatcherTestTree.createDirectory("watched"); - String deletedFile1 = fileWatcherTestTree.createFile("watched"); - Set deleted = newHashSet("watched", deletedDir1, deletedFile1); - - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - fileWatcherTestTree.delete("watched"); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(CREATED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor deletedEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(3)) - .handleFileWatcherEvent( - eq(DELETED), eq(testDirectory), deletedEvents.capture(), anyBoolean()); - assertEquals(deleted, newHashSet(deletedEvents.getAllValues())); - } - - @Test - public void doesNotWatchExcludedDirectories() throws Exception { - fileWatcherTestTree.createDirectory("", "excluded"); - - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - PathMatcher excludeMatcher = FileSystems.getDefault().getPathMatcher("glob:excluded"); - fileWatcher = - new FileTreeWatcher(testDirectory, newHashSet(excludeMatcher), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - String directory = fileWatcherTestTree.createDirectory(""); - String file = fileWatcherTestTree.createFile(""); - fileWatcherTestTree.createDirectory("excluded"); - fileWatcherTestTree.createFile("excluded"); - - Set created = newHashSet(directory, file); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor createdEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(2)) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), createdEvents.capture(), anyBoolean()); - assertEquals(newHashSet(created), newHashSet(createdEvents.getAllValues())); - } - - @Test - public void doesNotNotifyAboutIgnoredFiles() throws Exception { - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - PathMatcher excludeMatcher = FileSystems.getDefault().getPathMatcher("glob:*.{foo,bar}"); - fileWatcher = - new FileTreeWatcher(testDirectory, newHashSet(excludeMatcher), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - String file = fileWatcherTestTree.createFile(""); - fileWatcherTestTree.createFile("", "xxx.bar"); - fileWatcherTestTree.createFile("", "xxx.foo"); - - Set created = newHashSet(file); - - Thread.sleep(5000); - - verify(notificationHandler, never()).errorOccurred(eq(testDirectory), any(Throwable.class)); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(DELETED), eq(testDirectory), anyString(), anyBoolean()); - verify(notificationHandler, never()) - .handleFileWatcherEvent(eq(MODIFIED), eq(testDirectory), anyString(), anyBoolean()); - - ArgumentCaptor createdEvents = ArgumentCaptor.forClass(String.class); - verify(notificationHandler, times(1)) - .handleFileWatcherEvent( - eq(CREATED), eq(testDirectory), createdEvents.capture(), anyBoolean()); - assertEquals(newHashSet(created), newHashSet(createdEvents.getAllValues())); - } - - @Test - public void notifiesNotificationListenerWhenStarted() throws Exception { - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - - verify(notificationHandler, timeout(10000)).started(eq(testDirectory)); - } - - @Test - public void notifiesNotificationListenerWhenErrorOccurs() throws Exception { - RuntimeException error = new RuntimeException(); - FileWatcherNotificationHandler notificationHandler = aNotificationHandler(); - doThrow(error) - .when(notificationHandler) - .handleFileWatcherEvent(eq(CREATED), eq(testDirectory), anyString(), anyBoolean()); - - fileWatcher = new FileTreeWatcher(testDirectory, newHashSet(), notificationHandler); - fileWatcher.startup(); - - Thread.sleep(500); - fileWatcherTestTree.createFile(""); - Thread.sleep(5000); - - verify(notificationHandler, timeout(10000)).errorOccurred(eq(testDirectory), eq(error)); - } - - private FileWatcherNotificationHandler aNotificationHandler() { - return mock(FileWatcherNotificationHandler.class); - } -}