diff --git a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitChangesDetector.java b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitChangesDetector.java index 0df11f6782e..79a07622f8b 100644 --- a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitChangesDetector.java +++ b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitChangesDetector.java @@ -10,8 +10,6 @@ */ package org.eclipse.che.api.git; -import static com.google.common.collect.Sets.newConcurrentHashSet; -import static java.nio.file.Files.isDirectory; import static java.util.Collections.singletonList; import static org.eclipse.che.api.git.shared.FileChangedEventDto.Status.ADDED; import static org.eclipse.che.api.git.shared.FileChangedEventDto.Status.MODIFIED; @@ -21,20 +19,22 @@ import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.slf4j.LoggerFactory.getLogger; -import java.nio.file.PathMatcher; -import java.util.Set; +import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; -import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; -import javax.inject.Provider; +import javax.inject.Singleton; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator; import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter; +import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.core.notification.EventSubscriber; import org.eclipse.che.api.git.shared.FileChangedEventDto; import org.eclipse.che.api.git.shared.Status; import org.eclipse.che.api.project.server.ProjectManager; +import org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto; +import org.eclipse.che.api.vfs.impl.file.event.detectors.FileTrackingOperationEvent; import org.eclipse.che.api.vfs.watcher.FileWatcherManager; import org.slf4j.Logger; @@ -43,83 +43,123 @@ * * @author Igor Vinokur */ +@Singleton public class GitChangesDetector { private static final Logger LOG = getLogger(GitChangesDetector.class); - private static final String GIT_DIR = ".git"; - private static final String INCOMING_METHOD = "track/git-change"; private static final String OUTGOING_METHOD = "event/git-change"; private final RequestTransmitter transmitter; private final FileWatcherManager manager; - private final Provider projectManagerProvider; + private final ProjectManager projectManager; private final GitConnectionFactory gitConnectionFactory; + private final EventService eventService; + private final EventSubscriber eventSubscriber; - private final Set endpointIds = newConcurrentHashSet(); - - private int id; + private final Map watchIdRegistry = new HashMap<>(); @Inject public GitChangesDetector( RequestTransmitter transmitter, FileWatcherManager manager, - Provider projectManagerProvider, - GitConnectionFactory gitConnectionFactory) { + ProjectManager projectManager, + GitConnectionFactory gitConnectionFactory, + EventService eventService) { this.transmitter = transmitter; this.manager = manager; - this.projectManagerProvider = projectManagerProvider; + this.projectManager = projectManager; this.gitConnectionFactory = gitConnectionFactory; + this.eventService = eventService; + + eventSubscriber = + new EventSubscriber() { + @Override + public void onEvent(FileTrackingOperationEvent event) { + onFileTrackingOperationReceived( + event.getEndpointId(), event.getFileTrackingOperation()); + } + }; + eventService.subscribe(eventSubscriber); } - @Inject - public void configureHandler(RequestHandlerConfigurator configurator) { - configurator - .newConfiguration() - .methodName(INCOMING_METHOD) - .noParams() - .noResult() - .withConsumer(endpointIds::add); - } - - @PostConstruct - public void startWatcher() { - id = manager.registerByMatcher(matcher(), createConsumer(), modifyConsumer(), deleteConsumer()); + private void onFileTrackingOperationReceived( + String endpointId, FileTrackingOperationDto operation) { + FileTrackingOperationDto.Type type = operation.getType(); + String path = operation.getPath(); + String oldPath = operation.getOldPath(); + + switch (type) { + case START: + { + String key = path + endpointId; + if (watchIdRegistry.containsKey(key)) { + return; + } + int id = + manager.registerByPath( + path, + createConsumer(endpointId, path), + modifyConsumer(endpointId, path), + deleteConsumer(endpointId, path)); + watchIdRegistry.put(key, id); + + break; + } + case STOP: + { + Integer id = watchIdRegistry.remove(path + endpointId); + if (id != null) { + manager.unRegisterByPath(id); + } + + break; + } + case MOVE: + { + Integer oldId = watchIdRegistry.remove(oldPath + endpointId); + if (oldId != null) { + manager.unRegisterByPath(oldId); + } + + int newId = + manager.registerByPath( + path, + createConsumer(endpointId, path), + modifyConsumer(endpointId, path), + deleteConsumer(endpointId, path)); + watchIdRegistry.put(path + endpointId, newId); + + break; + } + default: + break; + } } @PreDestroy public void stopWatcher() { - manager.unRegisterByMatcher(id); - } - - private PathMatcher matcher() { - return it -> - !(isDirectory(it) || GIT_DIR.equals(it.getNameCount() > 2 ? it.getName(2).toString() : "")); + eventService.unsubscribe(eventSubscriber); } - private Consumer createConsumer() { - return fsEventConsumer(); + private Consumer createConsumer(String endpointId, String path) { + return fsEventConsumer(endpointId, path); } - private Consumer modifyConsumer() { - return fsEventConsumer(); + private Consumer modifyConsumer(String endpointId, String path) { + return fsEventConsumer(endpointId, path); } - private Consumer deleteConsumer() { + private Consumer deleteConsumer(String endpointId, String path) { return EMPTY_CONSUMER; } - private Consumer fsEventConsumer() { - return it -> endpointIds.forEach(transmitConsumer(it)); - } - - private Consumer transmitConsumer(String path) { - return id -> { + private Consumer fsEventConsumer(String endpointId, String path) { + return it -> { try { String normalizedPath = path.startsWith("/") ? path.substring(1) : path; String itemPath = normalizedPath.substring(normalizedPath.indexOf("/") + 1); String projectPath = - projectManagerProvider - .get() + projectManager .getProject(normalizedPath.split("/")[0]) .getBaseFolder() .getVirtualFile() @@ -141,7 +181,7 @@ private Consumer transmitConsumer(String path) { transmitter .newRequest() - .endpointId(id) + .endpointId(endpointId) .methodName(OUTGOING_METHOD) .paramsAsDto( newDto(FileChangedEventDto.class)