Skip to content

Commit

Permalink
Dynamic file watchers (#3482)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitry Kuleshov committed Dec 26, 2016
1 parent f9a91f6 commit 301121d
Show file tree
Hide file tree
Showing 67 changed files with 2,266 additions and 2,874 deletions.
Expand Up @@ -29,8 +29,7 @@ public class ClientServerEventService {
private final RequestTransmitter requestTransmitter;

@Inject
public ClientServerEventService(EventBus eventBus, DtoFactory dtoFactory,
RequestTransmitter requestTransmitter) {
public ClientServerEventService(EventBus eventBus, DtoFactory dtoFactory, RequestTransmitter requestTransmitter) {
this.dtoFactory = dtoFactory;
this.requestTransmitter = requestTransmitter;

Expand Down
Expand Up @@ -13,8 +13,8 @@

import com.google.web.bindery.event.shared.EventBus;

import org.eclipse.che.api.project.shared.dto.event.FileStateUpdateDto;
import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType;
import org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.event.FileContentUpdateEvent;
import org.eclipse.che.ide.api.notification.NotificationManager;
Expand All @@ -40,7 +40,7 @@
* @author Dmitry Kuleshov
*/
@Singleton
public class EditorFileStatusNotificationOperation implements JsonRpcRequestBiOperation<VfsFileStatusUpdateDto> {
public class EditorFileStatusNotificationOperation implements JsonRpcRequestBiOperation<FileStateUpdateDto> {

private final EventBus eventBus;
private final DeletedFilesController deletedFilesController;
Expand All @@ -58,8 +58,8 @@ public EditorFileStatusNotificationOperation(EventBus eventBus, DeletedFilesCont
@Inject
public void configureHandler(RequestHandlerConfigurator configurator) {
configurator.newConfiguration()
.methodName("event:file-in-vfs-status-changed")
.paramsAsDto(VfsFileStatusUpdateDto.class)
.methodName("event:file-state-changed")
.paramsAsDto(FileStateUpdateDto.class)
.noResult()
.withOperation(this);
}
Expand All @@ -68,7 +68,7 @@ public void inject(NotificationManager notificationManager) {
this.notificationManager = notificationManager;
}

public void apply(String endpointId, VfsFileStatusUpdateDto params) {
public void apply(String endpointId, FileStateUpdateDto params) {
final FileWatcherEventType status = params.getType();
final String stringPath = params.getPath();
final String name = stringPath.substring(stringPath.lastIndexOf("/") + 1);
Expand Down
Expand Up @@ -15,17 +15,22 @@
import com.google.inject.Inject;
import com.google.web.bindery.event.shared.EventBus;

import org.eclipse.che.api.project.shared.dto.event.ProjectTreeTrackingOperationDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.machine.DevMachine;
import org.eclipse.che.ide.api.machine.MachineEntity;
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.jsonrpc.JsonRpcInitializer;
import org.eclipse.che.ide.jsonrpc.RequestTransmitter;
import org.eclipse.che.ide.util.loging.Log;

import javax.inject.Singleton;

import static java.util.Collections.singletonMap;
import static org.eclipse.che.api.project.shared.dto.event.ProjectTreeTrackingOperationDto.Type.START;
import static org.eclipse.che.api.project.shared.dto.event.ProjectTreeTrackingOperationDto.Type.STOP;

/**
* @author Dmitry Kuleshov
Expand All @@ -36,11 +41,16 @@ public class JsonRpcWebSocketAgentEventListener implements WsAgentStateHandler {

private final JsonRpcInitializer initializer;
private final AppContext appContext;
private final RequestTransmitter requestTransmitter;
private final DtoFactory dtoFactory;

@Inject
public JsonRpcWebSocketAgentEventListener(JsonRpcInitializer initializer, AppContext appContext, EventBus eventBus) {
public JsonRpcWebSocketAgentEventListener(JsonRpcInitializer initializer, AppContext appContext, EventBus eventBus,
RequestTransmitter requestTransmitter, DtoFactory dtoFactory) {
this.appContext = appContext;
this.initializer = initializer;
this.requestTransmitter = requestTransmitter;
this.dtoFactory = dtoFactory;

eventBus.addHandler(WsAgentStateEvent.TYPE, this);
}
Expand All @@ -59,6 +69,8 @@ public void run() {
}
}.schedule(1_000);
}

initializeTreeExplorerFileWatcher();
}

private void internalInitialize() {
Expand All @@ -79,6 +91,14 @@ private void internalInitialize() {
}
}

private void initializeTreeExplorerFileWatcher() {
ProjectTreeTrackingOperationDto params = dtoFactory.createDto(ProjectTreeTrackingOperationDto.class)
.withPath("/")
.withType(START);

requestTransmitter.transmitOneToNone("ws-agent", "track:project-tree", params);
}

@Override
public void onWsAgentStopped(WsAgentStateEvent event) {
DevMachine devMachine = appContext.getDevMachine();
Expand Down
Expand Up @@ -12,7 +12,7 @@


import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType;
import org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto;
import org.eclipse.che.api.project.shared.dto.event.ProjectTreeStateUpdateDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.resources.Container;
import org.eclipse.che.ide.api.resources.ExternalResourceDelta;
Expand All @@ -37,25 +37,25 @@
* @author Dmitry Kuleshov
*/
@Singleton
public class ProjectTreeStatusNotificationOperation implements JsonRpcRequestBiOperation<ProjectTreeStatusUpdateDto> {
public class ProjectTreeStateNotificationOperation implements JsonRpcRequestBiOperation<ProjectTreeStateUpdateDto> {
private final AppContext appContext;

@Inject
public ProjectTreeStatusNotificationOperation(AppContext appContext) {
public ProjectTreeStateNotificationOperation(AppContext appContext) {
this.appContext = appContext;
}

@Inject
public void configureHandler(RequestHandlerConfigurator configurator) {
configurator.newConfiguration()
.methodName("event:project-tree-status-changed")
.paramsAsDto(ProjectTreeStatusUpdateDto.class)
.methodName("event:project-tree-state-changed")
.paramsAsDto(ProjectTreeStateUpdateDto.class)
.noResult()
.withOperation(this);
}

@Override
public void apply(String endpointId, ProjectTreeStatusUpdateDto params) throws JsonRpcException {
public void apply(String endpointId, ProjectTreeStateUpdateDto params) throws JsonRpcException {
final String path = params.getPath();
final FileWatcherEventType type = params.getType();

Expand Down
Expand Up @@ -15,7 +15,7 @@
import org.eclipse.che.ide.api.event.ng.ClientServerEventService;
import org.eclipse.che.ide.api.event.ng.EditorFileStatusNotificationOperation;
import org.eclipse.che.ide.api.event.ng.FileOpenCloseEventListener;
import org.eclipse.che.ide.api.event.ng.ProjectTreeStatusNotificationOperation;
import org.eclipse.che.ide.api.event.ng.ProjectTreeStateNotificationOperation;

/**
* GIN module for configuring client server events.
Expand All @@ -38,6 +38,6 @@ private void requestFunctions() {

private void notificationOperations() {
bind(EditorFileStatusNotificationOperation.class).asEagerSingleton();
bind(ProjectTreeStatusNotificationOperation.class).asEagerSingleton();
bind(ProjectTreeStateNotificationOperation.class).asEagerSingleton();
}
}
Expand Up @@ -16,6 +16,7 @@
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;

import org.eclipse.che.api.project.shared.dto.event.ProjectTreeTrackingOperationDto;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.DelayedTask;
Expand All @@ -41,6 +42,8 @@
import org.eclipse.che.ide.api.resources.marker.MarkerChangedEvent.MarkerChangedHandler;
import org.eclipse.che.ide.api.selection.Selection;
import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.jsonrpc.RequestTransmitter;
import org.eclipse.che.ide.part.explorer.project.ProjectExplorerView.ActionDelegate;
import org.eclipse.che.ide.project.node.SyntheticNode;
import org.eclipse.che.ide.project.node.SyntheticNodeUpdateEvent;
Expand All @@ -50,17 +53,24 @@
import org.eclipse.che.ide.ui.smartTree.NodeDescriptor;
import org.eclipse.che.ide.ui.smartTree.Tree;
import org.eclipse.che.ide.ui.smartTree.event.BeforeExpandNodeEvent;
import org.eclipse.che.ide.ui.smartTree.event.CollapseNodeEvent;
import org.eclipse.che.ide.ui.smartTree.event.ExpandNodeEvent;
import org.eclipse.che.ide.ui.smartTree.event.PostLoadEvent;
import org.eclipse.che.ide.ui.smartTree.event.SelectionChangedEvent;
import org.eclipse.che.ide.ui.smartTree.event.SelectionChangedEvent.SelectionChangedHandler;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.providers.DynaObject;
import org.vectomatic.dom.svg.ui.SVGResource;

import javax.validation.constraints.NotNull;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.eclipse.che.api.project.shared.dto.event.ProjectTreeTrackingOperationDto.Type.START;
import static org.eclipse.che.api.project.shared.dto.event.ProjectTreeTrackingOperationDto.Type.STOP;
import static org.eclipse.che.ide.api.resources.ResourceDelta.ADDED;
import static org.eclipse.che.ide.api.resources.ResourceDelta.MOVED_FROM;
import static org.eclipse.che.ide.api.resources.ResourceDelta.MOVED_TO;
Expand All @@ -86,6 +96,8 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
private final CoreLocalizationConstant locale;
private final Resources resources;
private final TreeExpander treeExpander;
private final RequestTransmitter requestTransmitter;
private final DtoFactory dtoFactory;

private UpdateTask updateTask = new UpdateTask();
private Set<Path> expandQueue = new HashSet<>();
Expand All @@ -102,13 +114,15 @@ public ProjectExplorerPresenter(final ProjectExplorerView view,
final ResourceNode.NodeFactory nodeFactory,
final SettingsProvider settingsProvider,
final AppContext appContext,
final WorkspaceAgent workspaceAgent) {
final WorkspaceAgent workspaceAgent, RequestTransmitter requestTransmitter, DtoFactory dtoFactory) {
this.view = view;
this.eventBus = eventBus;
this.nodeFactory = nodeFactory;
this.settingsProvider = settingsProvider;
this.locale = locale;
this.resources = resources;
this.requestTransmitter = requestTransmitter;
this.dtoFactory = dtoFactory;
this.view.setDelegate(this);

eventBus.addHandler(ResourceChangedEvent.getType(), this);
Expand Down Expand Up @@ -170,6 +184,40 @@ public void onExtensionsInitialized(ExtensionsInitializedEvent event) {
});
}

@Inject
public void initFileWatchers() {
final String endpointId = "ws-agent";
final String method = "track:project-tree";

getTree().addExpandHandler(new ExpandNodeEvent.ExpandNodeHandler() {
@Override
public void onExpand(ExpandNodeEvent event) {
Node node = event.getNode();

if (node instanceof ResourceNode) {
Resource data = ((ResourceNode)node).getData();
requestTransmitter.transmitOneToNone(endpointId, method, dtoFactory.createDto(ProjectTreeTrackingOperationDto.class)
.withPath(data.getLocation().toString())
.withType(START));
}
}
});

getTree().addCollapseHandler(new CollapseNodeEvent.CollapseNodeHandler() {
@Override
public void onCollapse(CollapseNodeEvent event) {
Node node = event.getNode();

if (node instanceof ResourceNode) {
Resource data = ((ResourceNode)node).getData();
requestTransmitter.transmitOneToNone(endpointId, method, dtoFactory.createDto(ProjectTreeTrackingOperationDto.class)
.withPath(data.getLocation().toString())
.withType(STOP));
}
}
});
}

/* Expose Project Explorer's internal API to the world, to allow automated Selenium scripts expand all projects tree. */
private native void registerNative() /*-{
var that = this;
Expand Down Expand Up @@ -218,7 +266,9 @@ public void onResourceChanged(ResourceChangedEvent event) {
// process root projects, they have only one segment in path
if (resource.getLocation().segmentCount() == 1) {
if (delta.getKind() == ADDED) {
tree.getNodeStorage().add(nodeFactory.newContainerNode((Container)resource, nodeSettings));
if (getNode(resource.getLocation()) == null) {
tree.getNodeStorage().add(nodeFactory.newContainerNode((Container)resource, nodeSettings));
}
} else if (delta.getKind() == REMOVED) {
Node node = getNode(resource.getLocation());

Expand Down
Expand Up @@ -12,6 +12,7 @@


import com.jayway.restassured.response.Response;

import org.eclipse.che.api.project.server.ProjectManager;
import org.eclipse.che.api.project.server.ProjectRegistry;
import org.eclipse.che.api.project.server.RegisteredProject;
Expand All @@ -34,8 +35,8 @@
import static org.mockito.Matchers.anyMapOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.testng.Assert.assertEquals;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;

/**
Expand Down Expand Up @@ -99,7 +100,7 @@ public void setUp() throws Exception {

when(classpathRegistry.getTestClasspathProvider(PROJECT_TYPE_MAVEN)).thenReturn(classpathProviderMaven);

projectManager = new ProjectManager(vfsProvider, null, null, projectRegistry, null, null, null, null, null,null);
projectManager = new ProjectManager(vfsProvider, null, null, projectRegistry, null, null, null, null, null, null);
resourcesPlugin = new ResourcesPlugin(null, wsPath, null, null);


Expand Down
Expand Up @@ -28,7 +28,7 @@
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.impl.file.event.detectors.ProjectTreeChangesDetector;
import org.eclipse.che.api.vfs.watcher.FileWatcherManager;
import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.commons.lang.IoUtil;
Expand Down Expand Up @@ -115,7 +115,7 @@ protected void initProjectApi() throws Exception {
fileWatcherNotificationHandler,
fileTreeWatcher,
new TestWorkspaceHolder(new ArrayList<>()),
mock(ProjectTreeChangesDetector.class));
mock(FileWatcherManager.class));

ResourcesPlugin plugin = new ResourcesPlugin("target/index", wsPath, () -> projectRegistry, () -> projectManager);

Expand Down
@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.maven.server;

import com.google.inject.Inject;

import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.project.shared.dto.event.PomModifiedEventDto;
import org.eclipse.che.api.vfs.watcher.FileWatcherManager;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import static java.nio.file.Files.isDirectory;
import static org.eclipse.che.api.vfs.watcher.FileWatcherManager.EMPTY_CONSUMER;
import static org.eclipse.che.dto.server.DtoFactory.newDto;

public class PomModificationDetector {
private static final String POM_XML = "pom.xml";

private final FileWatcherManager manager;
private final EventService eventService;

private int id;

@Inject
public PomModificationDetector(EventService eventService, FileWatcherManager manager) {
this.eventService = eventService;
this.manager = manager;
}

@PostConstruct
public void startWatcher() {
id = manager.registerByMatcher(it -> !isDirectory(it) && POM_XML.equals(it.getFileName().toString()),
EMPTY_CONSUMER,
it -> eventService.publish(newDto(PomModifiedEventDto.class).withPath(it)),
EMPTY_CONSUMER);
}

@PreDestroy
public void stopWatcher() {
manager.unRegisterByMatcher(id);
}

}

0 comments on commit 301121d

Please sign in to comment.