Skip to content

Commit

Permalink
VFS file watcher based use cases implementations (#2339)
Browse files Browse the repository at this point in the history
* che#1910: added several new user workflows implementations for VFS

Signed-off-by: Dmitry Kuleshov <[email protected]>
  • Loading branch information
Dmitry Kuleshov authored Sep 7, 2016
1 parent 8df0560 commit 5d267fe
Show file tree
Hide file tree
Showing 87 changed files with 2,431 additions and 845 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.websocket.Session;
import java.io.IOException;
import java.util.Optional;

import static org.eclipse.che.dto.server.DtoFactory.newDto;
Expand Down Expand Up @@ -47,7 +48,7 @@ public BasicWebSocketMessageTransmitter(WebSocketSessionRegistry registry,
}

@Override
public void transmit(String protocol, String message, Integer endpointId) {
public synchronized void transmit(String protocol, String message, Integer endpointId) {
final WebSocketTransmission transmission = newDto(WebSocketTransmission.class).withProtocol(protocol).withMessage(message);
validator.validate(transmission);

Expand All @@ -60,12 +61,16 @@ public void transmit(String protocol, String message, Integer endpointId) {
} else {
LOG.debug("Session registered and open, sending message");

sessionOptional.get().getAsyncRemote().sendText(transmission.toString());
try {
sessionOptional.get().getBasicRemote().sendText(transmission.toString());
} catch (IOException e) {
LOG.error("Error while trying to send a message to a basic websocket remote endpoint", e);
}
}
}

@Override
public void transmit(String protocol, String message) {
public synchronized void transmit(String protocol, String message) {
final WebSocketTransmission transmission = newDto(WebSocketTransmission.class).withProtocol(protocol).withMessage(message);
validator.validate(transmission);

Expand All @@ -74,8 +79,14 @@ public void transmit(String protocol, String message) {
registry.getSessions()
.stream()
.filter(Session::isOpen)
.map(Session::getAsyncRemote)
.forEach(it -> it.sendText(transmission.toString()));
.map(Session::getBasicRemote)
.forEach(it -> {
try {
it.sendText(transmission.toString());
} catch (IOException e) {
LOG.error("Error while trying to send a message to a basic websocket remote endpoint", e);
}
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.Optional;

import static java.util.Collections.emptySet;
Expand Down Expand Up @@ -53,14 +54,14 @@ public class BasicWebSocketTransmissionTransmitterTest {
@Mock
private Session session;
@Mock
private RemoteEndpoint.Async remote;
private RemoteEndpoint.Basic remote;

private WebSocketTransmission transmission;


@BeforeMethod
public void setUp() throws Exception {
when(session.getAsyncRemote()).thenReturn(remote);
when(session.getBasicRemote()).thenReturn(remote);
when(session.isOpen()).thenReturn(true);

when(registry.get(eq(ENDPOINT_ID))).thenReturn(Optional.of(session));
Expand All @@ -84,32 +85,32 @@ public void shouldValidateBroadcastMessage() {
}

@Test
public void shouldSendDirectMessageIfSessionIsOpenAndEndpointIsSet() {
public void shouldSendDirectMessageIfSessionIsOpenAndEndpointIsSet() throws IOException {
transmitter.transmit(PROTOCOL, MESSAGE, ENDPOINT_ID);

verify(session).getAsyncRemote();
verify(session).getBasicRemote();
verify(remote).sendText(transmission.toString());
verify(reSender, never()).add(eq(ENDPOINT_ID), any(WebSocketTransmission.class));
}

@Test
public void shouldSendBroadcastingMessageIfSessionIsOpen() {
public void shouldSendBroadcastingMessageIfSessionIsOpen() throws IOException {
transmitter.transmit(PROTOCOL, MESSAGE);

verify(session, never()).getAsyncRemote();
verify(session, never()).getBasicRemote();
verify(remote, never()).sendText(transmission.toString());
verify(reSender, never()).add(any(), any(WebSocketTransmission.class));

verify(registry).getSessions();
}

@Test
public void shouldAddMessageToPendingIfSessionIsNotOpenedAndEndpointIsSet() {
public void shouldAddMessageToPendingIfSessionIsNotOpenedAndEndpointIsSet() throws IOException {
when(session.isOpen()).thenReturn(false);

transmitter.transmit(PROTOCOL, MESSAGE, ENDPOINT_ID);

verify(session, never()).getAsyncRemote();
verify(session, never()).getBasicRemote();
verify(remote, never()).sendText(transmission.toString());
verify(reSender).add(eq(ENDPOINT_ID), any(WebSocketTransmission.class));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
*/
public class ReconcilerWithAutoSave implements Reconciler {

private static final int DELAY = 1000;
private static final int DELAY = 5000;


private final Map<String, ReconcilingStrategy> strategies;
Expand Down Expand Up @@ -250,4 +250,4 @@ public void enableAutoSave() {
autoSaveEnabled = true;
autoSaveTimer.schedule(DELAY);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class FileContentUpdateEvent extends GwtEvent<FileContentUpdateHandler> {
*/
private final String filePath;

/**
* Encoded content.
*/
private String modificationStamp;

/**
* Constructor.
*
Expand All @@ -33,6 +38,11 @@ public FileContentUpdateEvent(final String filePath) {
this.filePath = filePath;
}

public FileContentUpdateEvent(final String filePath, final String contentStamp) {
this.filePath = filePath;
this.modificationStamp = contentStamp;
}

@Override
public Type<FileContentUpdateHandler> getAssociatedType() {
return TYPE;
Expand All @@ -51,4 +61,13 @@ protected void dispatch(FileContentUpdateHandler handler) {
public String getFilePath() {
return filePath;
}

/**
* Returns content's stamp of the file that had changes.
*
* @return the path
*/
public String getModificationStamp() {
return modificationStamp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
*******************************************************************************/
package org.eclipse.che.ide.api.event.ng;

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

import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest;
import org.eclipse.che.api.project.shared.dto.event.FileClosedDto;
import org.eclipse.che.api.project.shared.dto.event.FileOpenedDto;
import org.eclipse.che.ide.api.event.FileEvent;
import org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto;
import org.eclipse.che.ide.api.editor.EditorAgent;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.jsonrpc.JsonRpcRequestTransmitter;
import org.eclipse.che.ide.util.loging.Log;
Expand All @@ -38,53 +38,31 @@ public ClientServerEventService(final JsonRpcRequestTransmitter transmitter,
this.transmitter = transmitter;
this.dtoFactory = dtoFactory;

Log.info(getClass(), "Adding file event listener");
eventBus.addHandler(FileEvent.TYPE, new FileEvent.FileEventHandler() {
Log.debug(getClass(), "Adding file event listener");
eventBus.addHandler(FileTrackingEvent.TYPE, new FileTrackingEvent.FileTrackingEventHandler() {
@Override
public void onFileOperation(FileEvent event) {
final String path = event.getFile().getLocation().toString();
public void onEvent(FileTrackingEvent event) {
final FileTrackingOperationDto.Type type = event.getType();
final String path = event.getPath();
final String oldPath = event.getOldPath();

switch (event.getOperationType()) {
case OPEN: {
transmitOpenFileNotification(path);

break;
}
case CLOSE: {
transmitCloseFileNotification(path);

break;
}
}
transmit(path, oldPath, type);
}
});


}

private void transmitCloseFileNotification(String path) {
Log.info(ClientServerEventService.class, "Sending file closed event: " + path);

final FileClosedDto dto = dtoFactory.createDto(FileClosedDto.class).withPath(path);
private void transmit(String path, String oldPath, FileTrackingOperationDto.Type type) {
final String params = dtoFactory.createDto(FileTrackingOperationDto.class)
.withPath(path)
.withType(type)
.withOldPath(oldPath)
.toString();

final JsonRpcRequest request = dtoFactory.createDto(JsonRpcRequest.class)
.withJsonrpc("2.0")
.withMethod("event:file-closed")
.withParams(dto.toString());
.withMethod("track:editor-file")
.withParams(params);

transmitter.transmit(request);
}

private void transmitOpenFileNotification(String path) {
Log.info(ClientServerEventService.class, "Sending file opened event: " + path);

final FileOpenedDto dto = dtoFactory.createDto(FileOpenedDto.class).withPath(path);

final JsonRpcRequest notification = dtoFactory.createDto(JsonRpcRequest.class)
.withJsonrpc("2.0")
.withMethod("event:file-opened")
.withParams(dto.toString());

transmitter.transmit(notification);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*******************************************************************************
* 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.ide.api.event.ng;

import com.google.inject.Singleton;

import java.util.HashSet;
import java.util.Set;

/**
* Contains the list of paths that correspond to opened files and should not trigger events
* notifications from file system because they are initiated by ourselves (e.g. refactoring,
* git checkout etc.)
*
* @author Valeriy Svydenko
*/
@Singleton
public class DeletedFilesController {
private Set<String> deletedFiles = new HashSet<>();

/**
* Adds the path to the file which need to skip.
*
* @param path
* path to the file
*/
public void add(String path) {
deletedFiles.add(path);
}

/**
* Removes the path to the file which need to skip.
*
* @param path
* path to the file
*
* @return {@code true} if set contains the specified path
*/
public boolean remove(String path) {
return deletedFiles.remove(path);
}

/** Returns {@code true} if this set contains the specified path. */
public boolean contains(String path) {
return deletedFiles.contains(path);
}
}
Loading

0 comments on commit 5d267fe

Please sign in to comment.