Skip to content

Commit

Permalink
CHE-5338. Clean up app state preference when workspace is removed
Browse files Browse the repository at this point in the history
Signed-off-by: Roman Nikitenko <[email protected]>
  • Loading branch information
RomanNikitenko committed Sep 13, 2017
1 parent 0157ffc commit 030d3f6
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.addAll;
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPING;
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 @@ -31,7 +32,9 @@
import java.util.Map;
import java.util.Optional;
import org.eclipse.che.api.core.model.workspace.Workspace;
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.app.CurrentUser;
import org.eclipse.che.ide.api.app.StartUpAction;
Expand All @@ -55,6 +58,7 @@
import org.eclipse.che.ide.api.selection.Selection;
import org.eclipse.che.ide.api.workspace.WorkspaceReadyEvent;
import org.eclipse.che.ide.api.workspace.event.WorkspaceStartedEvent;
import org.eclipse.che.ide.api.workspace.event.WorkspaceStatusChangedEvent;
import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent;
import org.eclipse.che.ide.project.node.SyntheticNode;
import org.eclipse.che.ide.resource.Path;
Expand All @@ -76,9 +80,6 @@ public class AppContextImpl
implements AppContext,
SelectionChangedHandler,
ResourceChangedHandler,
WindowActionHandler,
WorkspaceStartedEvent.Handler,
WorkspaceStoppedEvent.Handler,
ResourceManagerInitializer {
private final QueryParameters queryParameters;
private final List<String> projectsInImport;
Expand Down Expand Up @@ -121,10 +122,13 @@ public AppContextImpl(

projectsInImport = new ArrayList<>();

WorkspaceStateHandler workspaceStateHandler = new WorkspaceStateHandler();

eventBus.addHandler(SelectionChangedEvent.TYPE, this);
eventBus.addHandler(ResourceChangedEvent.getType(), this);
eventBus.addHandler(WindowActionEvent.TYPE, this);
eventBus.addHandler(WorkspaceStoppedEvent.TYPE, this);
eventBus.addHandler(WindowActionEvent.TYPE, workspaceStateHandler);
eventBus.addHandler(WorkspaceStoppedEvent.TYPE, workspaceStateHandler);
eventBus.addHandler(WorkspaceStatusChangedEvent.TYPE, workspaceStateHandler);

//in some cases IDE doesn't save preferences on window close
//so try to save if window lost focus
Expand Down Expand Up @@ -224,12 +228,7 @@ public void initResourceManager(final Callback<ResourceManager, Exception> callb
callback.onFailure(new NullPointerException("Dev machine is not initialized"));
}

if (!rootProjects.isEmpty()) {
for (Project project : rootProjects) {
eventBus.fireEvent(new ResourceChangedEvent(new ResourceDeltaImpl(project, REMOVED)));
}
rootProjects.clear();
}
clearProjects();

resourceManager = resourceManagerFactory.newResourceManager(runtime.getDevMachine());
resourceManager
Expand Down Expand Up @@ -421,41 +420,19 @@ public Project getRootProject() {
}
}

@Override
public void onWindowClosing(WindowActionEvent event) {
appStateManager.get().persistWorkspaceState(getWorkspaceId());
}

@Override
public void onWorkspaceStarted(WorkspaceStartedEvent event) {
setWorkspace(event.getWorkspace());
}

@Override
public void onWorkspaceStopped(WorkspaceStoppedEvent event) {
appStateManager
.get()
.persistWorkspaceState(getWorkspaceId())
.then(
ignored -> {
for (Project project : rootProjects) {
eventBus.fireEvent(
new ResourceChangedEvent(new ResourceDeltaImpl(project, REMOVED)));
}

rootProjects.clear();
resourceManager = null;
});

clearRuntime();
}

private void clearRuntime() {
runtime = null;
}

@Override
public void onWindowClosed(WindowActionEvent event) {}
private void clearProjects() {
if (!rootProjects.isEmpty()) {
rootProjects.forEach(
project ->
eventBus.fireEvent(
new ResourceChangedEvent(new ResourceDeltaImpl(project, REMOVED))));
rootProjects.clear();
}
}

@Override
public String getMasterEndpoint() {
Expand Down Expand Up @@ -493,4 +470,51 @@ public Map<String, String> getProperties() {
}
return properties;
}

private class WorkspaceStateHandler
implements WindowActionHandler,
WorkspaceStartedEvent.Handler,
WorkspaceStoppedEvent.Handler,
WorkspaceStatusChangedEvent.Handler {

Promise<Void> persistWorkspaceStatePromise;

@Override
public void onWindowClosing(WindowActionEvent event) {
appStateManager.get().persistWorkspaceState(getWorkspaceId());
}

@Override
public void onWindowClosed(WindowActionEvent event) {}

@Override
public void onWorkspaceStarted(WorkspaceStartedEvent event) {
setWorkspace(event.getWorkspace());
}

@Override
public void onWorkspaceStatusChangedEvent(WorkspaceStatusChangedEvent event) {
WorkspaceStatus workspaceStatus = event.getWorkspaceStatusEvent().getStatus();
if (STOPPING == workspaceStatus) {
persistWorkspaceStatePromise =
appStateManager.get().persistWorkspaceState(getWorkspaceId());
}
}

@Override
public void onWorkspaceStopped(WorkspaceStoppedEvent event) {
if (persistWorkspaceStatePromise != null) {
persistWorkspaceStatePromise.then(
arg -> {
clearProjects();
resourceManager = null;
clearRuntime();
});
} else {
clearProjects();
resourceManager = null;
clearRuntime();
}
}
}
}
8 changes: 8 additions & 0 deletions plugins/plugin-docker/che-plugin-docker-machine/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<findbugs.failonerror>false</findbugs.failonerror>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down Expand Up @@ -73,6 +77,10 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-user</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-workspace</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Set;
import org.eclipse.che.api.core.model.machine.ServerConf;
import org.eclipse.che.api.environment.server.TypeSpecificEnvironmentParser;
import org.eclipse.che.plugin.docker.machine.cleaner.AppStatesPreferenceCleaner;
import org.eclipse.che.plugin.docker.machine.parser.DockerImageEnvironmentParser;
import org.eclipse.che.plugin.docker.machine.parser.DockerfileEnvironmentParser;

Expand All @@ -33,6 +34,7 @@ protected void configure() {
bind(
org.eclipse.che.plugin.docker.machine.cleaner
.RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber.class);
bind(AppStatesPreferenceCleaner.class);

@SuppressWarnings("unused")
Multibinder<String> devMachineEnvVars =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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.plugin.docker.machine.cleaner;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.core.model.workspace.Workspace;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.api.user.server.PreferenceManager;
import org.eclipse.che.api.user.server.UserManager;
import org.eclipse.che.api.workspace.server.event.WorkspaceRemovedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Handler for clean up app state preference when workspace is removed. */
@Singleton
public class AppStatesPreferenceCleaner implements EventSubscriber<WorkspaceRemovedEvent> {
private static final Logger LOG = LoggerFactory.getLogger(AppStatesPreferenceCleaner.class);

/** The name of the property for the mappings in user preferences. */
public static final String APP_STATES_PREFERENCE_PROPERTY = "IdeAppStates";

private JsonParser jsonParser;
private EventService eventService;
private UserManager userManager;
private PreferenceManager preferenceManager;

@Inject
public AppStatesPreferenceCleaner(
JsonParser jsonParser,
EventService eventService,
UserManager userManager,
PreferenceManager preferenceManager) {
this.jsonParser = jsonParser;
this.eventService = eventService;
this.userManager = userManager;
this.preferenceManager = preferenceManager;
}

@PostConstruct
public void subscribe() {
eventService.subscribe(this);
}

@Override
public void onEvent(WorkspaceRemovedEvent workspaceRemovedEvent) {
try {
Workspace workspace = workspaceRemovedEvent.getWorkspace();
User user = userManager.getByName(workspace.getNamespace());
if (user == null) {
return;
}

String userId = user.getId();
Map<String, String> preferences = preferenceManager.find(userId);
String appStates = preferences.get(APP_STATES_PREFERENCE_PROPERTY);
if (appStates == null) {
return;
}

JsonObject workspaces = jsonParser.parse(appStates).getAsJsonObject();
JsonElement removedWorkspacePreferences = workspaces.remove(workspace.getId());
if (removedWorkspacePreferences != null) {
preferences.put(APP_STATES_PREFERENCE_PROPERTY, workspaces.toString());
preferenceManager.save(userId, preferences);
}
} catch (NotFoundException | ServerException e) {
Workspace workspace = workspaceRemovedEvent.getWorkspace();
LOG.error(
"Unable to clean up preferences for owner of the workspace {} with namespace {}",
workspace.getId(),
workspace.getNamespace());
}
}
}

0 comments on commit 030d3f6

Please sign in to comment.