From 3c947a0f5314c1a5701d88a469dd0b904358ae9a Mon Sep 17 00:00:00 2001 From: Dmytro Kulieshov Date: Tue, 4 Jul 2017 11:18:57 +0300 Subject: [PATCH 01/11] Rework importing a project while consuming Factory to avoid using Everrest based Websocket calls (#5493) --- .../factory/utils/FactoryProjectImporter.java | 135 +++++++++++------- .../che/api/git/GitJsonRpcMessenger.java | 90 ++++++++++++ .../org/eclipse/che/api/git/GitModule.java | 1 + 3 files changed, 177 insertions(+), 49 deletions(-) create mode 100644 wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitJsonRpcMessenger.java diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java index 07248c3d55..782407defa 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java @@ -14,6 +14,8 @@ package org.eclipse.che.ide.factory.utils; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; +import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator; +import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter; import org.eclipse.che.api.core.model.project.SourceStorage; import org.eclipse.che.api.factory.shared.dto.FactoryDto; import org.eclipse.che.api.git.shared.GitCheckoutEvent; @@ -38,20 +40,18 @@ import org.eclipse.che.ide.api.project.wizard.ProjectNotificationSubscriber; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.user.AskCredentialsDialog; import org.eclipse.che.ide.api.user.Credentials; +import org.eclipse.che.ide.projectimport.wizard.ProjectImportOutputJsonRpcNotifier; import org.eclipse.che.ide.resource.Path; -import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; import org.eclipse.che.ide.rest.RestContext; import org.eclipse.che.ide.util.ExceptionUtils; import org.eclipse.che.ide.util.StringUtils; -import org.eclipse.che.ide.websocket.MessageBus; -import org.eclipse.che.ide.websocket.MessageBusProvider; -import org.eclipse.che.ide.websocket.WebSocketException; -import org.eclipse.che.ide.websocket.rest.SubscriptionHandler; import org.eclipse.che.security.oauth.OAuthStatus; +import javax.inject.Singleton; import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -75,17 +75,18 @@ import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUC * @author Valeriy Svydenko * @author Anton Korneta */ +@Singleton public class FactoryProjectImporter extends AbstractImporter { - private static final String CHANNEL = "git:checkout:"; + private final AskCredentialsDialog askCredentialsDialog; + private final CoreLocalizationConstant locale; + private final NotificationManager notificationManager; + private final String restContext; + private final DialogFactory dialogFactory; + private final OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry; + private final RequestTransmitter requestTransmitter; + private final ProjectImportOutputJsonRpcNotifier subscriber; - private final MessageBusProvider messageBusProvider; - private final AskCredentialsDialog askCredentialsDialog; - private final CoreLocalizationConstant locale; - private final NotificationManager notificationManager; - private final String restContext; - private final DialogFactory dialogFactory; - private final OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry; - private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + private final Map checkoutContextRegistry = new HashMap<>(); private FactoryDto factory; private AsyncCallback callback; @@ -99,8 +100,8 @@ public class FactoryProjectImporter extends AbstractImporter { @RestContext String restContext, DialogFactory dialogFactory, OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry, - MessageBusProvider messageBusProvider, - DtoUnmarshallerFactory dtoUnmarshallerFactory) { + RequestTransmitter requestTransmitter, + ProjectImportOutputJsonRpcNotifier subscriber) { super(appContext, subscriberFactory); this.notificationManager = notificationManager; this.askCredentialsDialog = askCredentialsDialog; @@ -108,8 +109,34 @@ public class FactoryProjectImporter extends AbstractImporter { this.restContext = restContext; this.dialogFactory = dialogFactory; this.oAuth2AuthenticatorRegistry = oAuth2AuthenticatorRegistry; - this.messageBusProvider = messageBusProvider; - this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + this.requestTransmitter = requestTransmitter; + this.subscriber = subscriber; + } + + @Inject + private void configure(RequestHandlerConfigurator requestHandlerConfigurator) { + requestHandlerConfigurator.newConfiguration() + .methodName("git/checkoutOutput") + .paramsAsDto(GitCheckoutEvent.class) + .noResult() + .withConsumer(this::consumeGitCheckoutEvent); + } + + private void consumeGitCheckoutEvent(GitCheckoutEvent event) { + CheckoutContext context = checkoutContextRegistry.get(event.getWorkspaceId() + event.getProjectName()); + if (context == null) { + return; + } + + String projectName = context.projectName; + String reference = event.isCheckoutOnly() ? event.getBranchRef() : context.startPoint; + String repository = context.repository; + String branch = context.branch; + + String title = locale.clonedSource(projectName); + String content = locale.clonedSourceWithCheckout(projectName, repository, reference, branch); + + notificationManager.notify(title, content, SUCCESS, FLOAT_MODE); } public void startImporting(FactoryDto factory, AsyncCallback callback) { @@ -186,7 +213,6 @@ public class FactoryProjectImporter extends AbstractImporter { @NotNull final SourceStorage sourceStorage) { final String projectName = pathToProject.lastSegment(); final StatusNotification notification = notificationManager.notify(locale.cloningSource(projectName), null, PROGRESS, FLOAT_MODE); - final ProjectNotificationSubscriber subscriber = subscriberFactory.createSubscriber(); subscriber.subscribe(projectName, notification); String location = sourceStorage.getLocation(); // it's needed for extract repository name from repository url e.g https://github.com/codenvy/che-core.git @@ -195,37 +221,8 @@ public class FactoryProjectImporter extends AbstractImporter { final Map parameters = firstNonNull(sourceStorage.getParameters(), Collections.emptyMap()); final String branch = parameters.get("branch"); final String startPoint = parameters.get("startPoint"); - final MessageBus messageBus = messageBusProvider.getMachineMessageBus(); - final String channel = CHANNEL + appContext.getWorkspaceId() + ':' + projectName; - final SubscriptionHandler successImportHandler = new SubscriptionHandler( - dtoUnmarshallerFactory.newWSUnmarshaller(GitCheckoutEvent.class)) { - @Override - protected void onMessageReceived(GitCheckoutEvent result) { - if (result.isCheckoutOnly()) { - notificationManager.notify(locale.clonedSource(projectName), - locale.clonedSourceWithCheckout(projectName, repository, result.getBranchRef(), branch), - SUCCESS, - FLOAT_MODE); - } else { - notificationManager.notify(locale.clonedSource(projectName), - locale.clonedWithCheckoutOnStartPoint(projectName, repository, startPoint, branch), - SUCCESS, - FLOAT_MODE); - } - } - @Override - protected void onErrorReceived(Throwable e) { - try { - messageBus.unsubscribe(channel, this); - } catch (WebSocketException ignore) { - } - } - }; - try { - messageBus.subscribe(channel, successImportHandler); - } catch (WebSocketException ignore) { - } + subscribe(projectName, repository, branch, startPoint); MutableProjectConfig importConfig = new MutableProjectConfig(); importConfig.setPath(pathToProject.toString()); @@ -239,6 +236,8 @@ public class FactoryProjectImporter extends AbstractImporter { @Override public Project apply(Project project) throws FunctionException { subscriber.onSuccess(); + unsubscribe(projectName); + notification.setContent(locale.clonedSource(projectName)); notification.setStatus(SUCCESS); @@ -249,9 +248,11 @@ public class FactoryProjectImporter extends AbstractImporter { @Override public Promise apply(PromiseError err) throws FunctionException { final int errorCode = ExceptionUtils.getErrorCode(err.getCause()); + unsubscribe(projectName); switch (errorCode) { case UNAUTHORIZED_GIT_OPERATION: subscriber.onFailure(err.getMessage()); + final Map attributes = ExceptionUtils.getAttributes(err.getCause()); final String providerName = attributes.get(PROVIDER_NAME); final String authenticateUrl = attributes.get(AUTHENTICATE_URL); @@ -299,6 +300,28 @@ public class FactoryProjectImporter extends AbstractImporter { }); } + private void subscribe(String projectName, String repository, String branch, String startPoint) { + String key = appContext.getWorkspaceId() + projectName; + + checkoutContextRegistry.put(key, new CheckoutContext(projectName, repository, branch, startPoint)); + requestTransmitter.newRequest() + .endpointId("ws-agent") + .methodName("git/checkoutOutput/subscribe") + .paramsAsString(key) + .sendAndSkipResult(); + } + + private void unsubscribe(String projectName) { + String key = appContext.getWorkspaceId() + projectName; + + checkoutContextRegistry.remove(key); + requestTransmitter.newRequest() + .endpointId("ws-agent") + .methodName("git/checkoutOutput/unsubscribe") + .paramsAsString(key) + .sendAndSkipResult(); + } + private Promise tryAuthenticateAndRepeatImport(@NotNull final String providerName, @NotNull final String authenticateUrl, @NotNull final Path pathToProject, @@ -340,4 +363,18 @@ public class FactoryProjectImporter extends AbstractImporter { callback.onFailure(error.getCause()); }); } + + private class CheckoutContext { + private final String projectName; + private final String repository; + private final String branch; + private final String startPoint; + + private CheckoutContext(String projectName, String repository, String branch, String startPoint) { + this.projectName = projectName; + this.repository = repository; + this.branch = branch; + this.startPoint = startPoint; + } + } } diff --git a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitJsonRpcMessenger.java b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitJsonRpcMessenger.java new file mode 100644 index 0000000000..75074c936d --- /dev/null +++ b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitJsonRpcMessenger.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.api.git; + +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.GitCheckoutEvent; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static com.google.common.collect.Sets.newConcurrentHashSet; + +@Singleton +public class GitJsonRpcMessenger implements EventSubscriber { + private final Map> endpointIds = new ConcurrentHashMap<>(); + + private final EventService eventService; + private final RequestTransmitter transmitter; + + @Inject + public GitJsonRpcMessenger(EventService eventService, RequestTransmitter transmitter) { + this.eventService = eventService; + this.transmitter = transmitter; + } + + @PostConstruct + private void subscribe() { + eventService.subscribe(this); + } + + @PreDestroy + private void unsubscribe() { + eventService.unsubscribe(this); + } + + @Override + public void onEvent(GitCheckoutEvent event) { + String workspaceIdAndProjectName = event.getWorkspaceId() + event.getProjectName(); + endpointIds.entrySet() + .stream() + .filter(it -> it.getValue().contains(workspaceIdAndProjectName)) + .map(Entry::getKey) + .forEach(it -> transmitter.newRequest() + .endpointId(it) + .methodName("git/checkoutOutput") + .paramsAsDto(event) + .sendAndSkipResult()); + } + + @Inject + private void configureSubscribeHandler(RequestHandlerConfigurator configurator) { + configurator.newConfiguration() + .methodName("git/checkoutOutput/subscribe") + .paramsAsString() + .noResult() + .withBiConsumer((endpointId, workspaceIdAndProjectName) -> { + endpointIds.putIfAbsent(endpointId, newConcurrentHashSet()); + endpointIds.get(endpointId).add(workspaceIdAndProjectName); + }); + } + + @Inject + private void configureUnSubscribeHandler(RequestHandlerConfigurator configurator) { + configurator.newConfiguration() + .methodName("git/checkoutOutput/unsubscribe") + .paramsAsString() + .noResult() + .withBiConsumer((endpointId, workspaceIdAndProjectName) -> { + endpointIds.getOrDefault(endpointId, newConcurrentHashSet()).remove(workspaceIdAndProjectName); + endpointIds.computeIfPresent(endpointId, (key, value) -> value.isEmpty() ? null : value); + }); + } +} diff --git a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitModule.java b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitModule.java index 79587e7ece..a27664b76a 100644 --- a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitModule.java +++ b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitModule.java @@ -48,6 +48,7 @@ public class GitModule extends AbstractModule { bind(StatusPageWriter.class); bind(TagListWriter.class); bind(GitWebSocketMessenger.class); + bind(GitJsonRpcMessenger.class); Multibinder.newSetBinder(binder(), CredentialsProvider.class).addBinding().to(GitBasicAuthenticationCredentialsProvider.class); From cb1348b26c877080441e3bd7720c9fa7b16ae862 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Tue, 4 Jul 2017 11:25:18 +0300 Subject: [PATCH 02/11] CHE-5346 Rework git client-service (#5476) 1. Get rid of using Everrest based Websocket calls in `GitServiceClientImpl.java`. 2. Remove deprecated methods from git client service. 3. Get rid of `DevMachine devMachine` parameter from all git client service methods. 4. Rework Git clent side to use streams and lambdas. --- .../che/ide/api/git/GitServiceClient.java | 791 +----------------- .../che/ide/api/git/GitServiceClientImpl.java | 771 +++-------------- .../git/client/action/AddToIndexAction.java | 11 +- .../action/CompareWithLatestAction.java | 60 +- .../client/action/DeleteRepositoryAction.java | 8 +- .../client/action/InitRepositoryAction.java | 8 +- .../git/client/add/AddToIndexPresenter.java | 29 +- .../git/client/branch/BranchPresenter.java | 155 ++-- .../checkout/CheckoutReferencePresenter.java | 42 +- .../git/client/commit/CommitPresenter.java | 29 +- .../git/client/compare/ComparePresenter.java | 160 ++-- .../branchlist/BranchListPresenter.java | 90 +- .../revisionslist/RevisionListPresenter.java | 72 +- .../delete/DeleteRepositoryPresenter.java | 31 +- .../ext/git/client/fetch/FetchPresenter.java | 118 ++- .../git/client/history/HistoryPresenter.java | 87 +- .../client/init/InitRepositoryPresenter.java | 29 +- .../ext/git/client/merge/MergePresenter.java | 126 ++- .../ext/git/client/pull/PullPresenter.java | 116 ++- .../client/push/PushToRemotePresenter.java | 99 +-- .../git/client/remote/RemotePresenter.java | 60 +- .../add/AddRemoteRepositoryPresenter.java | 25 +- .../remove/RemoveFromIndexPresenter.java | 29 +- .../reset/commit/ResetToCommitPresenter.java | 80 +- .../reset/files/ResetFilesPresenter.java | 118 ++- .../client/status/StatusCommandPresenter.java | 21 +- .../client/add/AddToIndexPresenterTest.java | 2 +- .../client/branch/BranchPresenterTest.java | 43 +- .../checkout/CheckoutReferenceTest.java | 16 +- .../client/commit/CommitPresenterTest.java | 15 +- .../git/client/fetch/FetchPresenterTest.java | 4 +- .../client/history/HistoryPresenterTest.java | 10 +- .../init/InitRepositoryPresenterTest.java | 2 +- .../git/client/merge/MergePresenterTest.java | 4 +- .../add/AddRemoteRepositoryPresenterTest.java | 4 +- .../reset/files/ResetFilesPresenterTest.java | 6 +- .../status/StatusCommandPresenterTest.java | 6 +- .../pullrequest/client/vcs/GitVcsService.java | 185 ++-- 38 files changed, 890 insertions(+), 2572 deletions(-) diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClient.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClient.java index 0ca64c7ae7..314ce7c462 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClient.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClient.java @@ -10,32 +10,23 @@ *******************************************************************************/ package org.eclipse.che.ide.api.git; -import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.BranchListMode; import org.eclipse.che.api.git.shared.CheckoutRequest; -import org.eclipse.che.api.git.shared.Commiters; import org.eclipse.che.api.git.shared.DiffType; -import org.eclipse.che.api.git.shared.GitUrlVendorInfo; import org.eclipse.che.api.git.shared.LogResponse; import org.eclipse.che.api.git.shared.MergeResult; import org.eclipse.che.api.git.shared.PullResponse; import org.eclipse.che.api.git.shared.PushResponse; import org.eclipse.che.api.git.shared.Remote; -import org.eclipse.che.api.git.shared.RepoInfo; -import org.eclipse.che.api.git.shared.ResetRequest; +import org.eclipse.che.api.git.shared.ResetRequest.ResetType; import org.eclipse.che.api.git.shared.Revision; import org.eclipse.che.api.git.shared.ShowFileContentResponse; import org.eclipse.che.api.git.shared.Status; import org.eclipse.che.api.git.shared.StatusFormat; -import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.resource.Path; -import org.eclipse.che.ide.rest.AsyncRequestCallback; -import org.eclipse.che.ide.websocket.WebSocketException; -import org.eclipse.che.ide.websocket.rest.RequestCallback; import java.util.List; import java.util.Map; @@ -45,37 +36,13 @@ import java.util.Map; * * @author Ann Zhuleva * @author Vlad Zhukovskyi + * @author Igor Vinokur */ public interface GitServiceClient { /** * Add changes to Git index (temporary storage). Sends request over WebSocket. * - * @param devMachine - * current machine - * @param projectConfig - * project (root of GIT repository) - * @param update - * if true then never stage new files, but stage modified new contents of tracked files and remove files from - * the index if the corresponding files in the working tree have been removed - * @param filePattern - * pattern of the files to be added, default is "." (all files are added) - * @param callback - * callback - * @throws WebSocketException - * @deprecated use {@link #add(DevMachine, Path, boolean, Path[])} - */ - void add(DevMachine devMachine, - ProjectConfig projectConfig, - boolean update, - List filePattern, - RequestCallback callback) throws WebSocketException; - - /** - * Add changes to Git index (temporary storage). Sends request over WebSocket. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param update @@ -83,15 +50,12 @@ public interface GitServiceClient { * the index if the corresponding files in the working tree have been removed * @param paths * pattern of the files to be added, default is "." (all files are added) - * @throws WebSocketException */ - Promise add(DevMachine devMachine, Path project, boolean update, Path[] paths); + Promise add(Path project, boolean update, Path[] paths); /** * Fetch changes from remote repository to local one (sends request over WebSocket). * - * @param devMachine - * current machine * @param project * project root of GIT repository * @param remote @@ -107,100 +71,23 @@ public interface GitServiceClient { * * @param removeDeletedRefs * if true then delete removed refs from local repository - * @param callback - * callback - * @throws WebSocketException - * @deprecated use {@link #fetch(DevMachine, Path, String, List, boolean)} */ - @Deprecated - void fetch(DevMachine devMachine, - ProjectConfigDto project, - String remote, - List refspec, - boolean removeDeletedRefs, - RequestCallback callback) throws WebSocketException; - - /** - * Fetch changes from remote repository to local one (sends request over WebSocket). - * - * @param devMachine - * current machine - * @param project - * project root of GIT repository - * @param remote - * remote repository's name - * @param refspec - * list of refspec to fetch. - *

- * Expected form is: - *

    - *
  • refs/heads/featured:refs/remotes/origin/featured - branch 'featured' from remote repository will be fetched to - * 'refs/remotes/origin/featured'.
  • - *
  • featured - remote branch name.
  • - *
- * @param removeDeletedRefs - * if true then delete removed refs from local repository - * @throws WebSocketException - */ - Promise fetch(DevMachine devMachine, Path project, String remote, List refspec, boolean removeDeletedRefs); + Promise fetch(Path project, String remote, List refspec, boolean removeDeletedRefs); /** * Get the list of the branches. For now, all branches cannot be returned at once, so the parameter remote tells to get * remote branches if true or local ones (if false). * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param mode - * get remote branches - * @param callback - * @deprecated use {@link #branchList(DevMachine, Path, BranchListMode)} - */ - @Deprecated - void branchList(DevMachine devMachine, - ProjectConfig project, - @Nullable BranchListMode mode, - AsyncRequestCallback> callback); - - /** - * Get the list of the branches. For now, all branches cannot be returned at once, so the parameter remote tells to get - * remote branches if true or local ones (if false). - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param mode * get remote branches */ - Promise> branchList(DevMachine devMachine, Path project, BranchListMode mode); + Promise> branchList(Path project, BranchListMode mode); /** * Delete branch. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param name - * name of the branch to delete - * @param force - * force if true delete branch {@code name} even if it is not fully merged - * @deprecated use {@link #branchDelete(DevMachine, Path, String, boolean)} - */ - @Deprecated - void branchDelete(DevMachine devMachine, - ProjectConfigDto project, - String name, - boolean force, - AsyncRequestCallback callback); - - /** - * Delete branch. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param name @@ -208,33 +95,11 @@ public interface GitServiceClient { * @param force * force if true delete branch {@code name} even if it is not fully merged */ - Promise branchDelete(DevMachine devMachine, Path project, String name, boolean force); + Promise branchDelete(Path project, String name, boolean force); /** * Checkout the branch with pointed name. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param oldName - * branch's current name - * @param newName - * branch's new name - * @deprecated use {@link #branchRename(DevMachine, Path, String, String)} - */ - @Deprecated - void branchRename(DevMachine devMachine, - ProjectConfigDto project, - String oldName, - String newName, - AsyncRequestCallback callback); - - /** - * Checkout the branch with pointed name. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param oldName @@ -242,33 +107,11 @@ public interface GitServiceClient { * @param newName * branch's new name */ - Promise branchRename(DevMachine devMachine, Path project, String oldName, String newName); + Promise branchRename(Path project, String oldName, String newName); /** * Create new branch with pointed name. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param name - * new branch's name - * @param startPoint - * name of a commit at which to start the new branch - * @deprecated use {@link #branchCreate(DevMachine, Path, String, String)} - */ - @Deprecated - void branchCreate(DevMachine devMachine, - ProjectConfigDto project, - String name, - @Nullable String startPoint, - AsyncRequestCallback callback); - - /** - * Create new branch with pointed name. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param name @@ -276,80 +119,21 @@ public interface GitServiceClient { * @param startPoint * name of a commit at which to start the new branch */ - Promise branchCreate(DevMachine devMachine, Path project, String name, String startPoint); + Promise branchCreate(Path project, String name, String startPoint); /** * Checkout the branch with pointed name. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param checkoutRequest - * checkout request - * @deprecated {@link #checkout(DevMachine, Path, CheckoutRequest)} - */ - @Deprecated - void checkout(DevMachine devMachine, - ProjectConfig project, - CheckoutRequest checkoutRequest, - AsyncRequestCallback callback); - - /** - * Checkout the branch with pointed name. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param request * checkout request */ - Promise checkout(DevMachine devMachine, Path project, CheckoutRequest request); + Promise checkout(Path project, CheckoutRequest request); /** * Get the list of remote repositories for pointed by {@code projectConfig} parameter one. * - * @param devMachine - * current machine - * @param projectConfig - * project (root of GIT repository) - * @param remoteName - * remote repository's name - * @param verbose - * If true show remote url and name otherwise show remote name - * @deprecated instead of this method should use {@link GitServiceClient#remoteList(DevMachine, ProjectConfig, String, boolean)} - */ - @Deprecated - void remoteList(DevMachine devMachine, - ProjectConfigDto projectConfig, - @Nullable String remoteName, - boolean verbose, - AsyncRequestCallback> callback); - - /** - * Get the list of remote repositories for pointed by {@code projectConfig} parameter one. - * - * @param devMachine - * current machine - * @param projectConfig - * project (root of GIT repository) - * @param remoteName - * remote repository's name. Can be null in case when it is need to fetch all {@link Remote} - * @param verbose - * If true show remote url and name otherwise show remote name - * @return a promise that provides list {@link Remote} repositories for the {@code workspaceId}, {@code projectConfig}, - * {@code remoteName}, {@code verbose} or rejects with an error. - * @deprecated use {@link #remoteList(DevMachine, Path, String, boolean)} - */ - @Deprecated - Promise> remoteList(DevMachine devMachine, ProjectConfig projectConfig, @Nullable String remoteName, boolean verbose); - - /** - * Get the list of remote repositories for pointed by {@code projectConfig} parameter one. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param remote @@ -358,35 +142,12 @@ public interface GitServiceClient { * If true show remote url and name otherwise show remote name * @return a promise that provides list {@link Remote} repositories for the {@code workspaceId}, {@code projectConfig}, * {@code remoteName}, {@code verbose} or rejects with an error. - * @deprecated use {@link #remoteList(DevMachine, Path, String, boolean)} */ - Promise> remoteList(DevMachine devMachine, Path project, String remote, boolean verbose); + Promise> remoteList(Path project, String remote, boolean verbose); /** * Adds remote repository to the list of remote repositories. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param name - * remote repository's name - * @param url - * remote repository's URL - * @deprecated use {@link #remoteAdd(DevMachine, Path, String, String)} - */ - @Deprecated - void remoteAdd(DevMachine devMachine, - ProjectConfig project, - String name, - String url, - AsyncRequestCallback callback); - - /** - * Adds remote repository to the list of remote repositories. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param name @@ -394,58 +155,21 @@ public interface GitServiceClient { * @param url * remote repository's URL */ - Promise remoteAdd(DevMachine devMachine, Path project, String name, String url); + Promise remoteAdd(Path project, String name, String url); /** * Deletes the pointed(by name) remote repository from the list of repositories. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param name - * remote repository name to delete - * @deprecated use {@link #remoteDelete(DevMachine, Path, String)} - */ - @Deprecated - void remoteDelete(DevMachine devMachine, - ProjectConfig project, - String name, - AsyncRequestCallback callback); - - /** - * Deletes the pointed(by name) remote repository from the list of repositories. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param name * remote repository name to delete */ - Promise remoteDelete(DevMachine devMachine, Path project, String name); + Promise remoteDelete(Path project, String name); /** * Remove items from the working tree and the index. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param items - * items to remove - * @param cached - * is for removal only from index - * @deprecated use {@link #remove(DevMachine, Path, Path[], boolean)} - */ - @Deprecated - void remove(DevMachine devMachine, ProjectConfigDto project, List items, boolean cached, AsyncRequestCallback callback); - - /** - * Remove items from the working tree and the index. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param items @@ -453,7 +177,7 @@ public interface GitServiceClient { * @param cached * is for removal only from index */ - Promise remove(DevMachine devMachine, Path project, Path[] items, boolean cached); + Promise remove(Path project, Path[] items, boolean cached); /** * Reset current HEAD to the specified state. There two types of the reset:
@@ -461,35 +185,6 @@ public interface GitServiceClient { * git reset [paths] is the opposite of git add [paths]. 2. Reset the current branch head to [commit] and * possibly updates the index (resetting it to the tree of [commit]) and the working tree depending on [mode]. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param commit - * commit to which current head should be reset - * @param resetType - * type of the reset - * @param filePattern - * pattern of the files to reset the index. If null then reset the current branch head to [commit], - * else reset received files in index. - * @deprecated use {@link #reset(DevMachine, Path, String, ResetRequest.ResetType, Path[])} - */ - @Deprecated - void reset(DevMachine devMachine, - ProjectConfigDto project, - String commit, - @Nullable ResetRequest.ResetType resetType, - @Nullable List filePattern, - AsyncRequestCallback callback); - - /** - * Reset current HEAD to the specified state. There two types of the reset:
- * 1. Reset files in index - content of files is untouched. Typically it is useful to remove from index mistakenly added files.
- * git reset [paths] is the opposite of git add [paths]. 2. Reset the current branch head to [commit] and - * possibly updates the index (resetting it to the tree of [commit]) and the working tree depending on [mode]. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param commit @@ -500,71 +195,21 @@ public interface GitServiceClient { * pattern of the files to reset the index. If null then reset the current branch head to [commit], * else reset received files in index. */ - Promise reset(DevMachine devMachine, Path project, String commit, ResetRequest.ResetType resetType, Path[] files); + Promise reset(Path project, String commit, ResetType resetType, Path[] files); /** * Initializes new Git repository (over WebSocket). * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param bare - * to create bare repository or not - * @param callback - * callback - * @deprecated use {@link #init(DevMachine, Path, boolean)} - */ - @Deprecated - void init(DevMachine devMachine, ProjectConfigDto project, boolean bare, RequestCallback callback) throws WebSocketException; - - /** - * Initializes new Git repository (over WebSocket). - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param bare * to create bare repository or not */ - Promise init(DevMachine devMachine, Path project, boolean bare); + Promise init(Path project, boolean bare); /** * Pull (fetch and merge) changes from remote repository to local one (sends request over WebSocket). * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param refSpec - * list of refspec to fetch. - *

- * Expected form is: - *

    - *
  • refs/heads/featured:refs/remotes/origin/featured - branch 'featured' from remote repository will be fetched to - * 'refs/remotes/origin/featured'.
  • - *
  • featured - remote branch name.
  • - *
- * @param remote - * remote remote repository's name - * @param callback - * callback - * @throws WebSocketException - * @deprecated use {@link #pull(DevMachine, Path, String, String)} - */ - @Deprecated - void pull(DevMachine devMachine, - ProjectConfigDto project, - String refSpec, - String remote, - AsyncRequestCallback callback); - - /** - * Pull (fetch and merge) changes from remote repository to local one (sends request over WebSocket). - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param refSpec @@ -579,63 +224,11 @@ public interface GitServiceClient { * @param remote * remote remote repository's name */ - Promise pull(DevMachine devMachine, Path project, String refSpec, String remote); + Promise pull(Path project, String refSpec, String remote); /** * Push changes from local repository to remote one (sends request over WebSocket). * - * @param devMachine - * current machine - * @param project - * project - * @param refSpec - * list of refspec to push - * @param remote - * remote repository name or url - * @param force - * push refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. If true - * disables the check. This can cause the remote repository to lose commits - * @param callback - * callback - * @throws WebSocketException - * @deprecated use {@link #push(DevMachine, Path, List, String, boolean)} - */ - @Deprecated - void push(DevMachine devMachine, - ProjectConfigDto project, - List refSpec, - String remote, boolean force, - AsyncRequestCallback callback); - - - /** - * Push changes from local repository to remote one (sends request over WebSocket). - * - * @param devMachine - * current machine - * @param project - * project - * @param refSpec - * list of refspec to push - * @param remote - * remote repository name or url - * @param force - * push refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. If true - * disables the check. This can cause the remote repository to lose commits - * @deprecated use {@link #push(DevMachine, Path, List, String, boolean)} - */ - @Deprecated - Promise push(DevMachine devMachine, - ProjectConfig project, - List refSpec, - String remote, - boolean force); - - /** - * Push changes from local repository to remote one (sends request over WebSocket). - * - * @param devMachine - * current machine * @param project * project * @param refSpec @@ -646,36 +239,26 @@ public interface GitServiceClient { * push refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. If true * disables the check. This can cause the remote repository to lose commits */ - Promise push(DevMachine devMachine, Path project, List refSpec, String remote, boolean force); + Promise push(Path project, List refSpec, String remote, boolean force); /** * Clones one remote repository to local one (over WebSocket). * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param remoteUri * the location of the remote repository * @param remoteName * remote name instead of "origin" - * @param callback - * callback - * @throws WebSocketException - * @deprecated not used anymore */ - void cloneRepository(DevMachine devMachine, - ProjectConfigDto project, - String remoteUri, - String remoteName, - RequestCallback callback) throws WebSocketException; + Promise clone(Path project, + String remoteUri, + String remoteName); /** * Performs commit changes from index to repository. The result of the commit is represented by {@link Revision}, which is returned by * callback in onSuccess(Revision result). Sends request over WebSocket. * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param message @@ -684,166 +267,36 @@ public interface GitServiceClient { * automatically stage files that have been modified and deleted * @param amend * indicates that previous commit must be overwritten - * @param callback - * callback - * @throws WebSocketException - * @deprecated use {@link #commit(DevMachine, Path, String, boolean, boolean)} */ - @Deprecated - void commit(DevMachine devMachine, - ProjectConfig project, - String message, - boolean all, - boolean amend, - AsyncRequestCallback callback); - - /** - * Performs commit changes from index to repository. The result of the commit is represented by {@link Revision}, which is returned by - * callback in onSuccess(Revision result). Sends request over WebSocket. - * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param message - * commit log message - * @param all - * automatically stage files that have been modified and deleted - * @param amend - * indicates that previous commit must be overwritten - * @throws WebSocketException - */ - Promise commit(DevMachine devMachine, Path project, String message, boolean all, boolean amend); - - /** - * Performs commit for the given files (ignoring git index). - * - * @param devMachine - * current machine - * @param projectConfig - * project (root of GIT repository) - * @param message - * commit log message - * @param files - * the list of iles that are commited, ignoring the index - * @param amend - * indicates that previous commit must be overwritten - * @param callback - * callback - * @throws WebSocketException - * @deprecated use {@link #commit(DevMachine, Path, String, Path[], boolean)} - */ - @Deprecated - void commit(DevMachine devMachine, - ProjectConfigDto projectConfig, - String message, - List files, - boolean amend, - AsyncRequestCallback callback); - - /** - * Performs commit for the given files (ignoring git index). - * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param message - * commit log message - * @param files - * the list of iles that are commited, ignoring the index - * @param amend - * indicates that previous commit must be overwritten - * @throws WebSocketException - */ - Promise commit(DevMachine devMachine, Path project, String message, Path[] files, boolean amend); + Promise commit(Path project, String message, boolean all, boolean amend); /** * Performs commit changes from index to repository. * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param message * commit log message - * @param all - * automatically stage files that have been modified and deleted - * @param files - * the list of files that are committed, ignoring the index * @param amend * indicates that previous commit must be overwritten + * @param files + * the list of files that are committed, ignoring the index */ - Promise commit(DevMachine devMachine, Path project, String message, boolean all, Path[] files, boolean amend); + Promise commit(Path project, String message, boolean amend, Path[] files); /** * Get repository options. * - * @param devMachine - * current machine - * @param projectConfig - * project (root of GIT repository) - * @param requestedConfig - * list of config keys - * @param callback - * callback for sending asynchronous response - * @deprecated use {@link #config(DevMachine, Path, List)} - */ - @Deprecated - void config(DevMachine devMachine, - ProjectConfigDto projectConfig, - List requestedConfig, - AsyncRequestCallback> callback); - - /** - * Get repository options. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param requestedConfig * list of config keys */ - Promise> config(DevMachine devMachine, Path project, List requestedConfig); + Promise> config(Path project, List requestedConfig); /** * Compare two commits, get the diff for pointed file(s) or for the whole project in text format. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param fileFilter - * files for which to show changes - * @param type - * type of diff format - * @param noRenames - * don't show renamed files - * @param renameLimit - * the limit of shown renamed files - * @param commitA - * first commit to compare - * @param commitB - * second commit to be compared - * @deprecated use {@link #diff(DevMachine, Path, List, DiffType, boolean, int, String, String)} - */ - @Deprecated - void diff(DevMachine devMachine, - ProjectConfigDto project, - List fileFilter, - DiffType type, - boolean noRenames, - int renameLimit, - String commitA, - String commitB, - AsyncRequestCallback callback); - - /** - * Compare two commits, get the diff for pointed file(s) or for the whole project in text format. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param fileFilter @@ -859,8 +312,7 @@ public interface GitServiceClient { * @param commitB * second commit to be compared */ - Promise diff(DevMachine devMachine, - Path project, + Promise diff(Path project, List fileFilter, DiffType type, boolean noRenames, @@ -872,41 +324,6 @@ public interface GitServiceClient { * Compare commit with index or working tree (depends on {@code cached}), get the diff for pointed file(s) or for the whole project in * text format. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param fileFilter - * files for which to show changes - * @param type - * type of diff format - * @param noRenames - * don't show renamed files - * @param renameLimit - * the limit of shown renamed files - * @param commitA - * commit to compare - * @param cached - * if true then compare commit with index, if false, then compare with working tree. - * @deprecated use {@link #diff(DevMachine, Path, List, DiffType, boolean, int, String, boolean)} - */ - @Deprecated - void diff(DevMachine devMachine, - ProjectConfigDto project, - List fileFilter, - DiffType type, - boolean noRenames, - int renameLimit, - String commitA, - boolean cached, - AsyncRequestCallback callback); - - /** - * Compare commit with index or working tree (depends on {@code cached}), get the diff for pointed file(s) or for the whole project in - * text format. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param files @@ -922,8 +339,7 @@ public interface GitServiceClient { * @param cached * if true then compare commit with index, if false, then compare with working tree. */ - Promise diff(DevMachine devMachine, - Path project, + Promise diff(Path project, List files, DiffType type, boolean noRenames, @@ -934,27 +350,6 @@ public interface GitServiceClient { /** * Get the file content from specified revision or branch. * - * @param devMachine - * current machine - * @param project - * project configuration of root GIT repository - * @param file - * file name with its full path - * @param version - * revision or branch where the showed file is present - * @param callback - * callback for sending asynchronous response with file content - * @deprecated use {@link #showFileContent(DevMachine, Path, Path, String)} - */ - @Deprecated - void showFileContent(DevMachine devMachine, ProjectConfigDto project, String file, String version, - AsyncRequestCallback callback); - - /** - * Get the file content from specified revision or branch. - * - * @param devMachine - * current machine * @param project * project configuration of root GIT repository * @param file @@ -962,87 +357,33 @@ public interface GitServiceClient { * @param version * revision or branch where the showed file is present */ - Promise showFileContent(DevMachine devMachine, Path project, Path file, String version); - - /** - * Get log of commits. The result is the list of {@link Revision}, which is returned by callback in - * onSuccess(Revision result). - * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param fileFilter - * range of files to filter revisions list - * @param isTextFormat - * if true the loq response will be in text format - * @deprecated use {@link #log(DevMachine, Path, Path[], boolean)} - */ - @Deprecated - void log(DevMachine devMachine, ProjectConfigDto project, List fileFilter, boolean isTextFormat, - AsyncRequestCallback callback); + Promise showFileContent(Path project, Path file, String version); /** * Get log of commits. * - * Method is deprecated. Use {@link #log(DevMachine, Path, Path[], int, int, boolean)} to pass - * {@code skip} and {@code maxCount} parameters to limit the number of returning entries. - * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param fileFilter - * range of files to filter revisions list - * @param plainText - * if true the loq response will be in text format - */ - @Deprecated - Promise log(DevMachine devMachine, Path project, @Nullable Path[] fileFilter, boolean plainText); - - /** - * Get log of commits. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param fileFilter * range of files to filter revisions list * @param skip - * the number of commits that will be skipped + * the number of commits that will be skipped * @param maxCount - * the number of commits that will be returned + * the number of commits that will be returned * @param plainText * if true the loq response will be in text format */ - Promise log(DevMachine devMachine, Path project, @Nullable Path[] fileFilter, int skip, int maxCount, boolean plainText); + Promise log(Path project, @Nullable Path[] fileFilter, int skip, int maxCount, boolean plainText); /** * Merge the pointed commit with current HEAD. * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param commit - * commit's reference to merge with - * @deprecated use {@link #merge(DevMachine, Path, String)} - */ - @Deprecated - void merge(DevMachine devMachine, ProjectConfigDto project, String commit, AsyncRequestCallback callback); - - /** - * Merge the pointed commit with current HEAD. - * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param commit * commit's reference to merge with */ - Promise merge(DevMachine devMachine, Path project, String commit); + Promise merge(Path project, String commit); /** * Gets the working tree status. The status of added, modified or deleted files is shown is written in {@link String}. The format may @@ -1067,90 +408,28 @@ public interface GitServiceClient { * ?? folder/test.css * * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @param format - * to show in short format or not - * @deprecated use {@link #statusText(DevMachine, Path, StatusFormat)} - */ - @Deprecated - void statusText(DevMachine devMachine, ProjectConfigDto project, StatusFormat format, AsyncRequestCallback callback); - - /** - * Gets the working tree status. The status of added, modified or deleted files is shown is written in {@link String}. The format may - * be - * long, short or porcelain. Example of detailed format:
- *

- *

- *

-     * # Untracked files:
-     * #
-     * # file.html
-     * # folder
-     * 
- *

- * Example of short format: - *

- *

- *

-     * M  pom.xml
-     * A  folder/test.html
-     * D  123.txt
-     * ?? folder/test.css
-     * 
- * - * @param devMachine - * current machine * @param project * project (root of GIT repository) * @param format * to show in short format or not */ - Promise statusText(DevMachine devMachine, Path project, StatusFormat format); - - /** - * Gets the working tree status : list of untracked, changed not commited and changed not updated. - * - * @param devMachine - * current machine - * @param project - * project (root of GIT repository) - * @deprecated use {@link #getStatus(DevMachine, Path)} - */ - @Deprecated - void status(DevMachine devMachine, ProjectConfigDto project, AsyncRequestCallback callback); + Promise statusText(Path project, StatusFormat format); /** * Returns the current working tree status. * - * @param devMachine - * current machine * @param project * the project. * @return the promise which either resolves working tree status or rejects with an error */ - Promise getStatus(DevMachine devMachine, Path project); + Promise getStatus(Path project); /** * Remove the git repository from given path. * - * @param devMachine - * current machine * @param project * the project path * @return the promise with success status */ - Promise deleteRepository(DevMachine devMachine, Path project); - - @Deprecated - void getCommitters(DevMachine devMachine, ProjectConfigDto project, AsyncRequestCallback callback); - - @Deprecated - void deleteRepository(DevMachine devMachine, ProjectConfigDto project, AsyncRequestCallback callback); - - - @Deprecated - void getUrlVendorInfo(DevMachine devMachine, String vcsUrl, AsyncRequestCallback callback); + Promise deleteRepository(Path project); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClientImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClientImpl.java index aaf3b27609..7db298f3a0 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClientImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/git/GitServiceClientImpl.java @@ -10,11 +10,9 @@ *******************************************************************************/ package org.eclipse.che.ide.api.git; -import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.git.shared.AddRequest; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.BranchCreateRequest; @@ -25,7 +23,6 @@ import org.eclipse.che.api.git.shared.CommitRequest; import org.eclipse.che.api.git.shared.Commiters; import org.eclipse.che.api.git.shared.DiffType; import org.eclipse.che.api.git.shared.FetchRequest; -import org.eclipse.che.api.git.shared.GitUrlVendorInfo; import org.eclipse.che.api.git.shared.LogResponse; import org.eclipse.che.api.git.shared.MergeRequest; import org.eclipse.che.api.git.shared.MergeResult; @@ -35,48 +32,31 @@ import org.eclipse.che.api.git.shared.PushRequest; import org.eclipse.che.api.git.shared.PushResponse; import org.eclipse.che.api.git.shared.Remote; import org.eclipse.che.api.git.shared.RemoteAddRequest; -import org.eclipse.che.api.git.shared.RepoInfo; import org.eclipse.che.api.git.shared.ResetRequest; import org.eclipse.che.api.git.shared.Revision; import org.eclipse.che.api.git.shared.ShowFileContentResponse; import org.eclipse.che.api.git.shared.Status; import org.eclipse.che.api.git.shared.StatusFormat; -import org.eclipse.che.ide.api.machine.DevMachine; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper.RequestCall; -import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; -import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.MimeType; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.machine.WsAgentStateController; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.rest.AsyncRequest; -import org.eclipse.che.ide.rest.AsyncRequestCallback; import org.eclipse.che.ide.rest.AsyncRequestFactory; import org.eclipse.che.ide.rest.AsyncRequestLoader; import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; -import org.eclipse.che.ide.rest.HTTPHeader; import org.eclipse.che.ide.rest.StringMapUnmarshaller; import org.eclipse.che.ide.rest.StringUnmarshaller; import org.eclipse.che.ide.ui.loaders.request.LoaderFactory; -import org.eclipse.che.ide.websocket.Message; -import org.eclipse.che.ide.websocket.MessageBuilder; -import org.eclipse.che.ide.websocket.MessageBus; -import org.eclipse.che.ide.websocket.WebSocketException; -import org.eclipse.che.ide.websocket.rest.RequestCallback; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; import java.util.List; import java.util.Map; -import static com.google.gwt.http.client.RequestBuilder.DELETE; -import static com.google.gwt.http.client.RequestBuilder.POST; +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.toList; +import static org.eclipse.che.api.git.shared.AddRequest.DEFAULT_PATTERN; import static org.eclipse.che.api.git.shared.StatusFormat.PORCELAIN; -import static org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper.createFromAsyncRequest; import static org.eclipse.che.ide.MimeType.APPLICATION_JSON; import static org.eclipse.che.ide.MimeType.TEXT_PLAIN; import static org.eclipse.che.ide.rest.HTTPHeader.ACCEPT; @@ -90,43 +70,39 @@ import static org.eclipse.che.ide.rest.HTTPHeader.CONTENTTYPE; */ @Singleton public class GitServiceClientImpl implements GitServiceClient { - private static final String ADD = "/git/add"; - private static final String BRANCH = "/git/branch"; - private static final String CHECKOUT = "/git/checkout"; - private static final String CLONE = "/git/clone"; - private static final String COMMIT = "/git/commit"; - private static final String CONFIG = "/git/config"; - private static final String DIFF = "/git/diff"; - private static final String FETCH = "/git/fetch"; - private static final String INIT = "/git/init"; - private static final String LOG = "/git/log"; - private static final String SHOW = "/git/show"; - private static final String MERGE = "/git/merge"; - private static final String STATUS = "/git/status"; - private static final String PUSH = "/git/push"; - private static final String PULL = "/git/pull"; - private static final String REMOTE = "/git/remote"; - private static final String REMOVE = "/git/remove"; - private static final String RESET = "/git/reset"; - private static final String COMMITERS = "/git/commiters"; - private static final String REPOSITORY = "/git/repository"; + private static final String ADD = "/git/add"; + private static final String BRANCH = "/git/branch"; + private static final String CHECKOUT = "/git/checkout"; + private static final String CLONE = "/git/clone"; + private static final String COMMIT = "/git/commit"; + private static final String CONFIG = "/git/config"; + private static final String DIFF = "/git/diff"; + private static final String FETCH = "/git/fetch"; + private static final String INIT = "/git/init"; + private static final String LOG = "/git/log"; + private static final String SHOW = "/git/show"; + private static final String MERGE = "/git/merge"; + private static final String STATUS = "/git/status"; + private static final String PUSH = "/git/push"; + private static final String PULL = "/git/pull"; + private static final String REMOTE = "/git/remote"; + private static final String REMOVE = "/git/remove"; + private static final String RESET = "/git/reset"; + private static final String REPOSITORY = "/git/repository"; /** Loader to be displayed. */ private final AsyncRequestLoader loader; private final DtoFactory dtoFactory; private final DtoUnmarshallerFactory dtoUnmarshallerFactory; private final AsyncRequestFactory asyncRequestFactory; - private final WsAgentStateController wsAgentStateController; private final AppContext appContext; @Inject protected GitServiceClientImpl(LoaderFactory loaderFactory, - WsAgentStateController wsAgentStateController, DtoFactory dtoFactory, AsyncRequestFactory asyncRequestFactory, DtoUnmarshallerFactory dtoUnmarshallerFactory, AppContext appContext) { - this.wsAgentStateController = wsAgentStateController; this.appContext = appContext; this.loader = loaderFactory.newLoader(); this.dtoFactory = dtoFactory; @@ -135,93 +111,30 @@ public class GitServiceClientImpl implements GitServiceClient { } @Override - public void init(DevMachine devMachine, ProjectConfigDto project, boolean bare, final RequestCallback callback) - throws WebSocketException { - String url = INIT + "?projectPath=" + project.getPath() + "&bare=" + bare; - - Message message = new MessageBuilder(POST, url).header(ACCEPT, TEXT_PLAIN).build(); - - sendMessageToWS(message, callback); + public Promise init(Path project, boolean bare) { + String url = getWsAgentBaseUrl() + INIT + "?projectPath=" + project + "&bare=" + bare; + return asyncRequestFactory.createPostRequest(url, null).loader(loader).send(); } @Override - public Promise init(DevMachine devMachine, final Path project, final boolean bare) { - return createFromAsyncRequest(new RequestCall() { - @Override - public void makeCall(final AsyncCallback callback) { - String url = INIT + "?projectPath=" + project.toString() + "&bare=" + bare; - - Message message = new MessageBuilder(POST, url).header(ACCEPT, TEXT_PLAIN).build(); - - sendMessageToWS(message, new RequestCallback() { - @Override - protected void onSuccess(Void result) { - callback.onSuccess(result); - } - - @Override - protected void onFailure(Throwable exception) { - callback.onFailure(exception); - } - }); - } - }); - } - - @Override - public void cloneRepository(DevMachine devMachine, - ProjectConfigDto project, - String remoteUri, - String remoteName, - RequestCallback callback) throws WebSocketException { + public Promise clone(Path project, + String remoteUri, + String remoteName) { CloneRequest cloneRequest = dtoFactory.createDto(CloneRequest.class) .withRemoteName(remoteName) .withRemoteUri(remoteUri) - .withWorkingDir(project.getPath()); - - String params = "?projectPath=" + project.getPath(); + .withWorkingDir(project.toString()); + String params = "?projectPath=" + project; String url = CLONE + params; - MessageBuilder builder = new MessageBuilder(POST, url); - builder.data(dtoFactory.toJson(cloneRequest)) - .header(CONTENTTYPE, APPLICATION_JSON) - .header(ACCEPT, APPLICATION_JSON); - Message message = builder.build(); - - sendMessageToWS(message, callback); - } - - private void sendMessageToWS(final @NotNull Message message, final @NotNull RequestCallback callback) { - wsAgentStateController.getMessageBus().then(new Operation() { - @Override - public void apply(MessageBus arg) throws OperationException { - try { - arg.send(message, callback); - } catch (WebSocketException e) { - throw new OperationException(e.getMessage(), e); - } - } - }); + return asyncRequestFactory.createPostRequest(url, cloneRequest).loader(loader).send(); } @Override - @Deprecated - public void statusText(DevMachine devMachine, ProjectConfigDto project, StatusFormat format, AsyncRequestCallback callback) { - String params = "?projectPath=" + project.getPath() + "&format=" + format; - String url = appContext.getDevMachine().getWsAgentBaseUrl() + STATUS + params; - - asyncRequestFactory.createGetRequest(url) - .loader(loader) - .header(CONTENTTYPE, APPLICATION_JSON) - .header(ACCEPT, TEXT_PLAIN) - .send(callback); - } - - @Override - public Promise statusText(DevMachine devMachine, Path project, StatusFormat format) { - String params = "?projectPath=" + project.toString() + "&format=" + format; - String url = appContext.getDevMachine().getWsAgentBaseUrl() + STATUS + params; + public Promise statusText(Path project, StatusFormat format) { + String params = "?projectPath=" + project + "&format=" + format; + String url = getWsAgentBaseUrl() + STATUS + params; return asyncRequestFactory.createGetRequest(url) .loader(loader) @@ -231,89 +144,37 @@ public class GitServiceClientImpl implements GitServiceClient { } @Override - public void add(DevMachine devMachine, - ProjectConfig project, - boolean update, - @Nullable List filePattern, - RequestCallback callback) throws WebSocketException { - AddRequest addRequest = dtoFactory.createDto(AddRequest.class).withUpdate(update); - if (filePattern == null) { - addRequest.setFilePattern(AddRequest.DEFAULT_PATTERN); - } else { - addRequest.setFilePattern(filePattern); - } - String url = ADD + "?projectPath=" + project.getPath(); - - MessageBuilder builder = new MessageBuilder(POST, url); - builder.data(dtoFactory.toJson(addRequest)) - .header(CONTENTTYPE, APPLICATION_JSON); - Message message = builder.build(); - - sendMessageToWS(message, callback); + public Promise add(Path project, boolean update, Path[] paths) { + AddRequest addRequest = dtoFactory.createDto(AddRequest.class) + .withUpdate(update); + addRequest.setFilePattern(paths == null ? DEFAULT_PATTERN : + stream(paths).map(path -> path.isEmpty() ? "." : path.toString()).collect(toList())); + String url = getWsAgentBaseUrl() + ADD + "?projectPath=" + project; + return asyncRequestFactory.createPostRequest(url, addRequest).loader(loader).send(); } @Override - public Promise add(final DevMachine devMachine, final Path project, final boolean update, final Path[] paths) { - return createFromAsyncRequest(new RequestCall() { - @Override - public void makeCall(final AsyncCallback callback) { - final AddRequest addRequest = dtoFactory.createDto(AddRequest.class).withUpdate(update); - - if (paths == null) { - addRequest.setFilePattern(AddRequest.DEFAULT_PATTERN); - } else { - - final List patterns = new ArrayList<>(); //need for compatible with server side - for (Path path : paths) { - patterns.add(path.isEmpty() ? "." : path.toString()); - } - - addRequest.setFilePattern(patterns); - } - - final String url = ADD + "?projectPath=" + project.toString(); - final Message message = new MessageBuilder(POST, url).data(dtoFactory.toJson(addRequest)) - .header(CONTENTTYPE, APPLICATION_JSON) - .build(); - - sendMessageToWS(message, new RequestCallback() { - @Override - protected void onSuccess(Void result) { - callback.onSuccess(result); - } - - @Override - protected void onFailure(Throwable exception) { - callback.onFailure(exception); - } - }); - } - }); - } - - @Override - public void commit(DevMachine devMachine, - ProjectConfig project, - String message, - boolean all, - boolean amend, - AsyncRequestCallback callback) { + public Promise commit(Path project, String message, boolean all, boolean amend) { CommitRequest commitRequest = dtoFactory.createDto(CommitRequest.class) .withMessage(message) .withAmend(amend) .withAll(all); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project.getPath(); - - asyncRequestFactory.createPostRequest(url, commitRequest).loader(loader).send(callback); + String url = getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project; + return asyncRequestFactory.createPostRequest(url, commitRequest) + .loader(loader) + .send(dtoUnmarshallerFactory.newUnmarshaller(Revision.class)); } @Override - public Promise commit(DevMachine devMachine, Path project, String message, boolean all, boolean amend) { + public Promise commit(Path project, String message, boolean amend, Path[] files) { CommitRequest commitRequest = dtoFactory.createDto(CommitRequest.class) .withMessage(message) .withAmend(amend) - .withAll(all); - String url = devMachine.getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project; + .withFiles(stream(files).filter(file -> !file.isEmpty()) + .map(Path::toString) + .collect(toList())); + + String url = getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project; return asyncRequestFactory.createPostRequest(url, commitRequest) .loader(loader) @@ -321,166 +182,49 @@ public class GitServiceClientImpl implements GitServiceClient { } @Override - public void commit(final DevMachine devMachine, - final ProjectConfigDto project, - final String message, - final List files, - final boolean amend, - final AsyncRequestCallback callback) { - CommitRequest commitRequest = dtoFactory.createDto(CommitRequest.class) - .withMessage(message) - .withAmend(amend) - .withAll(false) - .withFiles(files); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project.getPath(); - - asyncRequestFactory.createPostRequest(url, commitRequest).loader(loader).send(callback); - } - - @Override - public Promise commit(DevMachine devMachine, Path project, String message, Path[] files, boolean amend) { - return commit(devMachine, project, message, false, files, amend); - } - - @Override - public Promise commit(DevMachine devMachine, Path project, String message, boolean all, Path[] files, boolean amend) { - List paths = new ArrayList<>(files.length); - - for (Path file : files) { - if (!file.isEmpty()) { - paths.add(file.toString()); - } - } - - CommitRequest commitRequest = dtoFactory.createDto(CommitRequest.class) - .withMessage(message) - .withAmend(amend) - .withAll(all) - .withFiles(paths); - String url = devMachine.getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project; - - return asyncRequestFactory.createPostRequest(url, commitRequest) - .loader(loader) - .send(dtoUnmarshallerFactory.newUnmarshaller(Revision.class)); - } - - /** {@inheritDoc} */ - @Override - public void config(DevMachine devMachine, - ProjectConfigDto project, - List requestedConfig, - AsyncRequestCallback> callback) { - String params = "?projectPath=" + project.getPath(); + public Promise> config(Path project, List requestedConfig) { + String params = "?projectPath=" + project; if (requestedConfig != null) { for (String entry : requestedConfig) { params += "&requestedConfig=" + entry; } } - String url = appContext.getDevMachine().getWsAgentBaseUrl() + CONFIG + params; - asyncRequestFactory.createGetRequest(url).loader(loader).send(callback); - } - - @Override - public Promise> config(DevMachine devMachine, Path project, List requestedConfig) { - String params = "?projectPath=" + project.toString(); - if (requestedConfig != null) { - for (String entry : requestedConfig) { - params += "&requestedConfig=" + entry; - } - } - String url = appContext.getDevMachine().getWsAgentBaseUrl() + CONFIG + params; + String url = getWsAgentBaseUrl() + CONFIG + params; return asyncRequestFactory.createGetRequest(url).loader(loader).send(new StringMapUnmarshaller()); } @Override - public void push(DevMachine devMachine, - ProjectConfigDto project, - List refSpec, - String remote, - boolean force, - AsyncRequestCallback callback) { - PushRequest pushRequest = dtoFactory.createDto(PushRequest.class).withRemote(remote).withRefSpec(refSpec).withForce(force); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + PUSH + "?projectPath=" + project.getPath(); - asyncRequestFactory.createPostRequest(url, pushRequest).send(callback); - } - - @Override - public Promise push(DevMachine devMachine, ProjectConfig project, List refSpec, String remote, boolean force) { + public Promise push(Path project, List refSpec, String remote, boolean force) { PushRequest pushRequest = dtoFactory.createDto(PushRequest.class) .withRemote(remote) .withRefSpec(refSpec) .withForce(force); - return asyncRequestFactory.createPostRequest(appContext.getDevMachine().getWsAgentBaseUrl() + PUSH + - "?projectPath=" + project.getPath(), pushRequest) + String url = getWsAgentBaseUrl() + PUSH + "?projectPath=" + project; + return asyncRequestFactory.createPostRequest(url, pushRequest) .send(dtoUnmarshallerFactory.newUnmarshaller(PushResponse.class)); } @Override - public Promise push(DevMachine devMachine, Path project, List refSpec, String remote, boolean force) { - PushRequest pushRequest = dtoFactory.createDto(PushRequest.class) - .withRemote(remote) - .withRefSpec(refSpec) - .withForce(force); - return asyncRequestFactory.createPostRequest(devMachine.getWsAgentBaseUrl() + PUSH + "?projectPath=" + project, pushRequest) - .send(dtoUnmarshallerFactory.newUnmarshaller(PushResponse.class)); - } - - @Override - public void remoteList(DevMachine devMachine, - ProjectConfigDto project, - @Nullable String remoteName, - boolean verbose, - AsyncRequestCallback> callback) { - String params = "?projectPath=" + project.getPath() + (remoteName != null ? "&remoteName=" + remoteName : "") + + public Promise> remoteList(Path project, String remoteName, boolean verbose) { + String params = "?projectPath=" + project + + (remoteName != null ? "&remoteName=" + remoteName : "") + "&verbose=" + String.valueOf(verbose); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOTE + params; - asyncRequestFactory.createGetRequest(url).loader(loader).send(callback); - } - - @Override - public Promise> remoteList(DevMachine devMachine, ProjectConfig project, @Nullable String remoteName, boolean verbose) { - String params = "?projectPath=" + project.getPath() + "&verbose=" + String.valueOf(verbose); - if (remoteName != null) { - params += "&remoteName=" + remoteName; - } - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOTE + params; + String url = getWsAgentBaseUrl() + REMOTE + params; return asyncRequestFactory.createGetRequest(url) .loader(loader) .send(dtoUnmarshallerFactory.newListUnmarshaller(Remote.class)); } @Override - public Promise> remoteList(DevMachine devMachine, Path project, String remoteName, boolean verbose) { - String params = "?projectPath=" + project.toString() + (remoteName != null ? "&remoteName=" + remoteName : "") + - "&verbose=" + String.valueOf(verbose); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOTE + params; - return asyncRequestFactory.createGetRequest(url) - .loader(loader) - .send(dtoUnmarshallerFactory.newListUnmarshaller(Remote.class)); - } - - @Override - @Deprecated - public void branchList(DevMachine devMachine, - ProjectConfig project, - BranchListMode listMode, - AsyncRequestCallback> callback) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project.getPath() + - (listMode == null ? "" : "&listMode=" + listMode); - asyncRequestFactory.createGetRequest(url).send(callback); - } - - @Override - public Promise> branchList(DevMachine devMachine, Path project, BranchListMode listMode) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project.toString() + - (listMode == null ? "" : "&listMode=" + listMode); + public Promise> branchList(Path project, BranchListMode listMode) { + String url = getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project + (listMode == null ? "" : "&listMode=" + listMode); return asyncRequestFactory.createGetRequest(url).send(dtoUnmarshallerFactory.newListUnmarshaller(Branch.class)); } @Override - public Promise getStatus(DevMachine devMachine, Path project) { - final String params = "?projectPath=" + project.toString() + "&format=" + PORCELAIN; - final String url = appContext.getDevMachine().getWsAgentBaseUrl() + STATUS + params; + public Promise getStatus(Path project) { + String params = "?projectPath=" + project + "&format=" + PORCELAIN; + String url = getWsAgentBaseUrl() + STATUS + params; return asyncRequestFactory.createGetRequest(url) .loader(loader) .header(CONTENTTYPE, APPLICATION_JSON) @@ -489,67 +233,24 @@ public class GitServiceClientImpl implements GitServiceClient { } @Override - public void status(DevMachine devMachine, ProjectConfigDto project, AsyncRequestCallback callback) { - String params = "?projectPath=" + project.getPath() + "&format=" + PORCELAIN; - String url = appContext.getDevMachine().getWsAgentBaseUrl() + STATUS + params; - asyncRequestFactory.createGetRequest(url).loader(loader) - .header(CONTENTTYPE, APPLICATION_JSON) - .header(ACCEPT, APPLICATION_JSON) - .send(callback); - } - - @Override - public void branchDelete(DevMachine devMachine, - ProjectConfigDto project, - String name, - boolean force, - AsyncRequestCallback callback) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project.getPath() - + "&name=" + name + "&force=" + force; - asyncRequestFactory.createDeleteRequest(url).loader(loader).send(callback); - } - - @Override - public Promise branchDelete(DevMachine devMachine, Path project, String name, boolean force) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project.toString() - + "&name=" + name + "&force=" + force; + public Promise branchDelete(Path project, String name, boolean force) { + String url = getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project + "&name=" + name + "&force=" + force; return asyncRequestFactory.createDeleteRequest(url).loader(loader).send(); } @Override - public void branchRename(DevMachine devMachine, - ProjectConfigDto project, - String oldName, - String newName, - AsyncRequestCallback callback) { - String params = "?projectPath=" + project.getPath() + "&oldName=" + oldName + "&newName=" + newName; - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + params; - asyncRequestFactory.createPostRequest(url, null).loader(loader) - .header(CONTENTTYPE, MimeType.APPLICATION_FORM_URLENCODED) - .send(callback); - } - - @Override - public Promise branchRename(DevMachine devMachine, Path project, String oldName, String newName) { - String params = "?projectPath=" + project.toString() + "&oldName=" + oldName + "&newName=" + newName; - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + params; + public Promise branchRename(Path project, String oldName, String newName) { + String params = "?projectPath=" + project + "&oldName=" + oldName + "&newName=" + newName; + String url = getWsAgentBaseUrl() + BRANCH + params; return asyncRequestFactory.createPostRequest(url, null).loader(loader) .header(CONTENTTYPE, MimeType.APPLICATION_FORM_URLENCODED) .send(); } @Override - public void branchCreate(DevMachine devMachine, ProjectConfigDto project, String name, String startPoint, - AsyncRequestCallback callback) { + public Promise branchCreate(Path project, String name, String startPoint) { BranchCreateRequest branchCreateRequest = dtoFactory.createDto(BranchCreateRequest.class).withName(name).withStartPoint(startPoint); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project.getPath(); - asyncRequestFactory.createPostRequest(url, branchCreateRequest).loader(loader).header(ACCEPT, APPLICATION_JSON).send(callback); - } - - @Override - public Promise branchCreate(DevMachine devMachine, Path project, String name, String startPoint) { - BranchCreateRequest branchCreateRequest = dtoFactory.createDto(BranchCreateRequest.class).withName(name).withStartPoint(startPoint); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project.toString(); + String url = getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project; return asyncRequestFactory.createPostRequest(url, branchCreateRequest) .loader(loader) .header(ACCEPT, APPLICATION_JSON) @@ -557,121 +258,49 @@ public class GitServiceClientImpl implements GitServiceClient { } @Override - public void checkout(DevMachine devMachine, - ProjectConfig project, - CheckoutRequest checkoutRequest, - AsyncRequestCallback callback) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + CHECKOUT + "?projectPath=" + project.getPath(); - asyncRequestFactory.createPostRequest(url, checkoutRequest).loader(loader).send(callback); + public Promise checkout(Path project, CheckoutRequest request) { + String url = getWsAgentBaseUrl() + CHECKOUT + "?projectPath=" + project; + return asyncRequestFactory.createPostRequest(url, request).loader(loader).send(new StringUnmarshaller()); } @Override - public Promise checkout(DevMachine devMachine, - Path project, - CheckoutRequest request) { - - final String url = devMachine.getWsAgentBaseUrl() + CHECKOUT + "?projectPath=" + project.toString(); - return asyncRequestFactory.createPostRequest(url, request).loader(loader).send(); - } - - @Override - public void remove(DevMachine devMachine, - ProjectConfigDto project, - List items, - boolean cached, - AsyncRequestCallback callback) { - String params = "?projectPath=" + project.getPath(); - if (items != null) { - for (String item : items) { - params += "&items=" + item; - } - } - params += "&cached=" + String.valueOf(cached); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOVE + params; - asyncRequestFactory.createDeleteRequest(url).loader(loader).send(callback); - } - - @Override - public Promise remove(DevMachine devMachine, Path project, Path[] items, boolean cached) { - String params = "?projectPath=" + project.toString(); + public Promise remove(Path project, Path[] items, boolean cached) { + String params = "?projectPath=" + project; if (items != null) { for (Path item : items) { params += "&items=" + item.toString(); } } params += "&cached=" + String.valueOf(cached); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOVE + params; + String url = getWsAgentBaseUrl() + REMOVE + params; return asyncRequestFactory.createDeleteRequest(url).loader(loader).send(); } @Override - public void reset(DevMachine devMachine, - ProjectConfigDto project, - String commit, - @Nullable ResetRequest.ResetType resetType, - @Nullable List filePattern, - AsyncRequestCallback callback) { - ResetRequest resetRequest = dtoFactory.createDto(ResetRequest.class).withCommit(commit); - if (resetType != null) { - resetRequest.setType(resetType); - } - if (filePattern != null) { - resetRequest.setFilePattern(filePattern); - } - String url = appContext.getDevMachine().getWsAgentBaseUrl() + RESET + "?projectPath=" + project.getPath(); - asyncRequestFactory.createPostRequest(url, resetRequest).loader(loader).send(callback); - } - - @Override - public Promise reset(DevMachine devMachine, Path project, String commit, ResetRequest.ResetType resetType, Path[] files) { + public Promise reset(Path project, String commit, ResetRequest.ResetType resetType, Path[] files) { ResetRequest resetRequest = dtoFactory.createDto(ResetRequest.class).withCommit(commit); if (resetType != null) { resetRequest.setType(resetType); } if (files != null) { - List fileList = new ArrayList<>(files.length); - for (Path file : files) { - fileList.add(file.isEmpty() ? "." : file.toString()); - } - resetRequest.setFilePattern(fileList); + resetRequest.setFilePattern(stream(files).map(file -> file.isEmpty() ? "." : file.toString()).collect(toList())); } - String url = devMachine.getWsAgentBaseUrl() + RESET + "?projectPath=" + project; + String url = getWsAgentBaseUrl() + RESET + "?projectPath=" + project; return asyncRequestFactory.createPostRequest(url, resetRequest).loader(loader).send(); } @Override - public void log(DevMachine devMachine, ProjectConfigDto project, List fileFilter, boolean isTextFormat, - @NotNull AsyncRequestCallback callback) { - StringBuilder params = new StringBuilder().append("?projectPath=").append(project.getPath()); + public Promise log(Path project, Path[] fileFilter, int skip, int maxCount, boolean plainText) { + StringBuilder params = new StringBuilder().append("?projectPath=") + .append(project) + .append("&skip=") + .append(skip) + .append("&maxCount=") + .append(maxCount); if (fileFilter != null) { - for (String file : fileFilter) { - params.append("&fileFilter=").append(file); - } + stream(fileFilter).forEach(file -> params.append("&fileFilter=").append(file)); } - String url = appContext.getDevMachine().getWsAgentBaseUrl() + LOG + params; - if (isTextFormat) { - asyncRequestFactory.createGetRequest(url).send(callback); - } else { - asyncRequestFactory.createGetRequest(url).loader(loader).header(ACCEPT, APPLICATION_JSON).send(callback); - } - } - - @Override - public Promise log(DevMachine devMachine, Path project, Path[] fileFilter, boolean plainText) { - return log(devMachine, project, fileFilter, -1, -1, plainText); - } - - @Override - public Promise log(DevMachine devMachine, Path project, Path[] fileFilter, int skip, int maxCount, boolean plainText) { - StringBuilder params = new StringBuilder().append("?projectPath=").append(project.toString()); - if (fileFilter != null) { - for (Path file : fileFilter) { - params.append("&fileFilter=").append(file.toString()); - } - } - params.append("&skip=").append(skip); - params.append("&maxCount=").append(maxCount); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + LOG + params; + String url = getWsAgentBaseUrl() + LOG + params; if (plainText) { return asyncRequestFactory.createGetRequest(url) .send(dtoUnmarshallerFactory.newUnmarshaller(LogResponse.class)); @@ -683,134 +312,67 @@ public class GitServiceClientImpl implements GitServiceClient { } @Override - public void remoteAdd(DevMachine devMachine, - ProjectConfig project, - String name, - String repositoryURL, - AsyncRequestCallback callback) { - RemoteAddRequest remoteAddRequest = dtoFactory.createDto(RemoteAddRequest.class).withName(name).withUrl(repositoryURL); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOTE + "?projectPath=" + project.getPath(); - asyncRequestFactory.createPutRequest(url, remoteAddRequest).loader(loader).send(callback); - } - - @Override - public Promise remoteAdd(DevMachine devMachine, Path project, String name, String url) { + public Promise remoteAdd(Path project, String name, String url) { RemoteAddRequest remoteAddRequest = dtoFactory.createDto(RemoteAddRequest.class).withName(name).withUrl(url); - String requestUrl = appContext.getDevMachine().getWsAgentBaseUrl() + REMOTE + "?projectPath=" + project.toString(); + String requestUrl = getWsAgentBaseUrl() + REMOTE + "?projectPath=" + project; return asyncRequestFactory.createPutRequest(requestUrl, remoteAddRequest).loader(loader).send(); } @Override - public void remoteDelete(DevMachine devMachine, - ProjectConfig project, - String name, - AsyncRequestCallback callback) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOTE + '/' + name + "?projectPath=" + project.getPath(); - asyncRequestFactory.createDeleteRequest(url).loader(loader).send(callback); - } - - @Override - public Promise remoteDelete(DevMachine devMachine, Path project, String name) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REMOTE + '/' + name + "?projectPath=" + project.toString(); + public Promise remoteDelete(Path project, String name) { + String url = getWsAgentBaseUrl() + REMOTE + '/' + name + "?projectPath=" + project; return asyncRequestFactory.createDeleteRequest(url).loader(loader).send(); } @Override - public void fetch(DevMachine devMachine, - ProjectConfigDto project, - String remote, - List refspec, - boolean removeDeletedRefs, - RequestCallback callback) throws WebSocketException { + public Promise fetch(Path project, String remote, List refspec, boolean removeDeletedRefs) { FetchRequest fetchRequest = dtoFactory.createDto(FetchRequest.class) .withRefSpec(refspec) .withRemote(remote) .withRemoveDeletedRefs(removeDeletedRefs); - - String url = FETCH + "?projectPath=" + project.getPath(); - MessageBuilder builder = new MessageBuilder(POST, url); - builder.data(dtoFactory.toJson(fetchRequest)) - .header(CONTENTTYPE, APPLICATION_JSON); - Message message = builder.build(); - - sendMessageToWS(message, callback); - } - - @Override - public Promise fetch(DevMachine devMachine, Path project, String remote, List refspec, boolean removeDeletedRefs) { - FetchRequest fetchRequest = dtoFactory.createDto(FetchRequest.class) - .withRefSpec(refspec) - .withRemote(remote) - .withRemoveDeletedRefs(removeDeletedRefs); - String url = devMachine.getWsAgentBaseUrl() + FETCH + "?projectPath=" + project; + String url = getWsAgentBaseUrl() + FETCH + "?projectPath=" + project; return asyncRequestFactory.createPostRequest(url, fetchRequest).send(); } @Override - public void pull(DevMachine devMachine, - ProjectConfigDto project, - String refSpec, - String remote, - AsyncRequestCallback callback) { + public Promise pull(Path project, String refSpec, String remote) { PullRequest pullRequest = dtoFactory.createDto(PullRequest.class).withRemote(remote).withRefSpec(refSpec); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + PULL + "?projectPath=" + project.getPath(); - asyncRequestFactory.createPostRequest(url, pullRequest).send(callback); - } - - @Override - public Promise pull(DevMachine devMachine, Path project, String refSpec, String remote) { - PullRequest pullRequest = dtoFactory.createDto(PullRequest.class).withRemote(remote).withRefSpec(refSpec); - String url = devMachine.getWsAgentBaseUrl() + PULL + "?projectPath=" + project; + String url = getWsAgentBaseUrl() + PULL + "?projectPath=" + project; return asyncRequestFactory.createPostRequest(url, pullRequest).send(dtoUnmarshallerFactory.newUnmarshaller(PullResponse.class)); } @Override - public void diff(DevMachine devMachine, - ProjectConfigDto project, - List fileFilter, - DiffType type, - boolean noRenames, - int renameLimit, - String commitA, - String commitB, @NotNull AsyncRequestCallback callback) { - diff(Path.valueOf(project.getPath()), fileFilter, type, noRenames, renameLimit, commitA, commitB, false).send(callback); - } - - @Override - public void diff(DevMachine devMachine, - ProjectConfigDto project, - List fileFilter, - DiffType type, - boolean noRenames, - int renameLimit, - String commitA, - boolean cached, - AsyncRequestCallback callback) { - diff(Path.valueOf(project.getPath()), fileFilter, type, noRenames, renameLimit, commitA, null, cached).send(callback); - } - - @Override - public Promise diff(DevMachine devMachine, - Path project, - List fileFilter, + public Promise diff(Path project, List fileFilter, DiffType type, boolean noRenames, int renameLimit, String commitA, String commitB) { - return diff(project, fileFilter, type, noRenames, renameLimit, commitA, commitB, false).send(new StringUnmarshaller()); + return diff(project, + fileFilter, + type, + noRenames, + renameLimit, + commitA, + commitB, + false).send(new StringUnmarshaller()); } @Override - public Promise diff(DevMachine devMachine, - Path project, - List files, + public Promise diff(Path project, List files, DiffType type, boolean noRenames, int renameLimit, String commitA, boolean cached) { - return diff(project, files, type, noRenames, renameLimit, commitA, null, cached).send(new StringUnmarshaller()); + return diff(project, + files, + type, + noRenames, + renameLimit, + commitA, + null, + cached).send(new StringUnmarshaller()); } private AsyncRequest diff(Path project, @@ -821,68 +383,40 @@ public class GitServiceClientImpl implements GitServiceClient { String commitA, String commitB, boolean cached) { - StringBuilder params = new StringBuilder().append("?projectPath=").append(project.toString()); + StringBuilder params = new StringBuilder().append("?projectPath=") + .append(project) + .append("&noRenames=").append(noRenames) + .append("&renameLimit=").append(renameLimit) + .append("&cached=").append(cached); if (fileFilter != null) { - for (String file : fileFilter) { - if (file.isEmpty()) { - continue; - } - params.append("&fileFilter=").append(file); - } + fileFilter.stream().filter(file -> !file.isEmpty()).forEach(file -> params.append("&fileFilter=").append(file)); } if (type != null) { params.append("&diffType=").append(type); } - params.append("&noRenames=").append(noRenames); - params.append("&renameLimit=").append(renameLimit); if (commitA != null) { params.append("&commitA=").append(commitA); } if (commitB != null) { params.append("&commitB=").append(commitB); } - params.append("&cached=").append(cached); - - String url = appContext.getDevMachine().getWsAgentBaseUrl() + DIFF + params; + String url = getWsAgentBaseUrl() + DIFF + params; return asyncRequestFactory.createGetRequest(url).loader(loader); } @Override - public void showFileContent(DevMachine devMachine, - @NotNull ProjectConfigDto project, - String file, - String version, - @NotNull AsyncRequestCallback callback) { - String params = "?projectPath=" + project.getPath() + "&file=" + file + "&version=" + version ; - String url = appContext.getDevMachine().getWsAgentBaseUrl() + SHOW + params; - asyncRequestFactory.createGetRequest(url).loader(loader).send(callback); - } - - @Override - public Promise showFileContent(DevMachine devMachine, Path project, Path file, String version) { - String params = "?projectPath=" + project.toString() + "&file=" + file + "&version=" + version ; - String url = appContext.getDevMachine().getWsAgentBaseUrl() + SHOW + params; + public Promise showFileContent(Path project, Path file, String version) { + String params = "?projectPath=" + project + "&file=" + file + "&version=" + version; + String url = getWsAgentBaseUrl() + SHOW + params; return asyncRequestFactory.createGetRequest(url) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(ShowFileContentResponse.class)); } @Override - public void merge(DevMachine devMachine, - ProjectConfigDto project, - String commit, - AsyncRequestCallback callback) { + public Promise merge(Path project, String commit) { MergeRequest mergeRequest = dtoFactory.createDto(MergeRequest.class).withCommit(commit); - String url = appContext.getDevMachine().getWsAgentBaseUrl() + MERGE + "?projectPath=" + project.getPath(); - asyncRequestFactory.createPostRequest(url, mergeRequest).loader(loader) - .header(ACCEPT, APPLICATION_JSON) - .send(callback); - } - - @Override - public Promise merge(DevMachine devMachine, Path project, String commit) { - MergeRequest mergeRequest = dtoFactory.createDto(MergeRequest.class).withCommit(commit); - String url = devMachine.getWsAgentBaseUrl() + MERGE + "?projectPath=" + project; + String url = getWsAgentBaseUrl() + MERGE + "?projectPath=" + project; return asyncRequestFactory.createPostRequest(url, mergeRequest) .loader(loader) .header(ACCEPT, APPLICATION_JSON) @@ -890,47 +424,12 @@ public class GitServiceClientImpl implements GitServiceClient { } @Override - public void getCommitters(DevMachine devMachine, ProjectConfigDto project, AsyncRequestCallback callback) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + COMMITERS + "?projectPath=" + project.getPath(); - asyncRequestFactory.createGetRequest(url).header(ACCEPT, APPLICATION_JSON).send(callback); + public Promise deleteRepository(Path project) { + String url = getWsAgentBaseUrl() + REPOSITORY + "?projectPath=" + project; + return asyncRequestFactory.createDeleteRequest(url).loader(loader).send(); } - - @Override - public void deleteRepository(DevMachine devMachine, ProjectConfigDto project, AsyncRequestCallback callback) { - String url = appContext.getDevMachine().getWsAgentBaseUrl() + REPOSITORY + "?projectPath=" + project.getPath(); - asyncRequestFactory.createDeleteRequest(url).loader(loader) - .header(ACCEPT, TEXT_PLAIN) - .send(callback); - } - - @Override - public Promise deleteRepository(DevMachine devMachine, final Path project) { - return createFromAsyncRequest(new RequestCall() { - @Override - public void makeCall(final AsyncCallback callback) { - String url = REPOSITORY + "?projectPath=" + project.toString(); - final Message message = new MessageBuilder(DELETE, url).header(ACCEPT, TEXT_PLAIN) - .build(); - - sendMessageToWS(message, new RequestCallback() { - @Override - protected void onSuccess(Void result) { - callback.onSuccess(result); - } - - @Override - protected void onFailure(Throwable exception) { - callback.onFailure(exception); - } - }); - } - }); - } - - @Override - public void getUrlVendorInfo(DevMachine devMachine, @NotNull String vcsUrl, @NotNull AsyncRequestCallback callback) { - asyncRequestFactory.createGetRequest(appContext.getDevMachine().getWsAgentBaseUrl() + "/git-service/info?vcsurl=" + vcsUrl) - .header(HTTPHeader.ACCEPT, MimeType.APPLICATION_JSON).send(callback); + private String getWsAgentBaseUrl() { + return appContext.getDevMachine().getWsAgentBaseUrl(); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/AddToIndexAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/AddToIndexAction.java index 6553ca5a60..8408c6e542 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/AddToIndexAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/AddToIndexAction.java @@ -16,7 +16,6 @@ import com.google.inject.Singleton; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; -import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; @@ -71,10 +70,9 @@ public class AddToIndexAction extends GitAction { public void actionPerformed(ActionEvent e) { final Resource[] resources = appContext.getResources(); checkState(resources != null); - final DevMachine devMachine = appContext.getDevMachine(); final GitOutputConsole console = gitOutputConsoleFactory.create(constant.addToIndexCommandName()); - consolesPanelPresenter.addCommandOutput(devMachine.getId(), console); - service.getStatus(devMachine, appContext.getRootProject().getLocation()) + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + service.getStatus(appContext.getRootProject().getLocation()) .then(status -> { if (containsInSelected(status.getUntracked())) { presenter.showDialog(); @@ -99,7 +97,7 @@ public class AddToIndexAction extends GitAction { Path path = resources[i].getLocation().removeFirstSegments(1); paths[i] = path.segmentCount() == 0 ? Path.EMPTY : path; } - service.add(appContext.getDevMachine(), appContext.getRootProject().getLocation(), false, paths) + service.add(appContext.getRootProject().getLocation(), false, paths) .then(voidArg -> { console.print(constant.addSuccess()); notificationManager.notify(constant.addSuccess()); @@ -111,9 +109,8 @@ public class AddToIndexAction extends GitAction { } private boolean containsInSelected(List items) { - Resource[] appContextResources = appContext.getResources(); for (String item : items) { - for (Resource selectedItem : appContextResources) { + for (Resource selectedItem : appContext.getResources()) { String selectedItemPath = selectedItem.getLocation() .removeFirstSegments(1) // remove project name from path .toString(); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/CompareWithLatestAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/CompareWithLatestAction.java index a018b16334..68ffaf7942 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/CompareWithLatestAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/CompareWithLatestAction.java @@ -10,18 +10,13 @@ *******************************************************************************/ package org.eclipse.che.ide.ext.git.client.action; -import com.google.common.base.Optional; import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.ide.api.git.GitServiceClient; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; @@ -89,44 +84,33 @@ public class CompareWithLatestAction extends GitAction { .removeTrailingSeparator() .toString(); - service.diff(appContext.getDevMachine(), - project.getLocation(), - selectedItemPath.isEmpty() ? null : singletonList(selectedItemPath), - NAME_STATUS, false, 0, REVISION, false) - .then(new Operation() { - @Override - public void apply(String diff) throws OperationException { - if (diff.isEmpty()) { - dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(), - locale.compareMessageIdenticalContentText(), null).show(); - } else { - final String[] changedFiles = diff.split("\n"); - if (changedFiles.length == 1) { - project.getFile(changedFiles[0].substring(2)).then(new Operation>() { - @Override - public void apply(Optional file) throws OperationException { - if (file.isPresent()) { - comparePresenter.showCompareWithLatest(file.get(), - defineStatus(changedFiles[0].substring(0, 1)), - REVISION); - } - } - }); - } else { - Map items = new HashMap<>(); - for (String item : changedFiles) { - items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1))); + service.diff(project.getLocation(), + selectedItemPath.isEmpty() ? null : singletonList(selectedItemPath), NAME_STATUS, false, 0, REVISION, false) + .then(diff -> { + if (diff.isEmpty()) { + dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(), + locale.compareMessageIdenticalContentText(), null).show(); + } else { + final String[] changedFiles = diff.split("\n"); + if (changedFiles.length == 1) { + project.getFile(changedFiles[0].substring(2)).then(file -> { + if (file.isPresent()) { + comparePresenter.showCompareWithLatest(file.get(), + defineStatus(changedFiles[0].substring(0, 1)), + REVISION); } - changesListPresenter.show(items, REVISION, null, project); + }); + } else { + Map items = new HashMap<>(); + for (String item : changedFiles) { + items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1))); } + changesListPresenter.show(items, REVISION, null, project); } } }) - .catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE); - } + .catchError(arg -> { + notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE); }); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/DeleteRepositoryAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/DeleteRepositoryAction.java index cd5979acfe..82fdfe3235 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/DeleteRepositoryAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/DeleteRepositoryAction.java @@ -19,7 +19,6 @@ import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitResources; import org.eclipse.che.ide.ext.git.client.delete.DeleteRepositoryPresenter; -import org.eclipse.che.ide.api.dialogs.ConfirmCallback; import org.eclipse.che.ide.api.dialogs.DialogFactory; import static com.google.common.base.Preconditions.checkState; @@ -52,11 +51,6 @@ public class DeleteRepositoryAction extends GitAction { dialogFactory.createConfirmDialog(constant.deleteGitRepositoryTitle(), constant.deleteGitRepositoryQuestion(project.getName()), - new ConfirmCallback() { - @Override - public void accepted() { - presenter.deleteRepository(project); - } - }, null).show(); + () -> presenter.deleteRepository(project), null).show(); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/InitRepositoryAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/InitRepositoryAction.java index 7530c6ffa2..1b036d558b 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/InitRepositoryAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/InitRepositoryAction.java @@ -20,7 +20,6 @@ import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitResources; import org.eclipse.che.ide.ext.git.client.GitUtil; import org.eclipse.che.ide.ext.git.client.init.InitRepositoryPresenter; -import org.eclipse.che.ide.api.dialogs.ConfirmCallback; import org.eclipse.che.ide.api.dialogs.DialogFactory; import javax.validation.constraints.NotNull; @@ -58,12 +57,7 @@ public class InitRepositoryAction extends GitAction { dialogFactory.createConfirmDialog(constant.createTitle(), constant.messagesInitRepoQuestion(project.getName()), - new ConfirmCallback() { - @Override - public void accepted() { - presenter.initRepository(project); - } - }, null).show(); + () -> presenter.initRepository(project), null).show(); } @Override diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenter.java index eb619fac88..6029a6165d 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenter.java @@ -13,9 +13,6 @@ package org.eclipse.che.ide.ext.git.client.add; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.machine.DevMachine; @@ -85,7 +82,6 @@ public class AddToIndexPresenter implements AddToIndexView.ActionDelegate { view.showDialog(); } - /** {@inheritDoc} */ @Override public void onAddClicked() { DevMachine devMachine = appContext.getDevMachine(); @@ -98,26 +94,19 @@ public class AddToIndexPresenter implements AddToIndexView.ActionDelegate { } final GitOutputConsole console = gitOutputConsoleFactory.create(constant.addToIndexCommandName()); consolesPanelPresenter.addCommandOutput(devMachine.getId(), console); - service.add(devMachine, projectLocation, view.isUpdated(), paths) - .then(new Operation() { - @Override - public void apply(Void arg) throws OperationException { - console.print(constant.addSuccess()); - notificationManager.notify(constant.addSuccess()); - view.close(); - } + service.add(projectLocation, view.isUpdated(), paths) + .then(arg -> { + console.print(constant.addSuccess()); + notificationManager.notify(constant.addSuccess()); + view.close(); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - console.printError(constant.addFailed()); - notificationManager.notify(constant.addFailed(), FAIL, FLOAT_MODE); - view.close(); - } + .catchError(arg -> { + console.printError(constant.addFailed()); + notificationManager.notify(constant.addFailed(), FAIL, FLOAT_MODE); + view.close(); }); } - /** {@inheritDoc} */ @Override public void onCancelClicked() { view.close(); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java index 344de4fbde..8a01cec59c 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java @@ -16,13 +16,8 @@ import com.google.inject.Singleton; import org.eclipse.che.api.core.ErrorCodes; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.CheckoutRequest; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.dialogs.ConfirmCallback; import org.eclipse.che.ide.api.dialogs.DialogFactory; -import org.eclipse.che.ide.api.dialogs.InputCallback; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Project; @@ -33,7 +28,6 @@ import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory; import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; import javax.validation.constraints.NotNull; -import java.util.List; import static org.eclipse.che.api.git.shared.BranchListMode.LIST_ALL; import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; @@ -48,11 +42,12 @@ import static org.eclipse.che.ide.util.ExceptionUtils.getErrorCode; */ @Singleton public class BranchPresenter implements BranchView.ActionDelegate { - public static final String BRANCH_RENAME_COMMAND_NAME = "Git rename branch"; - public static final String BRANCH_DELETE_COMMAND_NAME = "Git delete branch"; - public static final String BRANCH_CHECKOUT_COMMAND_NAME = "Git checkout branch"; - public static final String BRANCH_CREATE_COMMAND_NAME = "Git create branch"; - public static final String BRANCH_LIST_COMMAND_NAME = "Git list of branches"; + + private static final String BRANCH_RENAME_COMMAND_NAME = "Git rename branch"; + private static final String BRANCH_DELETE_COMMAND_NAME = "Git delete branch"; + private static final String BRANCH_CHECKOUT_COMMAND_NAME = "Git checkout branch"; + private static final String BRANCH_CREATE_COMMAND_NAME = "Git create branch"; + private static final String BRANCH_LIST_COMMAND_NAME = "Git list of branches"; private final DtoFactory dtoFactory; private final BranchView view; @@ -96,24 +91,17 @@ public class BranchPresenter implements BranchView.ActionDelegate { getBranches(); } - /** {@inheritDoc} */ @Override public void onCloseClicked() { view.close(); } - /** {@inheritDoc} */ @Override public void onRenameClicked() { if (selectedBranch.isRemote()) { dialogFactory.createConfirmDialog(constant.branchConfirmRenameTitle(), constant.branchConfirmRenameMessage(), - new ConfirmCallback() { - @Override - public void accepted() { - renameBranch(); - } - }, + this::renameBranch, null).show(); } else { renameBranch(); @@ -127,29 +115,18 @@ public class BranchPresenter implements BranchView.ActionDelegate { selectedBranchName, 0, selectedBranchName.length(), - new InputCallback() { - @Override - public void accepted(String newBranchName) { - renameBranch(newBranchName); - } - }, + this::renameBranch, null).show(); } private void renameBranch(String newName) { - service.branchRename(appContext.getDevMachine(), project.getLocation(), selectedBranch.getDisplayName(), newName) - .then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - getBranches(); - } + service.branchRename(project.getLocation(), selectedBranch.getDisplayName(), newName) + .then(ignored -> { + getBranches(); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), BRANCH_RENAME_COMMAND_NAME); - getBranches();//rename of remote branch occurs in three stages, so needs update list of branches on view - } + .catchError(error -> { + handleError(error.getCause(), BRANCH_RENAME_COMMAND_NAME); + getBranches();//rename of remote branch occurs in three stages, so needs update list of branches on view }); } @@ -160,24 +137,18 @@ public class BranchPresenter implements BranchView.ActionDelegate { return tokens.length > 0 ? tokens[tokens.length - 1] : selectedBranchName; } - /** {@inheritDoc} */ @Override public void onDeleteClicked() { - service.branchDelete(appContext.getDevMachine(), project.getLocation(), selectedBranch.getName(), true).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - getBranches(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), BRANCH_DELETE_COMMAND_NAME); - } - }); + service.branchDelete(project.getLocation(), selectedBranch.getName(), true) + .then(ignored -> { + getBranches(); + }) + .catchError(error -> { + handleError(error.getCause(), BRANCH_DELETE_COMMAND_NAME); + }); } - /** {@inheritDoc} */ @Override public void onCheckoutClicked() { final CheckoutRequest checkoutRequest = dtoFactory.createDto(CheckoutRequest.class); @@ -187,65 +158,48 @@ public class BranchPresenter implements BranchView.ActionDelegate { checkoutRequest.setName(selectedBranch.getDisplayName()); } - service.checkout(appContext.getDevMachine(), project.getLocation(), checkoutRequest).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - getBranches(); - - project.synchronize(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), BRANCH_CHECKOUT_COMMAND_NAME); - } - }); + service.checkout(project.getLocation(), checkoutRequest) + .then(ignored -> { + getBranches(); + project.synchronize(); + }) + .catchError(error -> { + handleError(error.getCause(), BRANCH_CHECKOUT_COMMAND_NAME); + }); } /** Get the list of branches. */ private void getBranches() { - service.branchList(appContext.getDevMachine(), project.getLocation(), LIST_ALL).then(new Operation>() { - @Override - public void apply(List branches) throws OperationException { - if (branches.isEmpty()) { - dialogFactory.createMessageDialog(constant.branchTitle(), - constant.initCommitWasNotPerformed(), - null).show(); - } else { - view.setBranches(branches); - view.showDialogIfClosed(); - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME); - } - }); + service.branchList(project.getLocation(), LIST_ALL) + .then(branches -> { + if (branches.isEmpty()) { + dialogFactory.createMessageDialog(constant.branchTitle(), + constant.initCommitWasNotPerformed(), + null).show(); + } else { + view.setBranches(branches); + view.showDialogIfClosed(); + } + }) + .catchError(error -> { + handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME); + }); } - /** {@inheritDoc} */ @Override public void onCreateClicked() { - dialogFactory.createInputDialog(constant.branchCreateNew(), constant.branchTypeNew(), new InputCallback() { - @Override - public void accepted(String value) { - if (value.isEmpty()) { - return; - } - - service.branchCreate(appContext.getDevMachine(), project.getLocation(), value, null).then(new Operation() { - @Override - public void apply(Branch branch) throws OperationException { - getBranches(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), BRANCH_CREATE_COMMAND_NAME); - } - }); + dialogFactory.createInputDialog(constant.branchCreateNew(), constant.branchTypeNew(), value -> { + if (value.isEmpty()) { + return; } + + service.branchCreate(project.getLocation(), value, null) + .then(branch -> { + getBranches(); + }) + .catchError(error -> { + handleError(error.getCause(), BRANCH_CREATE_COMMAND_NAME); + }); }, null).show(); } @@ -258,7 +212,6 @@ public class BranchPresenter implements BranchView.ActionDelegate { view.setEnableDeleteButton(false); } - /** {@inheritDoc} */ @Override public void onBranchSelected(@NotNull Branch branch) { selectedBranch = branch; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferencePresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferencePresenter.java index df03713173..9c18b3a0ec 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferencePresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferencePresenter.java @@ -14,14 +14,10 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.git.shared.CheckoutRequest; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Project; -import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole; @@ -87,30 +83,22 @@ public class CheckoutReferencePresenter implements CheckoutReferenceView.ActionD @Override public void onCheckoutClicked(final String reference) { - service.checkout(appContext.getDevMachine(), project.getLocation(), dtoFactory.createDto(CheckoutRequest.class).withName(reference)) - .then(new Operation() { - @Override - public void apply(Void arg) throws OperationException { - project.synchronize().then(new Operation() { - @Override - public void apply(Resource[] arg) throws OperationException { - view.close(); - } - }); - } + service.checkout(project.getLocation(), dtoFactory.createDto(CheckoutRequest.class).withName(reference)) + .then(branchName -> { + appContext.getRootProject().synchronize() + .then(arg -> { + view.close(); + }); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - final String errorMessage = (error.getMessage() != null) - ? error.getMessage() - : constant.checkoutFailed(); - GitOutputConsole console = gitOutputConsoleFactory.create(CHECKOUT_COMMAND_NAME); - console.printError(errorMessage); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.checkoutFailed(), FAIL, FLOAT_MODE); - view.close(); - } + .catchError(error -> { + final String errorMessage = (error.getMessage() != null) + ? error.getMessage() + : constant.checkoutFailed(); + GitOutputConsole console = gitOutputConsoleFactory.create(CHECKOUT_COMMAND_NAME); + console.printError(errorMessage); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.checkoutFailed(), FAIL, FLOAT_MODE); + view.close(); }); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java index 52f9bf637b..419a02c24c 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java @@ -19,7 +19,6 @@ import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.git.GitServiceClient; -import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.commons.exception.ServerException; @@ -115,9 +114,9 @@ public class CommitPresenter implements CommitView.ActionDelegate { view.setEnableAmendCheckBox(true); view.setEnablePushAfterCommitCheckBox(true); view.setEnableRemoteBranchesDropDownLis(false); - service.diff(appContext.getDevMachine(), project.getLocation(), null, NAME_STATUS, true, 0, "HEAD", false) + service.diff(project.getLocation(), null, NAME_STATUS, true, 0, "HEAD", false) .then(diff -> { - service.log(appContext.getDevMachine(), project.getLocation(), null, -1, 1, false) + service.log(project.getLocation(), null, -1, 1, false) .then(arg -> { if (diff.isEmpty()) { showAskForAmendDialog(); @@ -127,7 +126,7 @@ public class CommitPresenter implements CommitView.ActionDelegate { }) .catchError(error -> { if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { - service.getStatus(appContext.getDevMachine(), project.getLocation()).then( + service.getStatus(project.getLocation()).then( status -> { view.setEnableAmendCheckBox(false); view.setEnablePushAfterCommitCheckBox(false); @@ -143,7 +142,7 @@ public class CommitPresenter implements CommitView.ActionDelegate { notificationManager.notify(constant.diffFailed(), FAIL, FLOAT_MODE); }); - service.branchList(appContext.getDevMachine(), project.getLocation(), LIST_REMOTE) + service.branchList(project.getLocation(), LIST_REMOTE) .then(view::setRemoteBranchesList) .catchError(error -> { notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); @@ -188,22 +187,19 @@ public class CommitPresenter implements CommitView.ActionDelegate { @Override public void onCommitClicked() { - DevMachine devMachine = appContext.getDevMachine(); Path location = project.getLocation(); Path[] filesToCommitArray = getFilesToCommitArray(); - service.add(devMachine, location, false, filesToCommitArray) + service.add(location, false, filesToCommitArray) .then(arg -> { - service.commit(devMachine, - location, + service.commit(location, view.getMessage(), - false, - filesToCommitArray, - view.isAmend()) + view.isAmend(), + filesToCommitArray) .then(revision -> { onCommitSuccess(revision); if (view.isPushAfterCommit()) { - push(devMachine, location); + push(location); } view.close(); }) @@ -223,12 +219,11 @@ public class CommitPresenter implements CommitView.ActionDelegate { return filesToCommitArray; } - private void push(DevMachine devMachine, Path location) { + private void push(Path location) { String remoteBranch = view.getRemoteBranch(); String remote = remoteBranch.split("/")[0]; String branch = remoteBranch.split("/")[1]; - service.push(devMachine, - location, + service.push(location, singletonList(branch), remote, false) @@ -252,7 +247,7 @@ public class CommitPresenter implements CommitView.ActionDelegate { @Override public void setAmendCommitMessage() { - service.log(appContext.getDevMachine(), project.getLocation(), null, -1, -1, false) + service.log(project.getLocation(), null, -1, -1, false) .then(log -> { String message = ""; final Revision revision = getFirst(log.getCommits(), null); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/ComparePresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/ComparePresenter.java index 9fde283546..fc610e8fad 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/ComparePresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/ComparePresenter.java @@ -18,12 +18,7 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.event.FileContentUpdateEvent; import org.eclipse.che.ide.api.git.GitServiceClient; -import org.eclipse.che.api.git.shared.ShowFileContentResponse; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; -import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.File; @@ -109,40 +104,27 @@ public class ComparePresenter implements CompareView.ActionDelegate { final Path relPath = file.getLocation().removeFirstSegments(project.get().getLocation().segmentCount()); if (status.equals(DELETED)) { - service.showFileContent(appContext.getDevMachine(), project.get().getLocation(), relPath, revision) - .then(new Operation() { - @Override - public void apply(ShowFileContentResponse content) throws OperationException { - view.setTitle(file.getLocation().toString()); - view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle()); - view.show(content.getContent(), "", file.getLocation().toString(), false); - } + service.showFileContent(project.get().getLocation(), relPath, revision) + .then(content -> { + view.setTitle(file.getLocation().toString()); + view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle()); + view.show(content.getContent(), "", file.getLocation().toString(), false); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); - } + .catchError(error -> { + notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); }); } else { - service.showFileContent(appContext.getDevMachine(), project.get().getLocation(), relPath, revision) - .then(new Operation() { - @Override - public void apply(ShowFileContentResponse content) throws OperationException { - showCompare(content.getContent()); - } + service.showFileContent(project.get().getLocation(), relPath, revision) + .then(content -> { + showCompare(content.getContent()); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); - } + .catchError(error -> { + notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); }); } } /** - * * @param file * path of the file * @param status @@ -160,62 +142,40 @@ public class ComparePresenter implements CompareView.ActionDelegate { @Nullable final String revisionB) { this.compareWithLatest = false; - final DevMachine devMachine = appContext.getDevMachine(); final Path projectLocation = appContext.getRootProject().getLocation(); view.setTitle(file.toString()); if (status == Status.ADDED) { - service.showFileContent(devMachine, projectLocation, file, revisionB) - .then(new Operation() { - @Override - public void apply(ShowFileContentResponse response) throws OperationException { - view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), - revisionA == null ? "" : revisionA + locale.compareReadOnlyTitle()); - view.show("", response.getContent(), file.toString(), true); - } + service.showFileContent(projectLocation, file, revisionB) + .then(response -> { + view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), + revisionA == null ? "" : revisionA + locale.compareReadOnlyTitle()); + view.show("", response.getContent(), file.toString(), true); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); - } + .catchError(error -> { + notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); }); } else if (status == Status.DELETED) { - service.showFileContent(devMachine, projectLocation, file, revisionA) - .then(new Operation() { - @Override - public void apply(ShowFileContentResponse response) throws OperationException { - view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), revisionA + locale.compareReadOnlyTitle()); - view.show(response.getContent(), "", file.toString(), true); - } + service.showFileContent(projectLocation, file, revisionA) + .then(response -> { + view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), revisionA + locale.compareReadOnlyTitle()); + view.show(response.getContent(), "", file.toString(), true); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); - } + .catchError(error -> { + notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); }); } else { - service.showFileContent(devMachine, projectLocation, file, revisionA) - .then(new Operation() { - @Override - public void apply(final ShowFileContentResponse contentAResponse) throws OperationException { - service.showFileContent(devMachine, projectLocation, file, revisionB) - .then(new Operation() { - @Override - public void apply(ShowFileContentResponse contentBResponse) throws OperationException { - view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), - revisionA + locale.compareReadOnlyTitle()); - view.show(contentAResponse.getContent(), contentBResponse.getContent(), file.toString(), true); - } - }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); - } - }); - } + service.showFileContent(projectLocation, file, revisionA) + .then(contentAResponse -> { + service.showFileContent(projectLocation, file, revisionB) + .then(contentBResponse -> { + view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), + revisionA + locale.compareReadOnlyTitle()); + view.show(contentAResponse.getContent(), contentBResponse.getContent(), file.toString(), true); + }) + .catchError(error -> { + notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE); + }); }); } } @@ -227,46 +187,32 @@ public class ComparePresenter implements CompareView.ActionDelegate { return; } - ConfirmCallback confirmCallback = new ConfirmCallback() { - @Override - public void accepted() { - comparedFile.updateContent(newContent).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - final Container parent = comparedFile.getParent(); + ConfirmCallback confirmCallback = () -> comparedFile.updateContent(newContent) + .then(ignored -> { + final Container parent = comparedFile.getParent(); - if (parent != null) { - parent.synchronize(); - } + if (parent != null) { + parent.synchronize(); + } - eventBus.fireEvent(new FileContentUpdateEvent(comparedFile.getLocation().toString())); - view.hide(); - } - }); - } - }; + eventBus.fireEvent(new FileContentUpdateEvent(comparedFile.getLocation() + .toString())); + view.hide(); + }); - CancelCallback cancelCallback = new CancelCallback() { - @Override - public void cancelled() { - view.hide(); - } - }; + CancelCallback cancelCallback = view::hide; dialogFactory.createConfirmDialog(locale.compareSaveTitle(), locale.compareSaveQuestion(), locale.buttonYes(), locale.buttonNo(), confirmCallback, cancelCallback).show(); } private void showCompare(final String remoteContent) { - comparedFile.getContent().then(new Operation() { - @Override - public void apply(String local) throws OperationException { - localContent = local; - final String path = comparedFile.getLocation().removeFirstSegments(1).toString(); - view.setTitle(path); - view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle()); - view.show(remoteContent, localContent, path, false); - } + comparedFile.getContent().then(local -> { + localContent = local; + final String path = comparedFile.getLocation().removeFirstSegments(1).toString(); + view.setTitle(path); + view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle()); + view.show(remoteContent, localContent, path, false); }); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java index 90e983e046..f61ab503fb 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java @@ -10,19 +10,14 @@ *******************************************************************************/ package org.eclipse.che.ide.ext.git.client.compare.branchlist; -import com.google.common.base.Optional; import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.git.shared.Branch; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; @@ -35,7 +30,6 @@ import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; import javax.validation.constraints.NotNull; import java.util.HashMap; -import java.util.List; import java.util.Map; import static com.google.common.base.Preconditions.checkState; @@ -105,13 +99,11 @@ public class BranchListPresenter implements BranchListView.ActionDelegate { getBranches(); } - /** {@inheritDoc} */ @Override public void onCloseClicked() { view.close(); } - /** {@inheritDoc} */ @Override public void onCompareClicked() { @@ -120,61 +112,49 @@ public class BranchListPresenter implements BranchListView.ActionDelegate { .removeTrailingSeparator() .toString(); - service.diff(appContext.getDevMachine(), - project.getLocation(), + service.diff(project.getLocation(), selectedItemPath.isEmpty() ? null : singletonList(selectedItemPath), NAME_STATUS, false, 0, selectedBranch.getName(), false) - .then(new Operation() { - @Override - public void apply(String diff) throws OperationException { - if (diff.isEmpty()) { - dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(), - locale.compareMessageIdenticalContentText(), null).show(); - } else { - final String[] changedFiles = diff.split("\n"); - if (changedFiles.length == 1) { - project.getFile(changedFiles[0].substring(2)).then(new Operation>() { - @Override - public void apply(Optional file) throws OperationException { - if (file.isPresent()) { - comparePresenter.showCompareWithLatest(file.get(), - defineStatus(changedFiles[0].substring(0, 1)), - selectedBranch.getName()); - } - } - }); - } else { - Map items = new HashMap<>(); - for (String item : changedFiles) { - items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1))); + .then(diff -> { + if (diff.isEmpty()) { + dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(), + locale.compareMessageIdenticalContentText(), null).show(); + } else { + final String[] changedFiles = diff.split("\n"); + if (changedFiles.length == 1) { + project.getFile(changedFiles[0].substring(2)).then(file -> { + if (file.isPresent()) { + comparePresenter.showCompareWithLatest(file.get(), + defineStatus(changedFiles[0].substring(0, 1)), + selectedBranch.getName()); } - changesListPresenter.show(items, selectedBranch.getName(), null, project); + }); + } else { + Map items = new HashMap<>(); + for (String item : changedFiles) { + items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1))); } + changesListPresenter.show(items, selectedBranch.getName(), null, project); } } }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE); - } + .catchError(error -> { + notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE); }); view.close(); } - /** {@inheritDoc} */ @Override public void onBranchUnselected() { selectedBranch = null; view.setEnableCompareButton(false); } - /** {@inheritDoc} */ @Override public void onBranchSelected(@NotNull Branch branch) { selectedBranch = branch; @@ -184,21 +164,17 @@ public class BranchListPresenter implements BranchListView.ActionDelegate { /** Get list of branches from selected project. */ private void getBranches() { - service.branchList(appContext.getDevMachine(), project.getLocation(), LIST_ALL).then(new Operation>() { - @Override - public void apply(List branches) throws OperationException { - view.setBranches(branches); - view.showDialog(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - final String errorMessage = (error.getMessage() != null) ? error.getMessage() : locale.branchesListFailed(); - GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME); - console.printError(errorMessage); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(locale.branchesListFailed(), FAIL, NOT_EMERGE_MODE); - } - }); + service.branchList(project.getLocation(), LIST_ALL) + .then(branches -> { + view.setBranches(branches); + view.showDialog(); + }) + .catchError(error -> { + final String errorMessage = (error.getMessage() != null) ? error.getMessage() : locale.branchesListFailed(); + GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME); + console.printError(errorMessage); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(locale.branchesListFailed(), FAIL, NOT_EMERGE_MODE); + }); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionslist/RevisionListPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionslist/RevisionListPresenter.java index 9e89f4161f..5a332ac6a2 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionslist/RevisionListPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionslist/RevisionListPresenter.java @@ -10,18 +10,13 @@ *******************************************************************************/ package org.eclipse.che.ide.ext.git.client.compare.revisionslist; -import com.google.common.base.Optional; import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.core.ErrorCodes; import org.eclipse.che.ide.api.git.GitServiceClient; -import org.eclipse.che.api.git.shared.LogResponse; import org.eclipse.che.api.git.shared.Revision; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.api.resources.Project; @@ -127,60 +122,45 @@ public class RevisionListPresenter implements RevisionListView.ActionDelegate { /** Get list of revisions. */ private void getRevisions() { - service.log(appContext.getDevMachine(), project.getLocation(), new Path[]{selectedFilePath}, false) - .then(new Operation() { - @Override - public void apply(LogResponse log) throws OperationException { - view.setRevisions(log.getCommits()); - view.showDialog(); + service.log(project.getLocation(), new Path[]{selectedFilePath}, -1, -1, false) + .then(log -> { + view.setRevisions(log.getCommits()); + view.showDialog(); + }).catchError(error -> { + if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { + dialogFactory.createMessageDialog(locale.compareWithRevisionTitle(), + locale.initCommitWasNotPerformed(), + null).show(); + } else { + notificationManager.notify(locale.logFailed(), FAIL, NOT_EMERGE_MODE); } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { - dialogFactory.createMessageDialog(locale.compareWithRevisionTitle(), - locale.initCommitWasNotPerformed(), - null).show(); - } else { - notificationManager.notify(locale.logFailed(), FAIL, NOT_EMERGE_MODE); - } - } - }); + }); } private void compare() { - service.diff(appContext.getDevMachine(), - project.getLocation(), + service.diff(project.getLocation(), singletonList(selectedFilePath.toString()), NAME_STATUS, false, 0, selectedRevision.getId(), false) - .then(new Operation() { - @Override - public void apply(final String diff) throws OperationException { - if (diff.isEmpty()) { - dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(), - locale.compareMessageIdenticalContentText(), null).show(); - } else { - project.getFile(diff.substring(2)).then(new Operation>() { - @Override - public void apply(Optional file) throws OperationException { - if (file.isPresent()) { - comparePresenter.showCompareWithLatest(file.get(), defineStatus(diff.substring(0, 1)), selectedRevision.getId()); - } - } - }); + .then(diff -> { + if (diff.isEmpty()) { + dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(), + locale.compareMessageIdenticalContentText(), null).show(); + } else { + appContext.getRootProject().getFile(diff.substring(2)).then(file -> { + if (file.isPresent()) { + comparePresenter.showCompareWithLatest(file.get(), defineStatus(diff.substring(0, 1)), + selectedRevision.getId()); + } + }); - } } }) - .catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE); - } + .catchError(arg -> { + notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE); }); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/delete/DeleteRepositoryPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/delete/DeleteRepositoryPresenter.java index 957d5b561d..f88d13dae6 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/delete/DeleteRepositoryPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/delete/DeleteRepositoryPresenter.java @@ -13,9 +13,6 @@ package org.eclipse.che.ide.ext.git.client.delete; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; @@ -36,7 +33,7 @@ import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAI */ @Singleton public class DeleteRepositoryPresenter { - public static final String DELETE_REPO_COMMAND_NAME = "Git delete repository"; + private static final String DELETE_REPO_COMMAND_NAME = "Git delete repository"; private final GitServiceClient service; private final GitLocalizationConstant constant; @@ -61,25 +58,19 @@ public class DeleteRepositoryPresenter { } /** Delete Git repository. */ - public void deleteRepository(final Project project) { + public void deleteRepository(Project project) { final GitOutputConsole console = gitOutputConsoleFactory.create(DELETE_REPO_COMMAND_NAME); - service.deleteRepository(appContext.getDevMachine(), project.getLocation()).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - console.print(constant.deleteGitRepositorySuccess()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.deleteGitRepositorySuccess()); + service.deleteRepository(project.getLocation()).then(ignored -> { + console.print(constant.deleteGitRepositorySuccess()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.deleteGitRepositorySuccess()); - project.synchronize(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - console.printError(error.getMessage()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.failedToDeleteRepository(), FAIL, FLOAT_MODE); - } + appContext.getRootProject().synchronize(); + }).catchError(error -> { + console.printError(error.getMessage()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.failedToDeleteRepository(), FAIL, FLOAT_MODE); }); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java index 27bc7c5467..ea1b278752 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java @@ -16,10 +16,6 @@ import com.google.inject.Singleton; import org.eclipse.che.api.core.rest.shared.dto.ServiceError; import org.eclipse.che.api.git.shared.BranchListMode; import org.eclipse.che.api.git.shared.Branch; -import org.eclipse.che.api.git.shared.Remote; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; @@ -101,24 +97,20 @@ public class FetchPresenter implements FetchView.ActionDelegate { * local). */ private void updateRemotes() { - service.remoteList(appContext.getDevMachine(), project.getLocation(), null, true).then(new Operation>() { - @Override - public void apply(List remotes) throws OperationException { - view.setRepositories(remotes); - updateBranches(LIST_REMOTE); - view.setEnableFetchButton(!remotes.isEmpty()); - view.showDialog(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); - console.printError(constant.remoteListFailed()); - processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE); - view.setEnableFetchButton(false); - } - }); + service.remoteList(project.getLocation(), null, true) + .then(remotes -> { + view.setRepositories(remotes); + updateBranches(LIST_REMOTE); + view.setEnableFetchButton(!remotes.isEmpty()); + view.showDialog(); + }) + .catchError(error -> { + GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); + console.printError(constant.remoteListFailed()); + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE); + view.setEnableFetchButton(false); + }); } /** @@ -128,33 +120,29 @@ public class FetchPresenter implements FetchView.ActionDelegate { * is a remote mode */ private void updateBranches(@NotNull final BranchListMode remoteMode) { - service.branchList(appContext.getDevMachine(), project.getLocation(), remoteMode).then(new Operation>() { - @Override - public void apply(List branches) throws OperationException { - if (LIST_REMOTE.equals(remoteMode)) { - view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches)); - updateBranches(LIST_LOCAL); - } else { - view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches)); - for (Branch branch : branches) { - if (branch.isActive()) { - view.selectRemoteBranch(branch.getDisplayName()); - break; - } - } - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - final String errorMessage = error.getMessage() != null ? error.getMessage() : constant.branchesListFailed(); - GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); - console.printError(errorMessage); - processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); - view.setEnableFetchButton(false); - } - }); + service.branchList(project.getLocation(), remoteMode) + .then(branches -> { + if (LIST_REMOTE.equals(remoteMode)) { + view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches)); + updateBranches(LIST_LOCAL); + } else { + view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches)); + for (Branch branch : branches) { + if (branch.isActive()) { + view.selectRemoteBranch(branch.getDisplayName()); + break; + } + } + } + }) + .catchError(error -> { + final String errorMessage = error.getMessage() != null ? error.getMessage() : constant.branchesListFailed(); + GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); + console.printError(errorMessage); + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); + view.setEnableFetchButton(false); + }); } /** {@inheritDoc} */ @@ -165,23 +153,17 @@ public class FetchPresenter implements FetchView.ActionDelegate { final StatusNotification notification = notificationManager.notify(constant.fetchProcess(), PROGRESS, FLOAT_MODE); final GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); - service.fetch(appContext.getDevMachine(), project.getLocation(), view.getRepositoryName(), getRefs(), view.isRemoveDeletedRefs()) - .then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - console.print(constant.fetchSuccess(remoteUrl)); - processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notification.setStatus(SUCCESS); - notification.setTitle(constant.fetchSuccess(remoteUrl)); - } - }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), remoteUrl, notification, console); - processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - } - }); + service.fetch(project.getLocation(), view.getRepositoryName(), getRefs(), view.isRemoveDeletedRefs()) + .then(ignored -> { + console.print(constant.fetchSuccess(remoteUrl)); + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notification.setStatus(SUCCESS); + notification.setTitle(constant.fetchSuccess(remoteUrl)); + }) + .catchError(error -> { + handleError(error.getCause(), remoteUrl, notification, console); + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + }); view.close(); } @@ -231,13 +213,11 @@ public class FetchPresenter implements FetchView.ActionDelegate { } } - /** {@inheritDoc} */ @Override public void onCancelClicked() { view.close(); } - /** {@inheritDoc} */ @Override public void onValueChanged() { boolean isFetchAll = view.isFetchAllBranches(); @@ -245,13 +225,11 @@ public class FetchPresenter implements FetchView.ActionDelegate { view.setEnableRemoteBranchField(!isFetchAll); } - /** {@inheritDoc} */ @Override public void onRemoteBranchChanged() { view.selectLocalBranch(view.getRemoteBranch()); } - /** {@inheritDoc} */ @Override public void onRemoteRepositoryChanged() { updateBranches(LIST_REMOTE); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenter.java index 557b07cf6c..d6b26de080 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenter.java @@ -14,11 +14,7 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.core.ErrorCodes; -import org.eclipse.che.api.git.shared.LogResponse; import org.eclipse.che.api.git.shared.Revision; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.git.GitServiceClient; @@ -136,34 +132,26 @@ public class HistoryPresenter implements HistoryView.ActionDelegate { } private void fetchRevisions() { - service.log(appContext.getDevMachine(), - project.getLocation(), - selectedPath.isEmpty() ? null : new Path[]{selectedPath}, + service.log(project.getLocation(), selectedPath.isEmpty() ? null : new Path[]{selectedPath}, skip, DEFAULT_PAGE_SIZE, false) - .then(new Operation() { - @Override - public void apply(LogResponse log) throws OperationException { - List commits = log.getCommits(); - if (!commits.isEmpty()) { - skip += commits.size(); - revisions.addAll(commits); - view.setRevisions(revisions); - view.showDialog(); - } + .then(log -> { + List commits = log.getCommits(); + if (!commits.isEmpty()) { + skip += commits.size(); + revisions.addAll(commits); + view.setRevisions(revisions); + view.showDialog(); } }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { - dialogFactory.createMessageDialog(locale.historyTitle(), - locale.initCommitWasNotPerformed(), - null).show(); - } else { - notificationManager.notify(locale.logFailed(), FAIL, EMERGE_MODE); - } + .catchError(error -> { + if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { + dialogFactory.createMessageDialog(locale.historyTitle(), + locale.initCommitWasNotPerformed(), + null).show(); + } else { + notificationManager.notify(locale.logFailed(), FAIL, EMERGE_MODE); } }); } @@ -172,40 +160,33 @@ public class HistoryPresenter implements HistoryView.ActionDelegate { final String revisionA = revisions.indexOf(selectedRevision) + 1 == revisions.size() ? null : revisions.get(revisions.indexOf(selectedRevision) + 1).getId(); final String revisionB = selectedRevision.getId(); - service.diff(appContext.getDevMachine(), project.getLocation(), - singletonList(selectedPath.toString()), + service.diff(project.getLocation(), singletonList(selectedPath.toString()), NAME_STATUS, true, 0, revisionA, revisionB) - .then(new Operation() { - @Override - public void apply(final String diff) throws OperationException { - if (diff.isEmpty()) { - dialogFactory.createMessageDialog(locale.historyTitle(), locale.historyNothingToDisplay(), null).show(); - return; - } - final String[] changedFiles = diff.split("\n"); - if (changedFiles.length == 1) { - comparePresenter.showCompareBetweenRevisions(Path.valueOf(diff.substring(2)), - defineStatus(diff.substring(0, 1)), - revisionA, - revisionB); - } else { - Map items = new HashMap<>(); - for (String item : changedFiles) { - items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1))); - } - changesListPresenter.show(items, revisionA, revisionB, project); + .then(diff -> { + if (diff.isEmpty()) { + dialogFactory.createMessageDialog(locale.historyTitle(), locale.historyNothingToDisplay(), null).show(); + return; + } + final String[] changedFiles = diff.split("\n"); + if (changedFiles.length == 1) { + comparePresenter.showCompareBetweenRevisions(Path.valueOf(diff.substring(2)), + defineStatus(diff.substring(0, 1)), + revisionA, + revisionB); + } else { + Map items = new HashMap<>(); + for (String item : changedFiles) { + items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1))); } + changesListPresenter.show(items, revisionA, revisionB, project); } }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(locale.diffFailed(), FAIL, EMERGE_MODE); - } + .catchError(error -> { + notificationManager.notify(locale.diffFailed(), FAIL, EMERGE_MODE); }); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenter.java index 5ed2344d91..386c8d39b6 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenter.java @@ -13,9 +13,6 @@ package org.eclipse.che.ide.ext.git.client.init; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; @@ -66,22 +63,18 @@ public class InitRepositoryPresenter { public void initRepository(final Project project) { final GitOutputConsole console = gitOutputConsoleFactory.create(INIT_COMMAND_NAME); - service.init(appContext.getDevMachine(), project.getLocation(), false).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - console.print(constant.initSuccess()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.initSuccess()); + service.init(project.getLocation(), false) + .then(ignored -> { + console.print(constant.initSuccess()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.initSuccess()); - project.synchronize(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), console); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - } - }); + project.synchronize(); + }) + .catchError(error -> { + handleError(error.getCause(), console); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + }); } /** diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenter.java index 986c509dd7..19bc3bcc97 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenter.java @@ -16,11 +16,7 @@ import com.google.inject.Singleton; import org.eclipse.che.api.core.ErrorCodes; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.MergeResult; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.dialogs.ConfirmCallback; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; @@ -95,94 +91,76 @@ public class MergePresenter implements MergeView.ActionDelegate { selectedReference = null; view.setEnableMergeButton(false); - service.branchList(appContext.getDevMachine(), project.getLocation(), LIST_LOCAL).then(new Operation>() { - @Override - public void apply(List branches) throws OperationException { - List references = new ArrayList<>(); - for (Branch branch : branches) { - if (!branch.isActive()) { - Reference reference = new Reference(branch.getName(), branch.getDisplayName(), LOCAL_BRANCH); - references.add(reference); - } - } - view.setLocalBranches(references); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - console.printError(error.getMessage()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); - } - }); + service.branchList(project.getLocation(), LIST_LOCAL) + .then(branches -> { + List references = new ArrayList<>(); + for (Branch branch : branches) { + if (!branch.isActive()) { + Reference reference = new Reference(branch.getName(), branch.getDisplayName(), LOCAL_BRANCH); + references.add(reference); + } + } + view.setLocalBranches(references); + }) + .catchError(error -> { + console.printError(error.getMessage()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); + }); - service.branchList(appContext.getDevMachine(), project.getLocation(), LIST_REMOTE).then(new Operation>() { - @Override - public void apply(List branches) throws OperationException { - List references = new ArrayList<>(); - for (Branch branch : branches) { - if (!branch.isActive()) { - Reference reference = - new Reference(branch.getName(), branch.getDisplayName(), REMOTE_BRANCH); - references.add(reference); - } - } - view.setRemoteBranches(references); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - console.printError(error.getMessage()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); - } - }); + service.branchList(project.getLocation(), LIST_REMOTE) + .then(branches -> { + List references = new ArrayList<>(); + for (Branch branch : branches) { + if (!branch.isActive()) { + Reference reference = + new Reference(branch.getName(), branch.getDisplayName(), REMOTE_BRANCH); + references.add(reference); + } + } + view.setRemoteBranches(references); + }) + .catchError(error -> { + console.printError(error.getMessage()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); + }); view.showDialog(); } - /** {@inheritDoc} */ @Override public void onCancelClicked() { view.close(); } - /** {@inheritDoc} */ @Override public void onMergeClicked() { view.close(); final GitOutputConsole console = gitOutputConsoleFactory.create(MERGE_COMMAND_NAME); - service.merge(appContext.getDevMachine(), project.getLocation(), selectedReference.getDisplayName()) - .then(new Operation() { - @Override - public void apply(MergeResult result) throws OperationException { - console.print(formMergeMessage(result)); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(formMergeMessage(result)); + service.merge(project.getLocation(), selectedReference.getDisplayName()) + .then(result -> { + console.print(formMergeMessage(result)); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(formMergeMessage(result)); - project.synchronize(); + project.synchronize(); + }) + .catchError(error -> { + if (error.getCause() instanceof ServerException && + ((ServerException)error.getCause()).getErrorCode() == ErrorCodes.NO_COMMITTER_NAME_OR_EMAIL_DEFINED) { + dialogFactory.createMessageDialog(constant.mergeTitle(), constant.committerIdentityInfoEmpty(), + () -> { + //do nothing + }).show(); + return; } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - if (error.getCause() instanceof ServerException && - ((ServerException)error.getCause()).getErrorCode() == ErrorCodes.NO_COMMITTER_NAME_OR_EMAIL_DEFINED) { - dialogFactory.createMessageDialog(constant.mergeTitle(), constant.committerIdentityInfoEmpty(), - new ConfirmCallback() { - @Override - public void accepted() { - //do nothing - } - }).show(); - return; - } - console.printError(error.getMessage()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.mergeFailed(), FAIL, FLOAT_MODE); - } - }); + console.printError(error.getMessage()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.mergeFailed(), FAIL, FLOAT_MODE); + }); } /** diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java index d57089767e..f871631c08 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java @@ -16,11 +16,6 @@ import com.google.inject.Singleton; import org.eclipse.che.api.core.ErrorCodes; import org.eclipse.che.api.git.shared.BranchListMode; import org.eclipse.che.api.git.shared.Branch; -import org.eclipse.che.api.git.shared.PullResponse; -import org.eclipse.che.api.git.shared.Remote; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.git.GitServiceClient; @@ -34,7 +29,6 @@ import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory; import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; import javax.validation.constraints.NotNull; -import java.util.List; import static org.eclipse.che.api.git.shared.BranchListMode.LIST_LOCAL; import static org.eclipse.che.api.git.shared.BranchListMode.LIST_REMOTE; @@ -97,22 +91,16 @@ public class PullPresenter implements PullView.ActionDelegate { view.setEnablePullButton(false); - service.remoteList(appContext.getDevMachine(), project.getLocation(), null, true) - .then(new Operation>() { - @Override - public void apply(List remotes) throws OperationException { - updateBranches(LIST_REMOTE); - view.setRepositories(remotes); - view.setEnablePullButton(!remotes.isEmpty()); - view.showDialog(); - } + service.remoteList(project.getLocation(), null, true) + .then(remotes -> { + updateBranches(LIST_REMOTE); + view.setRepositories(remotes); + view.setEnablePullButton(!remotes.isEmpty()); + view.showDialog(); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), REMOTE_REPO_COMMAND_NAME); - view.setEnablePullButton(false); - } + .catchError(error -> { + handleError(error.getCause(), REMOTE_REPO_COMMAND_NAME); + view.setEnablePullButton(false); }); } @@ -125,29 +113,25 @@ public class PullPresenter implements PullView.ActionDelegate { */ private void updateBranches(@NotNull final BranchListMode remoteMode) { - service.branchList(appContext.getDevMachine(), project.getLocation(), remoteMode).then(new Operation>() { - @Override - public void apply(List branches) throws OperationException { - if (LIST_REMOTE.equals(remoteMode)) { - view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches)); - updateBranches(LIST_LOCAL); - } else { - view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches)); - for (Branch branch : branches) { - if (branch.isActive()) { - view.selectRemoteBranch(branch.getDisplayName()); - break; - } - } - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME); - view.setEnablePullButton(false); - } - }); + service.branchList(project.getLocation(), remoteMode) + .then(branches -> { + if (LIST_REMOTE.equals(remoteMode)) { + view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches)); + updateBranches(LIST_LOCAL); + } else { + view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches)); + for (Branch branch : branches) { + if (branch.isActive()) { + view.selectRemoteBranch(branch.getDisplayName()); + break; + } + } + } + }) + .catchError(error -> { + handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME); + view.setEnablePullButton(false); + }); } /** {@inheritDoc} */ @@ -158,30 +142,26 @@ public class PullPresenter implements PullView.ActionDelegate { final StatusNotification notification = notificationManager.notify(constant.pullProcess(), PROGRESS, FLOAT_MODE); - service.pull(appContext.getDevMachine(), project.getLocation(), getRefs(), view.getRepositoryName()).then(new Operation() { - @Override - public void apply(PullResponse response) throws OperationException { - GitOutputConsole console = gitOutputConsoleFactory.create(PULL_COMMAND_NAME); - console.print(response.getCommandOutput(), GREEN_COLOR); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notification.setStatus(SUCCESS); - if (response.getCommandOutput().contains("Already up-to-date")) { - notification.setTitle(constant.pullUpToDate()); - } else { - project.synchronize(); - notification.setTitle(constant.pullSuccess(view.getRepositoryUrl())); - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notification.setStatus(FAIL); - if (getErrorCode(error.getCause()) == ErrorCodes.MERGE_CONFLICT) { - project.synchronize(); - } - handleError(error.getCause(), PULL_COMMAND_NAME); - } - }); + service.pull(project.getLocation(), getRefs(), view.getRepositoryName()) + .then(response -> { + GitOutputConsole console = gitOutputConsoleFactory.create(PULL_COMMAND_NAME); + console.print(response.getCommandOutput(), GREEN_COLOR); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notification.setStatus(SUCCESS); + if (response.getCommandOutput().contains("Already up-to-date")) { + notification.setTitle(constant.pullUpToDate()); + } else { + project.synchronize(); + notification.setTitle(constant.pullSuccess(view.getRepositoryUrl())); + } + }) + .catchError(error -> { + notification.setStatus(FAIL); + if (getErrorCode(error.getCause()) == ErrorCodes.MERGE_CONFLICT) { + project.synchronize(); + } + handleError(error.getCause(), PULL_COMMAND_NAME); + }); } /** @return list of refs to fetch */ diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java index 7005d2ee8a..8424513998 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java @@ -18,11 +18,6 @@ import org.eclipse.che.api.core.rest.shared.dto.ServiceError; import org.eclipse.che.api.git.shared.BranchListMode; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.api.git.shared.Branch; -import org.eclipse.che.api.git.shared.PushResponse; -import org.eclipse.che.api.git.shared.Remote; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; @@ -39,7 +34,6 @@ import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; import javax.validation.constraints.NotNull; import java.util.Arrays; import java.util.List; -import java.util.Map; import static java.util.Collections.singletonList; import static org.eclipse.che.api.git.shared.BranchListMode.LIST_LOCAL; @@ -107,26 +101,22 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { * If remote repositories are found, then get the list of branches (remote and local). */ void updateRemotes() { - service.remoteList(appContext.getDevMachine(), project.getLocation(), null, true).then(new Operation>() { - @Override - public void apply(List remotes) throws OperationException { - updateLocalBranches(); - view.setRepositories(remotes); - view.setEnablePushButton(!remotes.isEmpty()); - view.setSelectedForcePushCheckBox(false); - view.showDialog(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed(); - GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME); - console.printError(errorMessage); - processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE); - view.setEnablePushButton(false); - } - }); + service.remoteList(project.getLocation(), null, true) + .then(remotes -> { + updateLocalBranches(); + view.setRepositories(remotes); + view.setEnablePushButton(!remotes.isEmpty()); + view.setSelectedForcePushCheckBox(false); + view.showDialog(); + }) + .catchError(error -> { + String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed(); + GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME); + console.printError(errorMessage); + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE); + view.setEnablePushButton(false); + }); } /** @@ -233,29 +223,24 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { final String configBranchRemote = "branch." + view.getLocalBranch() + ".remote"; final String configUpstreamBranch = "branch." + view.getLocalBranch() + ".merge"; - service.config(appContext.getDevMachine(), project.getLocation(), Arrays.asList(configUpstreamBranch, configBranchRemote)) - .then(new Operation>() { - @Override - public void apply(Map configs) throws OperationException { - if (configs.containsKey(configBranchRemote) && configs.containsKey(configUpstreamBranch)) { - String displayName = configs.get(configBranchRemote) + "/" + configs.get(configUpstreamBranch); - Branch upstream = dtoFactory.createDto(Branch.class) - .withActive(false) - .withRemote(true) - .withDisplayName(displayName) - .withName("refs/remotes/" + displayName); + service.config(project.getLocation(), Arrays.asList(configUpstreamBranch, configBranchRemote)) + .then(configs -> { + if (configs.containsKey(configBranchRemote) && configs.containsKey(configUpstreamBranch)) { + String displayName = configs.get(configBranchRemote) + "/" + configs.get(configUpstreamBranch); + Branch upstream = dtoFactory.createDto(Branch.class) + .withActive(false) + .withRemote(true) + .withDisplayName(displayName) + .withName("refs/remotes/" + displayName); - result.onSuccess(upstream); - } else { - result.onSuccess(null); - } + result.onSuccess(upstream); + } else { + result.onSuccess(null); } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - result.onFailure(error.getCause()); - } - }); + }) + .catchError(error -> { + result.onFailure(error.getCause()); + }); } /** @@ -265,17 +250,13 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { * is a remote mode */ void getBranchesForCurrentProject(@NotNull final BranchListMode remoteMode, final AsyncCallback> asyncResult) { - service.branchList(appContext.getDevMachine(), project.getLocation(), remoteMode).then(new Operation>() { - @Override - public void apply(List branches) throws OperationException { - asyncResult.onSuccess(branches); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - asyncResult.onFailure(error.getCause()); - } - }); + service.branchList(project.getLocation(), remoteMode) + .then(branches -> { + asyncResult.onSuccess(branches); + }) + .catchError(error -> { + asyncResult.onFailure(error.getCause()); + }); } /** {@inheritDoc} */ @@ -286,7 +267,7 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { final String repository = view.getRepository(); final GitOutputConsole console = gitOutputConsoleFactory.create(PUSH_COMMAND_NAME); - service.push(appContext.getDevMachine(), project.getLocation(), getRefs(), repository, view.isForcePushSelected()) + service.push(project.getLocation(), getRefs(), repository, view.isForcePushSelected()) .then(response -> { console.print(response.getCommandOutput()); processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemotePresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemotePresenter.java index 632daa66d8..4397e04750 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemotePresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemotePresenter.java @@ -15,9 +15,6 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.git.shared.Remote; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; @@ -29,7 +26,6 @@ import org.eclipse.che.ide.ext.git.client.remote.add.AddRemoteRepositoryPresente import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; import javax.validation.constraints.NotNull; -import java.util.List; import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; @@ -89,22 +85,18 @@ public class RemotePresenter implements RemoteView.ActionDelegate { * then get the list of branches (remote and local). */ private void getRemotes() { - service.remoteList(appContext.getDevMachine(), project.getLocation(), null, true).then(new Operation>() { - @Override - public void apply(List remotes) throws OperationException { - view.setEnableDeleteButton(selectedRemote != null); - view.setRemotes(remotes); - if (!view.isShown()) { - view.showDialog(); - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed(); - handleError(errorMessage); - } - }); + service.remoteList(project.getLocation(), null, true) + .then(remotes -> { + view.setEnableDeleteButton(selectedRemote != null); + view.setRemotes(remotes); + if (!view.isShown()) { + view.showDialog(); + } + }) + .catchError(error -> { + String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed(); + handleError(errorMessage); + }); } /** @@ -149,23 +141,19 @@ public class RemotePresenter implements RemoteView.ActionDelegate { return; } - service.remoteDelete(appContext.getDevMachine(), project.getLocation(), selectedRemote.getName()).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - getRemotes(); + service.remoteDelete(project.getLocation(), selectedRemote.getName()) + .then(ignored -> { + getRemotes(); - project.synchronize(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteDeleteFailed(); - GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME); - console.printError(errorMessage); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.remoteDeleteFailed(), FAIL, FLOAT_MODE); - } - }); + project.synchronize(); + }) + .catchError(error -> { + String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteDeleteFailed(); + GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME); + console.printError(errorMessage); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.remoteDeleteFailed(), FAIL, FLOAT_MODE); + }); } /** diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenter.java index 2e1c81df3f..d98c1a8669 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenter.java @@ -14,14 +14,9 @@ import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.git.GitServiceClient; -import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.resources.Project; -import org.eclipse.che.ide.rest.AsyncRequestCallback; import javax.validation.constraints.NotNull; @@ -69,18 +64,14 @@ public class AddRemoteRepositoryPresenter implements AddRemoteRepositoryView.Act final String url = view.getUrl().trim(); final Project project = appContext.getRootProject(); - service.remoteAdd(appContext.getDevMachine(), project.getLocation(), name, url).then(new Operation() { - @Override - public void apply(Void arg) throws OperationException { - callback.onSuccess(null); - view.close(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - callback.onFailure(error.getCause()); - } - }); + service.remoteAdd(project.getLocation(), name, url) + .then(arg -> { + callback.onSuccess(null); + view.close(); + }) + .catchError(error -> { + callback.onFailure(error.getCause()); + }); } /** {@inheritDoc} */ diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexPresenter.java index e638c75e2c..97d93983b7 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexPresenter.java @@ -12,9 +12,6 @@ package org.eclipse.che.ide.ext.git.client.remove; import com.google.inject.Inject; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; @@ -99,22 +96,18 @@ public class RemoveFromIndexPresenter implements RemoveFromIndexView.ActionDeleg checkState(!isNullOrEmpty(resources)); - service.remove(appContext.getDevMachine(), project.getLocation(), toRelativePaths(resources), view.isRemoved()).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - console.print(constant.removeFilesSuccessfull()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.removeFilesSuccessfull()); + service.remove(project.getLocation(), toRelativePaths(resources), view.isRemoved()) + .then(ignored -> { + console.print(constant.removeFilesSuccessfull()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.removeFilesSuccessfull()); - project.synchronize(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - handleError(error.getCause(), console); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - } - }); + project.synchronize(); + }) + .catchError(error -> { + handleError(error.getCause(), console); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + }); view.close(); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/commit/ResetToCommitPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/commit/ResetToCommitPresenter.java index 2355a9f529..075b962562 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/commit/ResetToCommitPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/commit/ResetToCommitPresenter.java @@ -14,12 +14,8 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.core.ErrorCodes; -import org.eclipse.che.api.git.shared.LogResponse; import org.eclipse.che.api.git.shared.ResetRequest; import org.eclipse.che.api.git.shared.Revision; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.git.GitServiceClient; @@ -82,32 +78,28 @@ public class ResetToCommitPresenter implements ResetToCommitView.ActionDelegate public void showDialog(final Project project) { this.project = project; - service.log(appContext.getDevMachine(), project.getLocation(), null, false).then(new Operation() { - @Override - public void apply(LogResponse log) throws OperationException { - view.setRevisions(log.getCommits()); - view.setMixMode(true); - view.setEnableResetButton(selectedRevision != null); - view.showDialog(); + service.log(project.getLocation(), null, -1, -1, false) + .then(log -> { + view.setRevisions(log.getCommits()); + view.setMixMode(true); + view.setEnableResetButton(selectedRevision != null); + view.showDialog(); - project.synchronize(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { - dialogFactory.createMessageDialog(constant.resetCommitViewTitle(), - constant.initCommitWasNotPerformed(), - null).show(); - return; - } - String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.logFailed(); - GitOutputConsole console = gitOutputConsoleFactory.create(LOG_COMMAND_NAME); - console.printError(errorMessage); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.logFailed(), FAIL, FLOAT_MODE); - } - }); + project.synchronize(); + }) + .catchError(error -> { + if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { + dialogFactory.createMessageDialog(constant.resetCommitViewTitle(), + constant.initCommitWasNotPerformed(), + null).show(); + return; + } + String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.logFailed(); + GitOutputConsole console = gitOutputConsoleFactory.create(LOG_COMMAND_NAME); + console.printError(errorMessage); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.logFailed(), FAIL, FLOAT_MODE); + }); } /** @@ -146,24 +138,20 @@ public class ResetToCommitPresenter implements ResetToCommitView.ActionDelegate final GitOutputConsole console = gitOutputConsoleFactory.create(RESET_COMMAND_NAME); - service.reset(appContext.getDevMachine(), project.getLocation(), selectedRevision.getId(), type, null).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - console.print(constant.resetSuccessfully()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.resetSuccessfully()); + service.reset(project.getLocation(), selectedRevision.getId(), type, null) + .then(ignored -> { + console.print(constant.resetSuccessfully()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.resetSuccessfully()); - project.synchronize(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.resetFail(); - console.printError(errorMessage); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.resetFail(), FAIL, FLOAT_MODE); - } - }); + project.synchronize(); + }) + .catchError(error -> { + String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.resetFail(); + console.printError(errorMessage); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.resetFail(), FAIL, FLOAT_MODE); + }); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenter.java index 2f4f8aa1cc..99639803b7 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenter.java @@ -14,10 +14,6 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.git.shared.IndexFile; -import org.eclipse.che.api.git.shared.Status; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.git.GitServiceClient; @@ -90,58 +86,54 @@ public class ResetFilesPresenter implements ResetFilesView.ActionDelegate { public void showDialog(Project project) { this.project = project; - service.getStatus(appContext.getDevMachine(), project.getLocation()).then(new Operation() { - @Override - public void apply(Status status) throws OperationException { - if (status.isClean()) { - dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show(); - return; - } + service.getStatus(project.getLocation()) + .then(status -> { + if (status.isClean()) { + dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show(); + return; + } - indexedFiles = new IndexFile[0]; + indexedFiles = new IndexFile[0]; - for (String path : status.getAdded()) { - indexedFiles = add(indexedFiles, wrap(path)); - } + for (String path : status.getAdded()) { + indexedFiles = add(indexedFiles, wrap(path)); + } - for (String path : status.getChanged()) { - indexedFiles = add(indexedFiles, wrap(path)); - } + for (String path : status.getChanged()) { + indexedFiles = add(indexedFiles, wrap(path)); + } - for (String path : status.getRemoved()) { - indexedFiles = add(indexedFiles, wrap(path)); - } + for (String path : status.getRemoved()) { + indexedFiles = add(indexedFiles, wrap(path)); + } - if (indexedFiles.length == 0) { - dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show(); - return; - } + if (indexedFiles.length == 0) { + dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show(); + return; + } - //Mark selected items to reset from index - Resource[] resources = appContext.getResources(); - if (resources != null) { - for (Resource selectedItem : resources) { - String selectedItemPath = selectedItem.getLocation().removeFirstSegments(1).toString(); - for (IndexFile file : indexedFiles) - if (file.getPath().startsWith(selectedItemPath)) { - file.setIndexed(false); - } - } - } + //Mark selected items to reset from index + Resource[] resources = appContext.getResources(); + if (resources != null) { + for (Resource selectedItem : resources) { + String selectedItemPath = selectedItem.getLocation().removeFirstSegments(1).toString(); + for (IndexFile file : indexedFiles) + if (file.getPath().startsWith(selectedItemPath)) { + file.setIndexed(false); + } + } + } - view.setIndexedFiles(indexedFiles); - view.showDialog(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - String errorMassage = error.getMessage() != null ? error.getMessage() : constant.statusFailed(); - GitOutputConsole console = gitOutputConsoleFactory.create(STATUS_COMMAND_NAME); - console.printError(errorMassage); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(errorMassage); - } - }); + view.setIndexedFiles(indexedFiles); + view.showDialog(); + }) + .catchError(error -> { + String errorMassage = error.getMessage() != null ? error.getMessage() : constant.statusFailed(); + GitOutputConsole console = gitOutputConsoleFactory.create(STATUS_COMMAND_NAME); + console.printError(errorMassage); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(errorMassage); + }); } protected IndexFile wrap(String path) { @@ -169,22 +161,18 @@ public class ResetFilesPresenter implements ResetFilesView.ActionDelegate { } view.close(); - service.reset(appContext.getDevMachine(), project.getLocation(), "HEAD", ResetType.MIXED, paths).then(new Operation() { - @Override - public void apply(Void ignored) throws OperationException { - console.print(constant.resetFilesSuccessfully()); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(constant.resetFilesSuccessfully()); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - String errorMassage = error.getMessage() != null ? error.getMessage() : constant.resetFilesFailed(); - console.printError(errorMassage); - consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); - notificationManager.notify(errorMassage); - } - }); + service.reset(project.getLocation(), "HEAD", ResetType.MIXED, paths) + .then(ignored -> { + console.print(constant.resetFilesSuccessfully()); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(constant.resetFilesSuccessfully()); + }) + .catchError(error -> { + String errorMassage = error.getMessage() != null ? error.getMessage() : constant.resetFilesFailed(); + console.printError(errorMassage); + consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); + notificationManager.notify(errorMassage); + }); } /** {@inheritDoc} */ diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenter.java index dec31f6f85..3359664647 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenter.java @@ -13,9 +13,6 @@ package org.eclipse.che.ide.ext.git.client.status; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; @@ -70,17 +67,13 @@ public class StatusCommandPresenter { /** Show status. */ public void showStatus(Project project) { - service.statusText(appContext.getDevMachine(), project.getLocation(), LONG).then(new Operation() { - @Override - public void apply(String status) throws OperationException { - printGitStatus(status); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - notificationManager.notify(constant.statusFailed(), FAIL, FLOAT_MODE); - } - }); + service.statusText(project.getLocation(), LONG) + .then(status -> { + printGitStatus(status); + }) + .catchError(error -> { + notificationManager.notify(constant.statusFailed(), FAIL, FLOAT_MODE); + }); } /** diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenterTest.java index d87d1dbef6..add8e8bf47 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexPresenterTest.java @@ -68,7 +68,7 @@ public class AddToIndexPresenterTest extends BaseTest { when(appContext.getRootProject()).thenReturn(mock(Project.class)); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); - when(service.add(any(DevMachine.class), any(Path.class), anyBoolean(), any(Path[].class))).thenReturn(voidPromise); + when(service.add(any(Path.class), anyBoolean(), any(Path[].class))).thenReturn(voidPromise); when(gitOutputConsoleFactory.create(anyString())).thenReturn(console); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java index 0faaabdf81..5e09f2eea9 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java @@ -14,7 +14,6 @@ import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.CheckoutRequest; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; -import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.ext.git.client.BaseTest; import org.eclipse.che.ide.api.dialogs.ConfirmCallback; @@ -69,8 +68,6 @@ public class BranchPresenterTest extends BaseTest { @Mock private Branch selectedBranch; @Mock - private WorkspaceAgent workspaceAgent; - @Mock private DialogFactory dialogFactory; @Mock private DtoFactory dtoFactory; @@ -98,7 +95,7 @@ public class BranchPresenterTest extends BaseTest { when(selectedBranch.isRemote()).thenReturn(IS_REMOTE); when(selectedBranch.isActive()).thenReturn(IS_ACTIVE); - when(service.branchList(anyObject(), anyObject(), anyObject())).thenReturn(branchListPromise); + when(service.branchList(anyObject(), anyObject())).thenReturn(branchListPromise); when(branchListPromise.then(any(Operation.class))).thenReturn(branchListPromise); when(branchListPromise.catchError(any(Operation.class))).thenReturn(branchListPromise); } @@ -107,7 +104,7 @@ public class BranchPresenterTest extends BaseTest { public void testShowBranchesWhenGetBranchesRequestIsSuccessful() throws Exception { final List branches = Collections.singletonList(selectedBranch); - when(service.branchList(anyObject(), anyObject(), anyObject())).thenReturn(branchListPromise); + when(service.branchList(anyObject(), anyObject())).thenReturn(branchListPromise); when(branchListPromise.then(any(Operation.class))).thenReturn(branchListPromise); when(branchListPromise.catchError(any(Operation.class))).thenReturn(branchListPromise); @@ -134,7 +131,7 @@ public class BranchPresenterTest extends BaseTest { public void testOnRenameClickedWhenLocalBranchSelected() throws Exception { reset(selectedBranch); - when(service.branchRename(anyObject(), anyObject(), anyString(), anyString())).thenReturn(voidPromise); + when(service.branchRename(anyObject(), anyString(), anyString())).thenReturn(voidPromise); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); @@ -163,7 +160,7 @@ public class BranchPresenterTest extends BaseTest { public void testOnRenameClickedWhenRemoteBranchSelectedAndUserConfirmRename() throws Exception { reset(selectedBranch); - when(service.branchRename(anyObject(), anyObject(), anyString(), anyString())).thenReturn(voidPromise); + when(service.branchRename(anyObject(), anyString(), anyString())).thenReturn(voidPromise); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); @@ -191,7 +188,7 @@ public class BranchPresenterTest extends BaseTest { voidPromiseCaptor.getValue().apply(null); verify(selectedBranch, times(2)).getDisplayName(); - verify(service, times(2)).branchList(anyObject(), anyObject(), eq(LIST_ALL)); + verify(service, times(2)).branchList(anyObject(), eq(LIST_ALL)); verify(console, never()).printError(anyString()); verify(notificationManager, never()).notify(anyString()); verify(constant, never()).branchRenameFailed(); @@ -205,7 +202,7 @@ public class BranchPresenterTest extends BaseTest { @Test public void testOnDeleteClickedWhenBranchDeleteRequestIsSuccessful() throws Exception { - when(service.branchDelete(anyObject(), any(Path.class), anyString(), anyBoolean())).thenReturn(voidPromise); + when(service.branchDelete(any(Path.class), anyString(), anyBoolean())).thenReturn(voidPromise); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); @@ -216,7 +213,7 @@ public class BranchPresenterTest extends BaseTest { voidPromiseCaptor.getValue().apply(null); verify(selectedBranch).getName(); - verify(service, times(2)).branchList(anyObject(), anyObject(), eq(LIST_ALL)); + verify(service, times(2)).branchList(anyObject(), eq(LIST_ALL)); verify(constant, never()).branchDeleteFailed(); verify(console, never()).printError(anyString()); verify(notificationManager, never()).notify(anyString()); @@ -224,9 +221,9 @@ public class BranchPresenterTest extends BaseTest { @Test public void testOnCheckoutClickedWhenSelectedNotRemoteBranch() throws Exception { - when(service.checkout(anyObject(), any(Path.class), any(CheckoutRequest.class))).thenReturn(voidPromise); - when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); - when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); + when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(stringPromise); + when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise); + when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise); when(selectedBranch.isRemote()).thenReturn(false); when(dtoFactory.createDto(CheckoutRequest.class)).thenReturn(checkoutRequest); @@ -234,8 +231,8 @@ public class BranchPresenterTest extends BaseTest { selectBranch(); presenter.onCheckoutClicked(); - verify(voidPromise).then(voidPromiseCaptor.capture()); - voidPromiseCaptor.getValue().apply(null); + verify(stringPromise).then(stringCaptor.capture()); + stringCaptor.getValue().apply(null); verify(checkoutRequest).setName(eq(BRANCH_NAME)); verifyNoMoreInteractions(checkoutRequest); @@ -243,17 +240,17 @@ public class BranchPresenterTest extends BaseTest { @Test public void testOnCheckoutClickedWhenSelectedRemoteBranch() throws Exception { - when(service.checkout(anyObject(), any(Path.class), any(CheckoutRequest.class))).thenReturn(voidPromise); - when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); - when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); + when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(stringPromise); + when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise); + when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise); when(dtoFactory.createDto(CheckoutRequest.class)).thenReturn(checkoutRequest); selectBranch(); presenter.onCheckoutClicked(); - verify(voidPromise).then(voidPromiseCaptor.capture()); - voidPromiseCaptor.getValue().apply(null); + verify(stringPromise).then(stringCaptor.capture()); + stringCaptor.getValue().apply(null); verify(checkoutRequest).setTrackBranch(eq(BRANCH_NAME)); verifyNoMoreInteractions(checkoutRequest); @@ -261,7 +258,7 @@ public class BranchPresenterTest extends BaseTest { @Test public void testOnCreateClickedWhenBranchCreateRequestIsSuccessful() throws Exception { - when(service.branchCreate(anyObject(), any(Path.class), anyString(), anyString())).thenReturn(branchPromise); + when(service.branchCreate(any(Path.class), anyString(), anyString())).thenReturn(branchPromise); when(branchPromise.then(any(Operation.class))).thenReturn(branchPromise); when(branchPromise.catchError(any(Operation.class))).thenReturn(branchPromise); @@ -279,8 +276,8 @@ public class BranchPresenterTest extends BaseTest { branchCaptor.getValue().apply(selectedBranch); verify(constant).branchTypeNew(); - verify(service).branchCreate(anyObject(), any(Path.class), anyString(), anyString()); - verify(service, times(2)).branchList(anyObject(), anyObject(), eq(LIST_ALL)); + verify(service).branchCreate(any(Path.class), anyString(), anyString()); + verify(service, times(2)).branchList(anyObject(), eq(LIST_ALL)); } @Test diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferenceTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferenceTest.java index c2616d04ac..81f736a8f1 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferenceTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/checkout/CheckoutReferenceTest.java @@ -20,7 +20,6 @@ import org.mockito.Mock; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; @@ -98,31 +97,32 @@ public class CheckoutReferenceTest extends BaseTest { presenter.onEnterClicked(); verify(view, never()).close(); - verify(service, never()).checkout(anyObject(), any(Path.class), any(CheckoutRequest.class)); + verify(service, never()).checkout(any(Path.class), any(CheckoutRequest.class)); } @Test public void onEnterClickedWhenValueIsCorrect() throws Exception { + when(appContext.getRootProject()).thenReturn(project); when(dtoFactory.createDto(CheckoutRequest.class)).thenReturn(checkoutRequest); when(checkoutRequest.withName(anyString())).thenReturn(checkoutRequest); when(checkoutRequest.withCreateNew(anyBoolean())).thenReturn(checkoutRequest); reset(service); - when(service.checkout(anyObject(), any(Path.class), any(CheckoutRequest.class))).thenReturn(voidPromise); - when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); - when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); + when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(stringPromise); + when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise); + when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise); when(view.getReference()).thenReturn(CORRECT_REFERENCE); presenter.showDialog(project); presenter.onEnterClicked(); - verify(voidPromise).then(voidPromiseCaptor.capture()); - voidPromiseCaptor.getValue().apply(null); + verify(stringPromise).then(stringCaptor.capture()); + stringCaptor.getValue().apply(null); verify(synchronizePromise).then(synchronizeCaptor.capture()); synchronizeCaptor.getValue().apply(new Resource[0]); verify(view).close(); - verify(service).checkout(anyObject(), any(Path.class), any(CheckoutRequest.class)); + verify(service).checkout(any(Path.class), any(CheckoutRequest.class)); verify(checkoutRequest).withName(CORRECT_REFERENCE); verifyNoMoreInteractions(checkoutRequest); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java index 3458a0c283..ea8525a329 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java @@ -106,21 +106,20 @@ public class CommitPresenterTest extends BaseTest { when(logPromise.then(any(Operation.class))).thenReturn(logPromise); when(logPromise.catchError(any(Operation.class))).thenReturn(logPromise); when(statusPromise.then(any(Operation.class))).thenReturn(statusPromise); - when(service.add(any(DevMachine.class), any(Path.class), anyBoolean(), any(Path[].class))).thenReturn(voidPromise); - when(service.commit(any(DevMachine.class), any(Path.class), anyString(), anyBoolean(), any(Path[].class), anyBoolean())) + when(service.add(any(Path.class), anyBoolean(), any(Path[].class))).thenReturn(voidPromise); + when(service.commit(any(Path.class), anyString(), anyBoolean(), any(Path[].class))) .thenReturn(revisionPromise); - when(service.diff(any(DevMachine.class), - any(Path.class), + when(service.diff(any(Path.class), eq(null), any(DiffType.class), anyBoolean(), anyInt(), anyString(), anyBoolean())).thenReturn(stringPromise); - when(service.branchList(any(DevMachine.class), any(Path.class), any(BranchListMode.class))).thenReturn(branchListPromise); - when(service.push(any(DevMachine.class), any(Path.class), anyList(), anyString(), anyBoolean())).thenReturn(pushPromise); - when(service.log(any(DevMachine.class), any(Path.class), eq(null), anyInt(), anyInt(), anyBoolean())).thenReturn(logPromise); - when(service.getStatus(any(DevMachine.class), any(Path.class))).thenReturn(statusPromise); + when(service.branchList(any(Path.class), any(BranchListMode.class))).thenReturn(branchListPromise); + when(service.push(any(Path.class), anyList(), anyString(), anyBoolean())).thenReturn(pushPromise); + when(service.log(any(Path.class), eq(null), anyInt(), anyInt(), anyBoolean())).thenReturn(logPromise); + when(service.getStatus(any(Path.class))).thenReturn(statusPromise); } @Test diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java index ed49d19b0b..7b70aebf05 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java @@ -64,11 +64,11 @@ public class FetchPresenterTest extends BaseTest { gitOutputConsoleFactory, processesPanelPresenter); - when(service.remoteList(anyObject(), any(Path.class), anyString(), anyBoolean())).thenReturn(remoteListPromise); + when(service.remoteList(any(Path.class), anyString(), anyBoolean())).thenReturn(remoteListPromise); when(remoteListPromise.then(any(Operation.class))).thenReturn(remoteListPromise); when(remoteListPromise.catchError(any(Operation.class))).thenReturn(remoteListPromise); - when(service.branchList(anyObject(), any(Path.class), anyObject())).thenReturn(branchListPromise); + when(service.branchList(any(Path.class), anyObject())).thenReturn(branchListPromise); when(branchListPromise.then(any(Operation.class))).thenReturn(branchListPromise); when(branchListPromise.catchError(any(Operation.class))).thenReturn(branchListPromise); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenterTest.java index 41886b1643..82c693fc14 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/history/HistoryPresenterTest.java @@ -18,7 +18,6 @@ import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.dialogs.ConfirmCallback; import org.eclipse.che.ide.api.dialogs.MessageDialog; -import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.commons.exception.ServerException; @@ -69,15 +68,13 @@ public class HistoryPresenterTest extends BaseTest { when(appContext.getResource()).thenReturn(resource); when(appContext.getRootProject()).thenReturn(project); - when(service.log(any(DevMachine.class), - any(Path.class), + when(service.log(any(Path.class), any(Path[].class), anyInt(), anyInt(), anyBoolean())) .thenReturn(logPromise); - when(service.diff(any(DevMachine.class), - any(Path.class), + when(service.diff(any(Path.class), anyList(), any(DiffType.class), anyBoolean(), @@ -85,8 +82,7 @@ public class HistoryPresenterTest extends BaseTest { anyString(), anyString())) .thenReturn(stringPromise); - when(service.showFileContent(any(DevMachine.class), - any(Path.class), + when(service.showFileContent(any(Path.class), any(Path.class), anyString())) .thenReturn(showPromise); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenterTest.java index a470437226..b038ac7849 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/init/InitRepositoryPresenterTest.java @@ -47,7 +47,7 @@ public class InitRepositoryPresenterTest extends BaseTest { service, appContext); - when(service.init(anyObject(), any(Path.class), anyBoolean())).thenReturn(voidPromise); + when(service.init(any(Path.class), anyBoolean())).thenReturn(voidPromise); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenterTest.java index a5fbb48369..0b515f24f5 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/merge/MergePresenterTest.java @@ -81,11 +81,11 @@ public class MergePresenterTest extends BaseTest { when(mergeResult.getMergeStatus()).thenReturn(ALREADY_UP_TO_DATE); when(selectedReference.getDisplayName()).thenReturn(DISPLAY_NAME); - when(service.branchList(anyObject(), any(Path.class), eq(LIST_LOCAL))).thenReturn(branchListPromise); + when(service.branchList(any(Path.class), eq(LIST_LOCAL))).thenReturn(branchListPromise); when(branchListPromise.then(any(Operation.class))).thenReturn(branchListPromise); when(branchListPromise.catchError(any(Operation.class))).thenReturn(branchListPromise); - when(service.branchList(anyObject(), any(Path.class), eq(LIST_REMOTE))).thenReturn(remoteListBranchPromise); + when(service.branchList(any(Path.class), eq(LIST_REMOTE))).thenReturn(remoteListBranchPromise); when(remoteListBranchPromise.then(any(Operation.class))).thenReturn(remoteListBranchPromise); when(remoteListBranchPromise.catchError(any(Operation.class))).thenReturn(remoteListBranchPromise); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenterTest.java index 31000dbc10..8c56f0ae3c 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/remote/add/AddRemoteRepositoryPresenterTest.java @@ -87,11 +87,11 @@ public class AddRemoteRepositoryPresenterTest extends BaseTest { when(appContext.getRootProject()).thenReturn(mock(Project.class)); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); - when(service.remoteAdd(anyObject(), anyObject(), anyString(), anyString())).thenReturn(voidPromise); + when(service.remoteAdd(anyObject(), anyString(), anyString())).thenReturn(voidPromise); when(view.getUrl()).thenReturn(" " + REMOTE_URI + " "); presenter.onOkClicked(); - verify(service).remoteAdd(anyObject(), anyObject(), anyString(), eq(REMOTE_URI)); + verify(service).remoteAdd(anyObject(), anyString(), eq(REMOTE_URI)); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenterTest.java index 4bcf80e868..33b24e3dda 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesPresenterTest.java @@ -67,7 +67,7 @@ public class ResetFilesPresenterTest extends BaseTest { when(indexFile.withIndexed(anyBoolean())).thenReturn(indexFile); when(indexFile.withPath(anyString())).thenReturn(indexFile); when(indexFile.getPath()).thenReturn("foo"); - when(service.getStatus(anyObject(), any(Path.class))).thenReturn(statusPromise); + when(service.getStatus(any(Path.class))).thenReturn(statusPromise); when(statusPromise.then(any(Operation.class))).thenReturn(statusPromise); when(statusPromise.catchError(any(Operation.class))).thenReturn(statusPromise); when(appContext.getResources()).thenReturn(new Resource[]{}); @@ -163,7 +163,7 @@ public class ResetFilesPresenterTest extends BaseTest { when(status.getChanged()).thenReturn(changes); when(status.getRemoved()).thenReturn(changes); - when(service.reset(anyObject(), any(Path.class), anyString(), any(ResetRequest.ResetType.class), anyObject())).thenReturn(voidPromise); + when(service.reset(any(Path.class), anyString(), any(ResetRequest.ResetType.class), anyObject())).thenReturn(voidPromise); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); @@ -192,7 +192,7 @@ public class ResetFilesPresenterTest extends BaseTest { when(status.getChanged()).thenReturn(changes); when(status.getRemoved()).thenReturn(changes); - when(service.reset(anyObject(), any(Path.class), anyString(), any(ResetRequest.ResetType.class), anyObject())).thenReturn(voidPromise); + when(service.reset(any(Path.class), anyString(), any(ResetRequest.ResetType.class), anyObject())).thenReturn(voidPromise); when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise); when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenterTest.java index 69b31e2280..a2d55beb96 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/status/StatusCommandPresenterTest.java @@ -13,7 +13,6 @@ package org.eclipse.che.ide.ext.git.client.status; import org.eclipse.che.api.git.shared.StatusFormat; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.ide.api.notification.StatusNotification; -import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.ext.git.client.BaseTest; import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory; import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; @@ -39,9 +38,6 @@ public class StatusCommandPresenterTest extends BaseTest { @InjectMocks private StatusCommandPresenter presenter; - @Mock - private WorkspaceAgent workspaceAgent; - @Mock private GitOutputConsoleFactory gitOutputConsoleFactory; @@ -59,7 +55,7 @@ public class StatusCommandPresenterTest extends BaseTest { constant, notificationManager); - when(service.statusText(anyObject(), any(Path.class), any(StatusFormat.class))).thenReturn(stringPromise); + when(service.statusText(any(Path.class), any(StatusFormat.class))).thenReturn(stringPromise); when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise); when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise); } diff --git a/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java b/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java index 011bd2d205..f1b2911d9b 100644 --- a/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java +++ b/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java @@ -20,30 +20,21 @@ import org.eclipse.che.api.git.shared.BranchListMode; import org.eclipse.che.api.git.shared.CheckoutRequest; import org.eclipse.che.api.git.shared.PushResponse; import org.eclipse.che.api.git.shared.Remote; -import org.eclipse.che.api.git.shared.Revision; import org.eclipse.che.api.git.shared.Status; import org.eclipse.che.api.promises.client.Function; -import org.eclipse.che.api.promises.client.FunctionException; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.promises.client.js.JsPromiseError; import org.eclipse.che.api.promises.client.js.Promises; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.git.GitServiceClient; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.resource.Path; -import org.eclipse.che.ide.rest.AsyncRequestCallback; import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; -import org.eclipse.che.ide.rest.Unmarshallable; -import org.eclipse.che.ide.websocket.WebSocketException; -import org.eclipse.che.ide.websocket.rest.RequestCallback; import javax.validation.constraints.NotNull; -import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * Git backed implementation for {@link VcsService}. @@ -52,10 +43,9 @@ import java.util.List; public class GitVcsService implements VcsService { private static final String BRANCH_UP_TO_DATE_ERROR_MESSAGE = "Everything up-to-date"; - private final GitServiceClient service; - private final DtoFactory dtoFactory; - private final DtoUnmarshallerFactory dtoUnmarshallerFactory; - private final AppContext appContext; + private final GitServiceClient service; + private final DtoFactory dtoFactory; + private final AppContext appContext; @Inject public GitVcsService(final DtoFactory dtoFactory, @@ -63,7 +53,6 @@ public class GitVcsService implements VcsService { final GitServiceClient service, final AppContext appContext) { this.dtoFactory = dtoFactory; - this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; this.service = service; this.appContext = appContext; } @@ -71,116 +60,73 @@ public class GitVcsService implements VcsService { @Override public void addRemote(@NotNull final ProjectConfig project, @NotNull final String remote, @NotNull final String remoteUrl, @NotNull final AsyncCallback callback) { - - service.remoteAdd(appContext.getDevMachine(), project, remote, remoteUrl, new AsyncRequestCallback() { - @Override - protected void onSuccess(final String notUsed) { - callback.onSuccess(null); - } - - @Override - protected void onFailure(final Throwable exception) { - callback.onFailure(exception); - } - }); + service.remoteAdd(appContext.getRootProject().getLocation(), remote, remoteUrl) + .then(arg -> { + callback.onSuccess(null); + }) + .catchError(error -> { + callback.onFailure(error.getCause()); + }); } @Override public void checkoutBranch(@NotNull final ProjectConfig project, @NotNull final String name, final boolean createNew, @NotNull final AsyncCallback callback) { - service.checkout(appContext.getDevMachine(), - project, + service.checkout(appContext.getRootProject().getLocation(), dtoFactory.createDto(CheckoutRequest.class) .withName(name) - .withCreateNew(createNew), - new AsyncRequestCallback() { - @Override - protected void onSuccess(final String branchName) { - callback.onSuccess(branchName); - } - - @Override - protected void onFailure(final Throwable exception) { - callback.onFailure(exception); - } - }); + .withCreateNew(createNew)) + .then(callback::onSuccess) + .catchError(error -> { + callback.onFailure(error.getCause()); + }); } @Override public void commit(@NotNull final ProjectConfig project, final boolean includeUntracked, @NotNull final String commitMessage, @NotNull final AsyncCallback callback) { - try { - - service.add(appContext.getDevMachine(), project, !includeUntracked, null, new RequestCallback() { - @Override - protected void onSuccess(Void aVoid) { - - service.commit(appContext.getDevMachine(), project, commitMessage, true, false, new AsyncRequestCallback() { - @Override - protected void onSuccess(final Revision revision) { - callback.onSuccess(null); - } - - @Override - protected void onFailure(final Throwable exception) { - callback.onFailure(exception); - } - }); - } - - @Override - protected void onFailure(final Throwable exception) { - callback.onFailure(exception); - } - }); - - } catch (final WebSocketException exception) { - callback.onFailure(exception); - } + service.add(appContext.getRootProject().getLocation(), !includeUntracked, null) + .then(arg -> { + service.commit(appContext.getRootProject().getLocation(), commitMessage, true, false) + .then(revision -> { + callback.onSuccess(null); + }) + .catchError(error -> { + callback.onFailure(error.getCause()); + }); + }) + .catchError(error -> { + callback.onFailure(error.getCause()); + }); } @Override public void deleteRemote(@NotNull final ProjectConfig project, @NotNull final String remote, @NotNull final AsyncCallback callback) { - service.remoteDelete(appContext.getDevMachine(), project, remote, new AsyncRequestCallback() { - @Override - protected void onSuccess(final String notUsed) { - callback.onSuccess(null); - } - - @Override - protected void onFailure(final Throwable exception) { - callback.onFailure(exception); - } - }); + service.remoteDelete(appContext.getRootProject().getLocation(), remote) + .then(arg -> { + callback.onSuccess(null); + }) + .catchError(error -> { + callback.onFailure(error.getCause()); + }); } @Override public Promise getBranchName(ProjectConfig project) { - return service.getStatus(appContext.getDevMachine(), Path.valueOf(project.getPath())) - .then(new Function() { - @Override - public String apply(Status status) throws FunctionException { - return status.getBranchName(); - } - }); + return service.getStatus(Path.valueOf(project.getPath())) + .then((Function)status -> status.getBranchName()); } @Override public void hasUncommittedChanges(@NotNull final ProjectConfig project, @NotNull final AsyncCallback callback) { - service.getStatus(appContext.getDevMachine(), Path.valueOf(project.getPath())) - .then(new Operation() { - @Override - public void apply(Status status) throws OperationException { - callback.onSuccess(!status.isClean()); - } + service.getStatus(Path.valueOf(project.getPath())) + .then(status -> { + callback.onSuccess(!status.isClean()); }) - .catchError(new Operation() { - @Override - public void apply(PromiseError err) throws OperationException { - callback.onFailure(err.getCause()); - } + .catchError(err -> { + callback.onFailure(err.getCause()); }); } @@ -214,20 +160,17 @@ public class GitVcsService implements VcsService { @Override public Promise> listRemotes(ProjectConfig project) { - return service.remoteList(appContext.getDevMachine(), project, null, false); + return service.remoteList(appContext.getRootProject().getLocation(), null, false); } @Override public Promise pushBranch(final ProjectConfig project, final String remote, final String localBranchName) { - return service.push(appContext.getDevMachine(), project, Collections.singletonList(localBranchName), remote, true) - .catchErrorPromise(new Function>() { - @Override - public Promise apply(PromiseError error) throws FunctionException { - if (BRANCH_UP_TO_DATE_ERROR_MESSAGE.equalsIgnoreCase(error.getMessage())) { - return Promises.reject(JsPromiseError.create(new BranchUpToDateException(localBranchName))); - } else { - return Promises.reject(error); - } + return service.push(appContext.getRootProject().getLocation(), Collections.singletonList(localBranchName), remote, true) + .catchErrorPromise(error -> { + if (BRANCH_UP_TO_DATE_ERROR_MESSAGE.equalsIgnoreCase(error.getMessage())) { + return Promises.reject(JsPromiseError.create(new BranchUpToDateException(localBranchName))); + } else { + return Promises.reject(error); } }); } @@ -243,24 +186,14 @@ public class GitVcsService implements VcsService { * callback when the operation is done. */ private void listBranches(final ProjectConfig project, final BranchListMode listMode, final AsyncCallback> callback) { - final Unmarshallable> unMarshaller = - dtoUnmarshallerFactory.newListUnmarshaller(Branch.class); - service.branchList(appContext.getDevMachine(), project, listMode, - new AsyncRequestCallback>(unMarshaller) { - @Override - protected void onSuccess(final List branches) { - final List result = new ArrayList<>(); - for (final Branch branch : branches) { - result.add(fromGitBranch(branch)); - } - callback.onSuccess(result); - } - - @Override - protected void onFailure(final Throwable exception) { - callback.onFailure(exception); - } - }); + service.branchList(Path.valueOf(project.getPath()), listMode) + .then(branches -> { + final List result = branches.stream().map(this::fromGitBranch).collect(Collectors.toList()); + callback.onSuccess(result); + }) + .catchError(error -> { + callback.onFailure(error.getCause()); + }); } /** From 7078a070a0d8f3e4a7b4ddf42b7292ad21aa7cc5 Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Tue, 4 Jul 2017 12:41:04 +0300 Subject: [PATCH 03/11] Avoid possible NPE (#5526) Signed-off-by: Vitalii Parfonov --- .../server/projecttype/ComposerValueProviderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugin-composer/che-plugin-composer-server/src/main/java/org/eclipse/che/plugin/composer/server/projecttype/ComposerValueProviderFactory.java b/plugins/plugin-composer/che-plugin-composer-server/src/main/java/org/eclipse/che/plugin/composer/server/projecttype/ComposerValueProviderFactory.java index 7c2d35bc1a..fb792312cf 100644 --- a/plugins/plugin-composer/che-plugin-composer-server/src/main/java/org/eclipse/che/plugin/composer/server/projecttype/ComposerValueProviderFactory.java +++ b/plugins/plugin-composer/che-plugin-composer-server/src/main/java/org/eclipse/che/plugin/composer/server/projecttype/ComposerValueProviderFactory.java @@ -54,7 +54,7 @@ public class ComposerValueProviderFactory implements ValueProviderFactory { JsonObject model = readModel(projectFolder); String value = ""; - if (attributeName.equals(PACKAGE)) { + if (attributeName.equals(PACKAGE) && model.has("name")) { value = model.get("name").getAsString(); } From a94173001642411f597066f841edf4236176ea67 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskii Date: Tue, 4 Jul 2017 14:14:02 +0300 Subject: [PATCH 04/11] Register refresh method for ProjectExplorer native object (#5530) * Provide internal API method fro refresh projects * Update codebase to java 8 * Internal API for fetch commands via Command Manager Signed-off-by: Vladyslav Zhukovskyi --- .../command/manager/CommandManagerImpl.java | 14 ++ .../project/ProjectExplorerPresenter.java | 153 +++++++----------- 2 files changed, 76 insertions(+), 91 deletions(-) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/CommandManagerImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/CommandManagerImpl.java index 908b3544d2..96770a99b0 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/CommandManagerImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/CommandManagerImpl.java @@ -87,6 +87,7 @@ public class CommandManagerImpl implements CommandManager, WsAgentComponent { this.commandNameGenerator = commandNameGenerator; commands = new HashMap<>(); + registerNative(); } @Override @@ -402,4 +403,17 @@ public class CommandManagerImpl implements CommandManager, WsAgentComponent { private void notifyCommandUpdated(CommandImpl prevCommand, CommandImpl command) { eventBus.fireEvent(new CommandUpdatedEvent(prevCommand, command)); } + + /* Expose Command Manager's internal API to the world, to allow selenium tests or clients that use IDE to refresh commands. */ + private native void registerNative() /*-{ + var that = this; + + var CommandManager = {}; + + CommandManager.refresh = $entry(function () { + that.@org.eclipse.che.ide.command.manager.CommandManagerImpl::fetchCommands()(); + }); + + $wnd.IDE.CommandManager = CommandManager; + }-*/; } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerPresenter.java index 6f4145f8f8..932e6943b3 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerPresenter.java @@ -30,7 +30,6 @@ import org.eclipse.che.ide.api.data.tree.TreeExpander; import org.eclipse.che.ide.api.data.tree.settings.NodeSettings; import org.eclipse.che.ide.api.data.tree.settings.SettingsProvider; import org.eclipse.che.ide.api.extension.ExtensionsInitializedEvent; -import org.eclipse.che.ide.api.extension.ExtensionsInitializedEvent.ExtensionsInitializedHandler; import org.eclipse.che.ide.api.mvp.View; import org.eclipse.che.ide.api.parts.PartStack; import org.eclipse.che.ide.api.parts.PartStackType; @@ -54,12 +53,6 @@ import org.eclipse.che.ide.resources.reveal.RevealResourceEvent; import org.eclipse.che.ide.resources.tree.ResourceNode; 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.providers.DynaObject; import org.vectomatic.dom.svg.ui.SVGResource; @@ -96,6 +89,7 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel private final CoreLocalizationConstant locale; private final Resources resources; private final TreeExpander treeExpander; + private final AppContext appContext; private final RequestTransmitter requestTransmitter; private final DtoFactory dtoFactory; private UpdateTask updateTask = new UpdateTask(); @@ -103,22 +97,23 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel private boolean hiddenFilesAreShown; @Inject - public ProjectExplorerPresenter(final ProjectExplorerView view, - final EventBus eventBus, - final CoreLocalizationConstant locale, - final Resources resources, - final ResourceNode.NodeFactory nodeFactory, - final SettingsProvider settingsProvider, - final AppContext appContext, - final Provider workspaceAgentProvider, - final RequestTransmitter requestTransmitter, - final DtoFactory dtoFactory) { + public ProjectExplorerPresenter(ProjectExplorerView view, + EventBus eventBus, + CoreLocalizationConstant locale, + Resources resources, + ResourceNode.NodeFactory nodeFactory, + SettingsProvider settingsProvider, + AppContext appContext, + Provider workspaceAgentProvider, + RequestTransmitter requestTransmitter, + DtoFactory dtoFactory) { this.view = view; this.eventBus = eventBus; this.nodeFactory = nodeFactory; this.settingsProvider = settingsProvider; this.locale = locale; this.resources = resources; + this.appContext = appContext; this.requestTransmitter = requestTransmitter; this.dtoFactory = dtoFactory; this.view.setDelegate(this); @@ -126,40 +121,22 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel eventBus.addHandler(ResourceChangedEvent.getType(), this); eventBus.addHandler(MarkerChangedEvent.getType(), this); eventBus.addHandler(SyntheticNodeUpdateEvent.getType(), this); - eventBus.addHandler(WorkspaceStoppedEvent.TYPE, new WorkspaceStoppedEvent.Handler() { - @Override - public void onWorkspaceStopped(WorkspaceStoppedEvent event) { - getTree().getNodeStorage().clear(); + eventBus.addHandler(WorkspaceStoppedEvent.TYPE, event -> getTree().getNodeStorage().clear()); + + view.getTree().getSelectionModel().addSelectionChangedHandler(event -> setSelection(new Selection<>(event.getSelection()))); + + view.getTree().addBeforeExpandHandler(event -> { + NodeDescriptor nodeDescriptor = view.getTree().getNodeDescriptor(event.getNode()); + + if (event.getNode() instanceof SyntheticNode && nodeDescriptor != null && nodeDescriptor.isExpandDeep()) { + event.setCancelled(true); } }); - view.getTree().getSelectionModel().addSelectionChangedHandler(new SelectionChangedHandler() { - @Override - public void onSelectionChanged(SelectionChangedEvent event) { - setSelection(new Selection<>(event.getSelection())); - } - }); - - view.getTree().addBeforeExpandHandler(new BeforeExpandNodeEvent.BeforeExpandNodeHandler() { - @Override - public void onBeforeExpand(BeforeExpandNodeEvent event) { - final NodeDescriptor nodeDescriptor = view.getTree().getNodeDescriptor(event.getNode()); - - if (event.getNode() instanceof SyntheticNode && nodeDescriptor != null && nodeDescriptor.isExpandDeep()) { - event.setCancelled(true); - } - } - }); - - view.getTree().getNodeLoader().addPostLoadHandler(new PostLoadEvent.PostLoadHandler() { - @Override - public void onPostLoad(PostLoadEvent event) { - for (Node node : event.getReceivedNodes()) { - - if (node instanceof ResourceNode && expandQueue.remove(((ResourceNode)node).getData().getLocation())) { - view.getTree().setExpanded(node, true); - } - + view.getTree().getNodeLoader().addPostLoadHandler(event -> { + for (Node node : event.getReceivedNodes()) { + if (node instanceof ResourceNode && expandQueue.remove(((ResourceNode)node).getData().getLocation())) { + view.getTree().setExpanded(node, true); } } }); @@ -169,21 +146,13 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel registerNative(); // when ide has already initialized, then we force set focus to the current part - eventBus.addHandler(ExtensionsInitializedEvent.getType(), new ExtensionsInitializedHandler() { - @Override - public void onExtensionsInitialized(ExtensionsInitializedEvent event) { - partStack.setActivePart(ProjectExplorerPresenter.this); - } - }); + eventBus.addHandler(ExtensionsInitializedEvent.getType(), event -> partStack.setActivePart(ProjectExplorerPresenter.this)); - Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { - @Override - public void execute() { - final PartStack partStack = checkNotNull(workspaceAgentProvider.get().getPartStack(PartStackType.NAVIGATION), - "Navigation part stack should not be a null"); - partStack.addPart(ProjectExplorerPresenter.this); - partStack.setActivePart(ProjectExplorerPresenter.this); - } + Scheduler.get().scheduleDeferred(() -> { + PartStack partStack = checkNotNull(workspaceAgentProvider.get().getPartStack(PartStackType.NAVIGATION), + "Navigation part stack should not be a null"); + partStack.addPart(ProjectExplorerPresenter.this); + partStack.setActivePart(ProjectExplorerPresenter.this); }); } @@ -192,41 +161,35 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel 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(); + getTree().addExpandHandler(event -> { + Node node = event.getNode(); - if (node instanceof ResourceNode) { - Resource data = ((ResourceNode)node).getData(); - requestTransmitter.newRequest() - .endpointId(endpointId) - .methodName(method) - .paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class) - .withPath(data.getLocation().toString()) - .withType(START)) - .sendAndSkipResult(); + if (node instanceof ResourceNode) { + Resource data = ((ResourceNode)node).getData(); + requestTransmitter.newRequest() + .endpointId(endpointId) + .methodName(method) + .paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class) + .withPath(data.getLocation().toString()) + .withType(START)) + .sendAndSkipResult(); - } } }); - getTree().addCollapseHandler(new CollapseNodeEvent.CollapseNodeHandler() { - @Override - public void onCollapse(CollapseNodeEvent event) { - Node node = event.getNode(); + getTree().addCollapseHandler(event -> { + Node node = event.getNode(); - if (node instanceof ResourceNode) { - Resource data = ((ResourceNode)node).getData(); - requestTransmitter.newRequest() - .endpointId(endpointId) - .methodName(method) - .paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class) - .withPath(data.getLocation().toString()) - .withType(STOP)) - .sendAndSkipResult(); + if (node instanceof ResourceNode) { + Resource data = ((ResourceNode)node).getData(); + requestTransmitter.newRequest() + .endpointId(endpointId) + .methodName(method) + .paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class) + .withPath(data.getLocation().toString()) + .withType(STOP)) + .sendAndSkipResult(); - } } }); } @@ -247,7 +210,11 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel ProjectExplorer.reveal = $entry(function (path) { that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doReveal(*)(path); - }) + }); + + ProjectExplorer.refresh = $entry(function () { + that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doRefresh()(); + }); $wnd.IDE.ProjectExplorer = ProjectExplorer; }-*/; @@ -268,6 +235,10 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel eventBus.fireEvent(new RevealResourceEvent(Path.valueOf(path))); } + private void doRefresh() { + appContext.getWorkspaceRoot().synchronize(); + } + @Override @SuppressWarnings("unchecked") public void onResourceChanged(ResourceChangedEvent event) { From 035fed1a0709ef1a0542b2ed1983c5e855772e48 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Tue, 4 Jul 2017 13:55:30 +0100 Subject: [PATCH 05/11] Fix broken links to che-docs (#5531) See che-docs#149 Signed-off-by: Jonah Graham --- samples/sample-plugin-json/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/sample-plugin-json/README.md b/samples/sample-plugin-json/README.md index 56a76290b4..9d0ceaadd1 100644 --- a/samples/sample-plugin-json/README.md +++ b/samples/sample-plugin-json/README.md @@ -1,11 +1,11 @@ ## Description -The **JSON Example** is a providing a plugin sample which is use as a continuous example in the plugin documentation. You can learn more about it at: https://www.eclipse.org/che/docs/plugins/introduction/index.html#the-json-example +The **JSON Example** is a providing a plugin sample which is use as a continuous example in the plugin documentation. You can learn more about it at: https://www.eclipse.org/che/docs/assemblies/intro/index.html This sample demonstrate how to extend the Eclipse Che in various ways: -- How to register a new file type and add code completion (Read the tutorial at:https://www.eclipse.org/che/docs/plugins/code-editors/index.html#code-completion) +- How to register a new file type and add code completion (Read the tutorial at:https://www.eclipse.org/che/docs/assemblies/sdk-code-editors/index.html#code-completion) -- How to define a custom project type with project creation wizard and register project-specific actions (Read the tutorial at: https://www.eclipse.org/che/docs/plugins/project-types/index.html) +- How to define a custom project type with project creation wizard and register project-specific actions (Read the tutorial at: https://www.eclipse.org/che/docs/assemblies/sdk-project-types/index.html) ## How to build sample-plugin-json plugin From bb0a3f005b79c638abb889564bfd18c2d505c13a Mon Sep 17 00:00:00 2001 From: Dharmit Shah Date: Mon, 5 Jun 2017 12:02:52 +0530 Subject: [PATCH 06/11] Add CentOS based Golang stack to default assembly Signed-off-by: Dharmit Shah --- .../src/main/resources/stacks.json | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/ide/che-core-ide-stacks/src/main/resources/stacks.json b/ide/che-core-ide-stacks/src/main/resources/stacks.json index aa8dc55215..fe3a5b147a 100644 --- a/ide/che-core-ide-stacks/src/main/resources/stacks.json +++ b/ide/che-core-ide-stacks/src/main/resources/stacks.json @@ -2618,5 +2618,69 @@ } ], "creator": "Dharmit Shah" +}, +{ + "id": "centos-go", + "creator": "Dharmit Shah", + "name": "CentOS Go", + "description": "CentOS based Go Stack", + "scope": "advanced", + "tags": [ + "CentOS", + "Go" + ], + "components": [ + { + "name": "CentOS", + "version": "7.3" + }, + { + "name": "Go", + "version": "1.6.2" + } + ], + "source": { + "type": "image", + "origin": "registry.centos.org/che-stacks/centos-go" + }, + "workspaceConfig": { + "environments": { + "default": { + "machines": { + "dev-machine": { + "agents": [ + "org.eclipse.che.exec", "org.eclipse.che.terminal", "org.eclipse.che.ws-agent", "org.eclipse.che.ssh" + ], + "servers": {}, + "attributes" : { + "memoryLimitBytes": "2147483648" + } + } + }, + "recipe": { + "location": "registry.centos.org/che-stacks/centos-go", + "type": "dockerimage" + } + } + }, + "name": "default", + "defaultEnv": "default", + "description": null, + "commands": [ + { + "name": "run", + "type": "custom", + "commandLine": "cd ${current.project.path} && go get -d && go run main.go", + "attributes": { + "previewUrl": "http://${server.port.8080}", + "goal": "Run" + } + } + ] + }, + "stackIcon": { + "name": "type-go.svg", + "mediaType": "image/svg+xml" + } } ] From ea372fbb9eb545bebfb372099d275843e3c4bf7e Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Tue, 4 Jul 2017 18:01:18 +0300 Subject: [PATCH 07/11] This PR fixes #5528 (#5533) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Check LS launcher for ability to launch * This PR fixes #5528 by filtering contributed languages and launchers for their ability to launch. Signed-off-by: Thomas Mäder Signed-off-by: Vitalii Parfonov --- .../registry/LanguageServerRegistryImpl.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/LanguageServerRegistryImpl.java b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/LanguageServerRegistryImpl.java index 59a255b351..e32bd2e65f 100644 --- a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/LanguageServerRegistryImpl.java +++ b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/LanguageServerRegistryImpl.java @@ -13,6 +13,7 @@ package org.eclipse.che.api.languageserver.registry; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; + import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.languageserver.exception.LanguageServerException; import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncher; @@ -25,39 +26,43 @@ import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.services.LanguageServer; -import java.io.File; import java.net.URI; -import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; import static org.eclipse.che.api.languageserver.shared.ProjectLangugageKey.createProjectKey; @Singleton public class LanguageServerRegistryImpl implements LanguageServerRegistry, ServerInitializerObserver { - public final static String PROJECT_FOLDER_PATH = "/projects"; + public final static String PROJECT_FOLDER_PATH = "/projects"; private final List languages; - private final Map launchers = new HashMap<>(); + private final Map launchers; /** * Started {@link LanguageServer} by project. */ - private final ConcurrentHashMap projectToServer= new ConcurrentHashMap<>(); + private final ConcurrentHashMap projectToServer = new ConcurrentHashMap<>(); private final Provider projectManagerProvider; private final ServerInitializer initializer; @Inject - public LanguageServerRegistryImpl(Set languageServerLaunchers, Set languages, - Provider projectManagerProvider, ServerInitializer initializer) { - this.languages= new ArrayList<>(languages); - this.launchers.putAll(languageServerLaunchers.stream() - .collect(Collectors.toMap(LanguageServerLauncher::getLanguageId, launcher -> launcher))); + public LanguageServerRegistryImpl(Set languageServerLaunchers, + Set languages, + Provider projectManagerProvider, + ServerInitializer initializer) { + this.launchers = languageServerLaunchers.stream() + .filter(LanguageServerLauncher::isAbleToLaunch) + .collect(toMap(LanguageServerLauncher::getLanguageId, identity())); + this.languages = languages.stream() + .filter(language -> launchers.containsKey(language.getLanguageId())) + .collect(toList()); this.projectManagerProvider = projectManagerProvider; this.initializer = initializer; this.initializer.addObserver(this); @@ -82,11 +87,11 @@ public class LanguageServerRegistryImpl implements LanguageServerRegistry, Serve } private boolean matchesExtensions(LanguageDescription language, String path) { - return language.getFileExtensions().stream().anyMatch(extension->path.endsWith(extension)); + return language.getFileExtensions().stream().anyMatch(extension -> path.endsWith(extension)); } private boolean matchesFilenames(LanguageDescription language, String path) { - return language.getFileNames().stream().anyMatch(name->path.endsWith(name)); + return language.getFileNames().stream().anyMatch(name -> path.endsWith(name)); } @Nullable @@ -120,7 +125,7 @@ public class LanguageServerRegistryImpl implements LanguageServerRegistry, Serve @Override public Map getInitializedLanguages() { Map initializedServers = initializer.getInitializedServers(); - return projectToServer.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> initializedServers.get(e.getValue()))); + return projectToServer.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> initializedServers.get(e.getValue()))); } protected String extractProjectPath(String filePath) throws LanguageServerException { From 80493203481fc6b7c3fb93890f14c25344348044 Mon Sep 17 00:00:00 2001 From: Sun Seng David TAN Date: Tue, 4 Jul 2017 18:11:32 +0200 Subject: [PATCH 08/11] Openshift connector improvements (#5052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CHE-4141 - Use Persistent Volumes Claims when creating workspaces Signed-off-by: Snjezana Peco * Implement getContainerLogs method in OpenShiftConnector Signed-off-by: Snjezana Peco * Implement createExec() and startExec() in OpenShiftConnector Add implementations of createExec() and startExec(). Since OpenShift does not separate the create and start steps, a holder class KubernetesExecHolder is necessary, to pass information between the call to createExec() (which just saves relevant information) and startExec(). Additionally, adds KubernetesOutputAdapter, which parses the output from OpenShift into LogMessages that can be handled by Che's MessageProcessor class. Signed-off-by: Angel Misevski * Add implementation of getEvents() to avoid busy wait Signed-off-by: Angel Misevski * Update Dockerfile to avoid permissions issues Signed-off-by: Mario Loriedo * Che server and workpaces exposed on the same single TCP port (#4351) Signed-off-by: Mario Loriedo * Disabling usage of user account service in openshift-connector Signed-off-by: Sun Seng David Tan * Update Docker Compose tests to fix test failure Updating to Jackson 2.7.7 causes tests in the docker compose plugin to fail. This is due to the fact that the tests expect empty values in dictionaries to be parsed as the empty string, whereas jackson 2.7.7 parses them as null (as specified by the yaml spec). Modifies the affected tests to explicitly use an empty string (i.e. "") instead of an empty value. Signed-off-by: Angel Misevski * Find an alternative to subPath in volumeMount Signed-off-by: Snjezana Peco * Setting rwx permissions for all on /data/ in case it's not mounted Signed-off-by: Mario Loriedo * Add support for resource limits when running on Openshift Add resource limits to workspace Pods when running on OpenShift. The memory limit is normally obtained from the API request to create the workspace, however it can be overridden via the property `che.openshift.workspace.memory.override`. The cpu limit used is determined by the property `che.openshift.workspace.cpu.limit`. In both cases, the value of the property is passed directly to OpenShift, so any valid quantity is acceptable (e.g. 150Mi, 1Gi, 1024, etc). Signed-off-by: Angel Misevski * Fix dockerImageConfig is null (since v1.5 of OpenShift API) Signed-off-by: Sun Seng David Tan * Add Nullable annotation to che.docker.ip.external The property che.docker.ip.external can be null, but OpenShiftConnector does not include the annotation. This prevents Che from initialising if e.g. running on docker without the property set. Signed-off-by: Angel Misevski * CHE-158 Adding TLS support for Workspace routes Signed-off-by: Ilya Buziuk * Adding property to set requests for RAM Signed-off-by: Mario Loriedo * CHE-158 Using '-' instead of '.' for generating OpenShift route Urls Signed-off-by: Ilya Buziuk * Fixing tests after changing Url generation logic Signed-off-by: Ilya Buziuk * Redirect insecure HTTP requests to TLS endpoint Signed-off-by: Mario Loriedo * CHE-180: Creating and closing OpenShiftClient in every method of OpenshiftConnector Signed-off-by: Ilya Buziuk * Update route naming to make it work on OSO Signed-off-by: Mario Loriedo * Rework PVC management on OpenShift - Change how subdirectories are created in pods to use a short, terminating job instead of a full deployment - Add OpenShiftWorkspaceFilesCleaner class to properly notice workspace deleted events - Add helper class to manage job pods. For creation, some effort is made to avoid attempting to create workspaces unnecessarily, but only exists in-memory - Workspace deletions are batched together so that removing workspaces directories can be done when server is idled, avoiding unnecessary PVC mounts - Add two new properties: che.openshift.jobs.image and che.openshift.jobs.memorylimit, which are used by OpenShiftPvcHelper to set up pods Current issues: - Since workspace directories are not deleted immediately, attempting to re-create a workspace with the same name will result in the previous instance's project to already be there. This should have a minor impact. - Memory for which workspace dirs have been created is not persisted, resulting in potentially unnecessary jobs - Openshift workspace files cleaner is included by overwriting binding in WsMasterModule instead of using a provider. This could be better, but OpenShift integration may be reaching a point where a custom module is a better solution. Signed-off-by: Angel Misevski Signed-off-by: Sun Seng David Tan * Delete ReplicaSets explicitly when shutting down a workspace Signed-off-by: Angel Misevski * Fix OpenShiftConnectorTest Signed-off-by: Mario Loriedo * Fix route server names if unknown should start with server-. https://issues.jboss.org/browse/CHE-230 Signed-off-by: Sun Seng David Tan * Add property to control manual workspace dir creation in OpenShift Add property 'che.openshift.precreate.workspace.dirs'. If property is true, OpenShiftConnector will run a pod before launching workspaces to create a subpath in the workspace's persistent volume with correct permissions. If the property is false, this step is skipped. This is necessary as in older versions of OpenShift/Kubernetes, subpaths created as part of a volume mount are created with root permissions, and so cannot be modified by workspace pods. More recent versions fix this, creating subpath volumes with correct permissions, making the step above unnecessary. Signed-off-by: Angel Misevski * CHE-102 - Idle detection of che-server and workspaces Signed-off-by: Snjezana Peco * Add and modify tests for OpenShift helper classes Add tests for the untested classes in openshift.client.kuberentes, and update existing tests where necessary. Signed-off-by: Angel Misevski * Recent changes required access to `/` which is impossible under OS Signed-off-by: David Festal * adapt che-server entrypoint.sh to environments without write permissions in '/' (#5344) * adapt che-server entrypoint.sh to environments without write permissions in '/' * CHE-280: Adding container's state info to the 'inspectContainer' API Signed-off-by: Ilya Buziuk * Factorize code of `ServerEvaluationStrategy` classes, to use the Custom strategy as the basis of other strategies (#5366) * Pull-up the local docker port management (use exposed ports) Signed-off-by: David Festal * Make all the strategies extend `CustomEvaluationStrategy` Signed-off-by: David Festal * Add a `workspaceIdWithoutPrefix` macro and use it for `single-port` This macro is based on the `workspaceId` macro, but without the `workspace` prefix. Signed-off-by: David Festal * Add the `isDevMachine` to allow conditions in the ST template. This is required to allow the `single-port` strategy to have a different url according to the type of machine. (see the work done for CHE-175 : Support multi-container workspaces on OpenShift) Signed-off-by: David Festal * Small fixes after comments from @fbenoit Signed-off-by: David Festal * Fix unnecessary space pointed out by @sunix Signed-off-by: David Festal * Remove unnecessary `else` as suggested by @sunix Signed-off-by: David Festal * Keep the method signatures compatible with the `condenvy` strategy Signed-off-by: David Festal * Align names of parameters of constructors (requested by @garagatyi) Signed-off-by: David Festal * Add a default implementation to avoid breaking the Codenvy build Signed-off-by: David Festal * Also rename the attributes Signed-off-by: David Festal * Use a constant for the `workspace` prefix string Signed-off-by: David Festal * Fix formatting as requested by @sunix Signed-off-by: David Festal * Use a constant for the `isDevMachine` macro name Signed-off-by: David Festal * Add unit tests for `workspaceIdWithoutPrefixè and `isDevMachine` macros Signed-off-by: David Festal * Another requested formatting fix Signed-off-by: David Festal * Make new tests clearer Signed-off-by: David Festal * yet another formatting request Signed-off-by: David Festal * Respect the original order of imports Signed-off-by: David Festal * remove unnecessary `toString()` Signed-off-by: David Festal * use a lowercase `S` in the `server-` prefix Signed-off-by: David Festal * Multi-container workspace Support (#5110) * Fix 2 NPE that prevented using *non-dev* additional machines In the context of https://issues.jboss.org/browse/CHE-175 Signed-off-by: David Festal * Name openshift resources based on the machine name for non-dev machines This fixes https://issues.jboss.org/browse/CHE-259 and https://issues.jboss.org/browse/CHE-258 Signed-off-by: David Festal * Fix failing Traeffik tests... ... by: - adding the new `CHE_IS_DEV_MACHINE` env variable in tests - pulling up all the `CustomServerEvaluationStrategy` features in an abstract `BaseServerEvaluationStrategy` (which all other Che strategies extend) and have the `CustomServerEvaluationStrategy` class simply extend this `BaseServerEvaluationStrategy`. Signed-off-by: David Festal * Fix tests in the LocalDockerEvaluationStrategy... ... by correctly using the boolean attribute to manage the new use-case introduced by @fbenoit in master. Signed-off-by: David Festal * Replace OSIO-specific `single-port` strategy by `docker-local-custom` This fixes redhat-developer/rh-che#113 Signed-off-by: David Festal --- .../WEB-INF/classes/codenvy/che.properties | 45 + core/che-core-api-core/pom.xml | 11 + .../che/api/core/event/ServerIdleEvent.java | 34 + dockerfiles/che/Dockerfile.centos | 3 + dockerfiles/che/entrypoint.sh | 42 +- .../che/plugin/docker/client/Exec.java | 2 +- .../compose/yaml/CommandDeserializerTest.java | 5 +- .../yaml/EnvironmentDeserializerTest.java | 4 +- .../che-plugin-docker-machine/pom.xml | 3 + .../machine/BaseServerEvaluationStrategy.java | 517 +++++++++ .../CustomServerEvaluationStrategy.java | 366 +----- .../DefaultServerEvaluationStrategy.java | 35 +- .../machine/DockerInstanceRuntimeInfo.java | 5 + .../docker/machine/DockerMachineModule.java | 1 + ...lDockerCustomServerEvaluationStrategy.java | 45 + .../LocalDockerServerEvaluationStrategy.java | 61 +- .../docker/machine/MachineProviderImpl.java | 1 + .../machine/ServerEvaluationStrategy.java | 68 +- .../machine/idle/ServerIdleDetector.java | 114 ++ .../machine/local/LocalDockerModule.java | 3 + .../CustomServerEvaluationStrategyTest.java | 69 +- ...kerCustomServerEvaluationStrategyTest.java | 158 +++ .../machine/ServerEvaluationStrategyTest.java | 11 +- .../che-plugin-openshift-client/pom.xml | 16 + .../openshift/client/OpenShiftConnector.java | 1008 +++++++++++++---- .../openshift/client/OpenShiftPvcHelper.java | 232 ++++ .../client/OpenShiftRouteCreator.java | 83 ++ .../OpenShiftWorkspaceFilesCleaner.java | 107 ++ .../kubernetes/KubernetesContainer.java | 2 +- .../kubernetes/KubernetesExecHolder.java | 56 + .../kubernetes/KubernetesLabelConverter.java | 6 + .../kubernetes/KubernetesOutputAdapter.java | 76 ++ .../client/kubernetes/KubernetesService.java | 2 +- .../client/OpenShiftConnectorTest.java | 29 +- .../OpenShiftWorkspaceFilesCleanerTest.java | 176 +++ .../kubernetes/KubernetesContainerTest.java | 4 +- .../kubernetes/KubernetesEnvVarTest.java | 2 +- .../KubernetesLabelConverterTest.java | 59 +- .../KubernetesOutputAdapterTest.java | 245 ++++ .../kubernetes/KubernetesServiceTest.java | 14 +- ...TraefikCreateContainerInterceptorTest.java | 2 +- 41 files changed, 2961 insertions(+), 761 deletions(-) create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/event/ServerIdleEvent.java create mode 100644 plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/BaseServerEvaluationStrategy.java create mode 100644 plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategy.java create mode 100644 plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/idle/ServerIdleDetector.java create mode 100644 plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategyTest.java create mode 100644 plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftPvcHelper.java create mode 100644 plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftRouteCreator.java create mode 100644 plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleaner.java create mode 100644 plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesExecHolder.java create mode 100644 plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapter.java create mode 100644 plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleanerTest.java create mode 100644 plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapterTest.java diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties index 8f875bda6f..be78e964e4 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties @@ -205,9 +205,14 @@ che.docker.ip.external=NULL # - 'docker-local': internal address is address of container within docker network, and exposed ports # are used. # - 'custom': The evaluation strategy may be customized through a template property. +# - 'docker-local-custom': internal address is set as in docker-local strategy, external address is composed +# as in the custom strategy with the 'template' and the 'external.protocol' properties. + # The 'docker-local' strategy may be useful if a firewall prevents communication between che-server and # workspace containers, but will prevent communication when che-server and workspace containers are not # on the same Docker network. +# The 'docker-local-custom' strategy may be useful when Che and the workspace servers need to be exposed on the +# same single TCP port. che.docker.server_evaluation_strategy=default @@ -298,12 +303,52 @@ che.openshift.project=eclipse-che che.openshift.serviceaccountname=cheserviceaccount che.openshift.liveness.probe.delay=300 che.openshift.liveness.probe.timeout=1 +che.openshift.workspaces.pvc.name=claim-che-workspace +che.openshift.workspaces.pvc.quantity=10Gi +# Create secure route against HTTPS +# NOTE: In order to create routes against HTTPS +# Property 'strategy.che.docker.server_evaluation_strategy.secure.external.urls' should be also set to true +che.openshift.secure.routes=false +# Pod that is launched when performing persistent volume claim maintenance jobs on OpenShift +che.openshift.jobs.image=centos:centos7 +che.openshift.jobs.memorylimit=250Mi + +# Run job to create workspace subpath directories in persistent volume before launching workspace. +# Necessary in some versions of OpenShift/Kubernetes as workspace subpath volumemounts are created +# with root permissions, and thus cannot be modified by workspaces running as user (presents as error +# importing projects into workspace in Che). Default is "true", but should be set to false if version +# of Openshift/Kubernetes creates subdirectories with user permissions. +# Relevant issue: https://github.com/kubernetes/kubernetes/issues/41638 +che.openshift.precreate.workspace.dirs=true + +# Specifications of compute resources that can be consumed +# by the workspace container: +# +# - Amount of memory required for a workspace container to run e.g. 512Mi +che.openshift.workspace.memory.request=NULL +# +# - Maximum amount of memory a workspace container can use e.g. 1.3Gi +che.openshift.workspace.memory.override=NULL + +# The Openshift will idle the server if no workspace is run for +# this length of time. +che.openshift.server.inactive.stop.timeout.ms=1800000 + +# +# +# Be aware that setting che.openshift.workspace.memory.override +# will override Che memory limits +# +# More information about setting Compute Resources in OpenShift can be +# found here: https://docs.openshift.org/latest/dev_guide/compute_resources.html#dev-compute-resources # Which implementation of DockerConnector to use in managing containers. In general, # the base implementation of DockerConnector is appropriate, but OpenShiftConnector # is necessary for deploying Che on OpenShift. Options: # - 'default' : Use DockerConnector # - 'openshift' : use OpenShiftConnector +# Note that if 'openshift' connector is used, the property che.docker.ip.external +# MUST be set. che.docker.connector=default # Defines whether stacks loaded once or each time server starts. diff --git a/core/che-core-api-core/pom.xml b/core/che-core-api-core/pom.xml index b2978ed389..2cabd3299a 100644 --- a/core/che-core-api-core/pom.xml +++ b/core/che-core-api-core/pom.xml @@ -255,6 +255,17 @@ + + com.mycila + license-maven-plugin + + + + **/ServerIdleEvent.java + + + + diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/event/ServerIdleEvent.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/event/ServerIdleEvent.java new file mode 100644 index 0000000000..c904583f34 --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/event/ServerIdleEvent.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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.core.event; +/** + * Event informing about idling the che server. + */ +public class ServerIdleEvent { + private long timeout; + + /** + * Implements the handler to handle idling. + */ + public ServerIdleEvent(long timeout) { + super(); + this.timeout = timeout; + } + + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } +} diff --git a/dockerfiles/che/Dockerfile.centos b/dockerfiles/che/Dockerfile.centos index 2fca8eb300..3ea613af59 100644 --- a/dockerfiles/che/Dockerfile.centos +++ b/dockerfiles/che/Dockerfile.centos @@ -48,3 +48,6 @@ EXPOSE 8000 8080 COPY entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] ADD eclipse-che.tar.gz /home/user/ +RUN mkdir /logs && chmod 0777 /logs +RUN chmod -R 0777 /home/user/ +RUN mkdir /data && chmod 0777 /data diff --git a/dockerfiles/che/entrypoint.sh b/dockerfiles/che/entrypoint.sh index 964634d5a4..6ac3fda6d6 100755 --- a/dockerfiles/che/entrypoint.sh +++ b/dockerfiles/che/entrypoint.sh @@ -51,7 +51,7 @@ Variables: export CHE_REGISTRY_HOST=${CHE_REGISTRY_HOST:-${DEFAULT_CHE_REGISTRY_HOST}} DEFAULT_CHE_PORT=8080 - CHE_PORT=${CHE_PORT:-${DEFAULT_CHE_PORT}} + export CHE_PORT=${CHE_PORT:-${DEFAULT_CHE_PORT}} DEFAULT_CHE_IP= CHE_IP=${CHE_IP:-${DEFAULT_CHE_IP}} @@ -246,18 +246,40 @@ init() { fi ### Are we going to use the embedded che.properties or one provided by user?` ### CHE_LOCAL_CONF_DIR is internal Che variable that sets where to load - export CHE_LOCAL_CONF_DIR="/conf" - if [ -f "/conf/che.properties" ]; then - echo "Found custom che.properties..." - if [ "$CHE_USER" != "root" ]; then - sudo chown -R ${CHE_USER} ${CHE_LOCAL_CONF_DIR} + # check if we have permissions to create /conf folder. + if [ -w / ]; then + export CHE_LOCAL_CONF_DIR="/conf" + if [ -f "/conf/che.properties" ]; then + echo "Found custom che.properties..." + if [ "$CHE_USER" != "root" ]; then + sudo chown -R ${CHE_USER} ${CHE_LOCAL_CONF_DIR} + fi + else + if [ ! -d ${CHE_LOCAL_CONF_DIR} ]; then + mkdir -p ${CHE_LOCAL_CONF_DIR} + fi + if [ -w ${CHE_LOCAL_CONF_DIR} ];then + echo "ERROR: user ${CHE_USER} does OK have write permissions to ${CHE_LOCAL_CONF_DIR}" + echo "Using embedded che.properties... Copying template to ${CHE_LOCAL_CONF_DIR}/che.properties" + cp -rf "${CHE_HOME}/conf/che.properties" ${CHE_LOCAL_CONF_DIR}/che.properties + else + echo "ERROR: user ${CHE_USER} does not have write permissions to ${CHE_LOCAL_CONF_DIR}" + exit 1 + fi fi else - if [ ! -d /conf ]; then - mkdir -p /conf + echo "WARN: parent dir is not writeable, CHE_LOCAL_CONF_DIR will be set to ${CHE_DATA}/conf" + export CHE_LOCAL_CONF_DIR="${CHE_DATA}/conf" + if [ ! -d ${CHE_LOCAL_CONF_DIR} ]; then + mkdir -p ${CHE_LOCAL_CONF_DIR} + fi + if [ -w ${CHE_LOCAL_CONF_DIR} ];then + echo "Using embedded che.properties... Copying template to ${CHE_LOCAL_CONF_DIR}/che.properties" + cp -rf "${CHE_HOME}/conf/che.properties" ${CHE_LOCAL_CONF_DIR}/che.properties + else + echo "ERROR: user ${CHE_USER} does not have write permissions to ${CHE_LOCAL_CONF_DIR}" + exit 1 fi - echo "Using embedded che.properties... Copying template to ${CHE_LOCAL_CONF_DIR}/che.properties" - cp -rf "${CHE_HOME}/conf/che.properties" ${CHE_LOCAL_CONF_DIR}/che.properties fi # Update the provided che.properties with the location of the /data mounts diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/Exec.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/Exec.java index 8eddc50920..fda34f8e0a 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/Exec.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/Exec.java @@ -20,7 +20,7 @@ public class Exec { private final String[] command; private final String id; - Exec(String[] command, String id) { + public Exec(String[] command, String id) { this.command = command; this.id = id; } diff --git a/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/CommandDeserializerTest.java b/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/CommandDeserializerTest.java index 1b892c7966..b727f05fff 100644 --- a/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/CommandDeserializerTest.java +++ b/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/CommandDeserializerTest.java @@ -70,7 +70,8 @@ public class CommandDeserializerTest { assertEquals(environment.get("MYSQL_PASSWORD"), "password"); assertTrue(service.getExpose().containsAll(asList("4403", "5502"))); - assertEquals(service.getCommand(), commandWords); + assertTrue(service.getCommand().containsAll(commandWords)); + assertEquals(service.getCommand().size(), commandNumberOfWords); } @DataProvider(name = "validCommand") @@ -137,7 +138,7 @@ public class CommandDeserializerTest { {"\"echo ${PWD}\"", asList("echo", "${PWD}"), 2}, {"\"(Test)\"", singletonList("(Test)"), 1}, - {"", null, 1}, + {"\"\"", singletonList(""), 1}, }; } diff --git a/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/EnvironmentDeserializerTest.java b/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/EnvironmentDeserializerTest.java index 9b7d7e7ba1..609f846122 100644 --- a/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/EnvironmentDeserializerTest.java +++ b/plugins/plugin-docker/che-plugin-docker-compose/src/test/java/org/eclipse/che/plugin/docker/compose/yaml/EnvironmentDeserializerTest.java @@ -68,8 +68,8 @@ public class EnvironmentDeserializerTest { + " dev-machine: \n" + " image: codenvy/ubuntu_jdk8\n" + " environment:\n" - + " MYSQL_ROOT_PASSWORD: ", - ImmutableMap.of("MYSQL_ROOT_PASSWORD", null) + + " MYSQL_ROOT_PASSWORD: \"\"", + ImmutableMap.of("MYSQL_ROOT_PASSWORD", "") }, // dictionary format, value of variable contains colon sign diff --git a/plugins/plugin-docker/che-plugin-docker-machine/pom.xml b/plugins/plugin-docker/che-plugin-docker-machine/pom.xml index 0cf02bc035..4f6e4a6420 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/pom.xml +++ b/plugins/plugin-docker/che-plugin-docker-machine/pom.xml @@ -165,8 +165,11 @@ **/DefaultServerEvaluationStrategyTest.java **/LocalDockerServerEvaluationStrategy.java **/LocalDockerServerEvaluationStrategyTest.java + **/LocalDockerCustomServerEvaluationStrategy.java + **/LocalDockerCustomServerEvaluationStrategyTest.java **/DockerInstanceRuntimeInfo.java **/DockerInstanceRuntimeInfoTest.java + **/ServerIdleDetector.java diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/BaseServerEvaluationStrategy.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/BaseServerEvaluationStrategy.java new file mode 100644 index 0000000000..73dee6634b --- /dev/null +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/BaseServerEvaluationStrategy.java @@ -0,0 +1,517 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.docker.machine; + +import com.google.common.base.Strings; +import com.google.inject.Inject; +import com.google.inject.name.Named; + +import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl; +import org.eclipse.che.api.machine.server.model.impl.ServerImpl; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.plugin.docker.client.json.ContainerInfo; +import org.eclipse.che.plugin.docker.client.json.PortBinding; +import org.stringtemplate.v4.ST; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static com.google.common.base.Strings.isNullOrEmpty; + +/** + * Represents a server evaluation strategy for the configuration where the strategy can be customized through template properties. + * + * @author Florent Benoit + * @see ServerEvaluationStrategy + */ +public abstract class BaseServerEvaluationStrategy extends ServerEvaluationStrategy { + + /** + * Regexp to extract port (under the form 22/tcp or 4401/tcp, etc.) from label references + */ + public static final String LABEL_CHE_SERVER_REF_KEY = "^che:server:(.*):ref$"; + + /** + * Name of the property for getting the workspace ID. + */ + public static final String CHE_WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID="; + + /** + * Name of the property to get the machine name property + */ + public static final String CHE_MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME="; + + /** + * Name of the property to get the property that indicates if the machine is the dev machine + */ + public static final String CHE_IS_DEV_MACHINE_PROPERTY = "CHE_IS_DEV_MACHINE="; + + /** + * Prefix added in front of the generated name to build the workspaceId + */ + public static final String CHE_WORKSPACE_ID_PREFIX = "workspace"; + + + /** + * name of the macro that indicates if the machine is the dev machine + */ + public static final String IS_DEV_MACHINE_MACRO = "isDevMachine"; + + /** + * Used to store the address set by property {@code che.docker.ip}, if applicable. + */ + protected String cheDockerIp; + + /** + * Used to store the address set by property {@code che.docker.ip.external}. if applicable. + */ + protected String cheDockerIpExternal; + + /** + * The current port of che. + */ + private final String chePort; + + /** + * Secured or not ? (for example https vs http) + */ + private final String cheDockerCustomExternalProtocol; + + /** + * Template for external addresses. + */ + private String cheDockerCustomExternalTemplate; + + /** + * Option to enable the use of the container address, when searching for addresses. + */ + private boolean localDockerMode; + + + /** + * Option to tell if an exception should be thrown when the host defined in the `externalAddress` isn't known + * and cannot be converted into a valid IP. + */ + private boolean throwOnUnknownHost = true; + + /** + * Default constructor + */ + public BaseServerEvaluationStrategy(String cheDockerIp, + String cheDockerIpExternal, + String cheDockerCustomExternalTemplate, + String cheDockerCustomExternalProtocol, + String chePort) { + this(cheDockerIp, cheDockerIpExternal, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, false); + } + + /** + * Constructor to be called by derived strategies + */ + public BaseServerEvaluationStrategy(String cheDockerIp, + String cheDockerIpExternal, + String cheDockerCustomExternalTemplate, + String cheDockerCustomExternalProtocol, + String chePort, + boolean localDockerMode) { + this.cheDockerIp = cheDockerIp; + this.cheDockerIpExternal = cheDockerIpExternal; + this.chePort = chePort; + this.cheDockerCustomExternalTemplate = cheDockerCustomExternalTemplate; + this.cheDockerCustomExternalProtocol = cheDockerCustomExternalProtocol; + this.localDockerMode = localDockerMode; + } + + @Override + protected Map getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) { + final String internalAddressContainer = containerInfo.getNetworkSettings().getIpAddress(); + + final String internalAddress; + + if (localDockerMode) { + internalAddress = !isNullOrEmpty(internalAddressContainer) ? + internalAddressContainer : + internalHost; + } else { + internalAddress = + cheDockerIp != null ? + cheDockerIp : + internalHost; + } + + boolean useExposedPorts = localDockerMode && internalAddress != internalHost; + + return getExposedPortsToAddressPorts(internalAddress, containerInfo.getNetworkSettings().getPorts(), useExposedPorts); + } + + + /** + * Override the host for all ports by using the external template. + */ + @Override + protected Map getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) { + + // create Rendering evaluation + RenderingEvaluation renderingEvaluation = getOnlineRenderingEvaluation(containerInfo, internalHost); + + // get current ports + Map> ports = containerInfo.getNetworkSettings().getPorts(); + + if (isNullOrEmpty(cheDockerCustomExternalTemplate)) { + return getExposedPortsToAddressPorts(renderingEvaluation.getExternalAddress(), ports, false); + } + + return ports.keySet().stream() + .collect(Collectors.toMap(portKey -> portKey, + portKey -> renderingEvaluation.render(cheDockerCustomExternalTemplate, portKey))); + } + + + /** + * Constructs a map of {@link ServerImpl} from provided parameters, using selected strategy + * for evaluating addresses and ports. + * + *

Keys consist of port number and transport protocol (tcp or udp) separated by + * a forward slash (e.g. 8080/tcp) + * + * @param containerInfo + * the {@link ContainerInfo} describing the container. + * @param internalHost + * alternative hostname to use, if address cannot be obtained from containerInfo + * @param serverConfMap + * additional Map of {@link ServerConfImpl}. Configurations here override those found + * in containerInfo. + * @return a Map of the servers exposed by the container. + */ + public Map getServers(ContainerInfo containerInfo, + String internalHost, + Map serverConfMap) { + Map servers = super.getServers(containerInfo, internalHost, serverConfMap); + return servers.entrySet().stream().collect(Collectors.toMap(map -> map.getKey(), map -> updateServer(map.getValue()))); + } + + + /** + * Updates the protocol for the given server by using given protocol (like https) for http URLs. + * @param server the server to update + * @return updated server object + */ + protected ServerImpl updateServer(ServerImpl server) { + if (!Strings.isNullOrEmpty(cheDockerCustomExternalProtocol)) { + if ("http".equals(server.getProtocol())) { + server.setProtocol(cheDockerCustomExternalProtocol); + String url = server.getUrl(); + int length = "http".length(); + server.setUrl(cheDockerCustomExternalProtocol.concat(url.substring(length))); + } + } + return server; + } + + + /** + * Allow to get the rendering outside of the evaluation strategies. + * It is called online as in this case we have access to container info + */ + public RenderingEvaluation getOnlineRenderingEvaluation(ContainerInfo containerInfo, String internalHost) { + return new OnlineRenderingEvaluation(containerInfo).withInternalHost(internalHost); + } + + /** + * Allow to get the rendering outside of the evaluation strategies. + * It is called offline as without container info, user need to provide merge of container and images data + */ + public RenderingEvaluation getOfflineRenderingEvaluation(Map labels, Set exposedPorts, String[] env) { + return new OfflineRenderingEvaluation(labels, exposedPorts, env); + } + + /** + * Simple interface for performing the rendering for a given portby using the given template + * + * @author Florent Benoit + */ + public interface RenderingEvaluation { + /** + * Gets the template rendering for the given port and using the given template + * + * @param template + * which can include + * @param port + * the port for the mapping + * @return the rendering of the template + */ + String render(String template, String port); + + /** + * Gets default external address. + */ + String getExternalAddress(); + } + + /** + * Online implementation (using the container info) + */ + protected class OnlineRenderingEvaluation extends OfflineRenderingEvaluation implements RenderingEvaluation { + + private String gatewayAddressContainer; + private String internalHost; + + protected OnlineRenderingEvaluation(ContainerInfo containerInfo) { + super(containerInfo.getConfig().getLabels(), containerInfo.getConfig().getExposedPorts().keySet(), + containerInfo.getConfig().getEnv()); + this.gatewayAddressContainer = containerInfo.getNetworkSettings().getGateway(); + } + + protected OnlineRenderingEvaluation withInternalHost(String internalHost) { + this.internalHost = internalHost; + return this; + } + + @Override + public String getExternalAddress() { + if (localDockerMode) { + return cheDockerIpExternal != null ? + cheDockerIpExternal : + !isNullOrEmpty(gatewayAddressContainer) ? + gatewayAddressContainer : + this.internalHost; + } + + return cheDockerIpExternal != null ? + cheDockerIpExternal : + cheDockerIp != null ? + cheDockerIp : + !isNullOrEmpty(gatewayAddressContainer) ? + gatewayAddressContainer : + this.internalHost; + + } + } + + /** + * Offline implementation (container not yet created) + */ + protected class OfflineRenderingEvaluation extends DefaultRenderingEvaluation implements RenderingEvaluation { + + public OfflineRenderingEvaluation(Map labels, Set exposedPorts, String[] env) { + super(labels, exposedPorts, env); + } + } + + /** + * Inner class used to perform the rendering + */ + protected abstract class DefaultRenderingEvaluation implements RenderingEvaluation { + + /** + * Labels + */ + private Map labels; + + /** + * Ports + */ + private Set exposedPorts; + + /** + * Environment variables + */ + private final String[] env; + + /** + * Map with properties for all ports + */ + private Map globalPropertiesMap = new HashMap<>(); + + /** + * Mapping between a port and the server ref name + */ + private Map portsToRefName; + + /** + * Data initialized ? + */ + private boolean initialized; + + /** + * Default constructor. + */ + protected DefaultRenderingEvaluation(Map labels, Set exposedPorts, String[] env) { + this.labels = labels; + this.exposedPorts = exposedPorts; + this.env = env; + } + + /** + * Initialize data + */ + protected void init() { + this.initPortMapping(); + this.populateGlobalProperties(); + } + + /** + * Compute port mapping with server ref name + */ + protected void initPortMapping() { + // ok, so now we have a map of labels and a map of exposed ports + // need to extract the name of the ref (if defined in a label) or then pickup default name "Server--" + Pattern pattern = Pattern.compile(LABEL_CHE_SERVER_REF_KEY); + Map portsToKnownRefName = labels.entrySet().stream() + .filter(map -> pattern.matcher(map.getKey()).matches()) + .collect(Collectors.toMap(p -> { + Matcher matcher = pattern.matcher(p.getKey()); + matcher.matches(); + String val = matcher.group(1); + return val.contains("/") ? val : val.concat("/tcp"); + }, p -> p.getValue())); + + // add to this map only port without a known ref name + Map portsToUnkownRefName = + exposedPorts.stream().filter((port) -> !portsToKnownRefName.containsKey(port)) + .collect(Collectors.toMap(p -> p, p -> "server-" + p.replace('/', '-'))); + + // list of all ports with refName (known/unknown) + this.portsToRefName = new HashMap(portsToKnownRefName); + portsToRefName.putAll(portsToUnkownRefName); + } + + /** + * Gets default external address. + */ + public String getExternalAddress() { + return cheDockerIpExternal != null ? + cheDockerIpExternal : cheDockerIp; + } + + /** + * Populate the template properties + */ + protected void populateGlobalProperties() { + String externalAddress = getExternalAddress(); + String externalIP = getExternalIp(externalAddress); + globalPropertiesMap.put("internalIp", cheDockerIp); + globalPropertiesMap.put("externalAddress", externalAddress); + globalPropertiesMap.put("externalIP", externalIP); + globalPropertiesMap.put("workspaceId", getWorkspaceId()); + globalPropertiesMap.put("workspaceIdWithoutPrefix", getWorkspaceId().replaceFirst(CHE_WORKSPACE_ID_PREFIX,"")); + globalPropertiesMap.put("machineName", getMachineName()); + globalPropertiesMap.put("wildcardNipDomain", getWildcardNipDomain(externalAddress)); + globalPropertiesMap.put("wildcardXipDomain", getWildcardXipDomain(externalAddress)); + globalPropertiesMap.put("chePort", chePort); + globalPropertiesMap.put(IS_DEV_MACHINE_MACRO, getIsDevMachine()); + } + + /** + * Rendering + */ + @Override + public String render(String template, String port) { + if (!this.initialized) { + init(); + this.initialized = true; + } + ST stringTemplate = new ST(template); + globalPropertiesMap.forEach((key, value) -> stringTemplate.add(key, + IS_DEV_MACHINE_MACRO.equals(key) ? + Boolean.parseBoolean(value) + : value)); + stringTemplate.add("serverName", portsToRefName.get(port)); + return stringTemplate.render(); + } + + /** + * returns if the current machine is the dev machine + * + * @return true if the curent machine is the dev machine + */ + protected String getIsDevMachine() { + return Arrays.stream(env).filter(env -> env.startsWith(CHE_IS_DEV_MACHINE_PROPERTY)) + .map(s -> s.substring(CHE_IS_DEV_MACHINE_PROPERTY.length())) + .findFirst().get(); + } + + /** + * Gets the workspace ID from the config of the given container + * + * @return workspace ID + */ + protected String getWorkspaceId() { + return Arrays.stream(env).filter(env -> env.startsWith(CHE_WORKSPACE_ID_PROPERTY)) + .map(s -> s.substring(CHE_WORKSPACE_ID_PROPERTY.length())) + .findFirst().get(); + } + + /** + * Gets the workspace Machine Name from the config of the given container + * + * @return machine name of the workspace + */ + protected String getMachineName() { + return Arrays.stream(env).filter(env -> env.startsWith(CHE_MACHINE_NAME_PROPERTY)) + .map(s -> s.substring(CHE_MACHINE_NAME_PROPERTY.length())) + .findFirst().get(); + } + + /** + * Gets the IP address of the external address + * + * @return IP Address + */ + protected String getExternalIp(String externalAddress) { + try { + return InetAddress.getByName(externalAddress).getHostAddress(); + } catch (UnknownHostException e) { + if (throwOnUnknownHost) { + throw new UnsupportedOperationException("Unable to find the IP for the address '" + externalAddress + "'", e); + } + } + return null; + } + + /** + * Gets a Wildcard domain based on the ip using an external provider nip.io + * + * @return wildcard domain + */ + protected String getWildcardNipDomain(String externalAddress) { + return String.format("%s.%s", getExternalIp(externalAddress), "nip.io"); + } + + /** + * Gets a Wildcard domain based on the ip using an external provider xip.io + * + * @return wildcard domain + */ + protected String getWildcardXipDomain(String externalAddress) { + return String.format("%s.%s", getExternalIp(externalAddress), "xip.io"); + } + + } + + @Override + protected boolean useHttpsForExternalUrls() { + return "https".equals(cheDockerCustomExternalProtocol); + } + + public BaseServerEvaluationStrategy withThrowOnUnknownHost(boolean throwOnUnknownHost) { + this.throwOnUnknownHost = throwOnUnknownHost; + return this; + } +} diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategy.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategy.java index 07086fbb1c..314a88c96b 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategy.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategy.java @@ -10,29 +10,10 @@ *******************************************************************************/ package org.eclipse.che.plugin.docker.machine; -import com.google.common.base.Strings; import com.google.inject.Inject; import com.google.inject.name.Named; -import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl; -import org.eclipse.che.api.machine.server.model.impl.ServerImpl; import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.plugin.docker.client.json.ContainerInfo; -import org.eclipse.che.plugin.docker.client.json.PortBinding; -import org.stringtemplate.v4.ST; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static com.google.common.base.Strings.isNullOrEmpty; /** * Represents a server evaluation strategy for the configuration where the strategy can be customized through template properties. @@ -40,39 +21,7 @@ import static com.google.common.base.Strings.isNullOrEmpty; * @author Florent Benoit * @see ServerEvaluationStrategy */ -public class CustomServerEvaluationStrategy extends DefaultServerEvaluationStrategy { - - /** - * Regexp to extract port (under the form 22/tcp or 4401/tcp, etc.) from label references - */ - public static final String LABEL_CHE_SERVER_REF_KEY = "^che:server:(.*):ref$"; - - /** - * Name of the property for getting the workspace ID. - */ - public static final String CHE_WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID="; - - /** - * Name of the property to get the machine name property - */ - public static final String CHE_MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME="; - - /** - * The current port of che. - */ - private final String chePort; - - /** - * Secured or not ? (for example https vs http) - */ - private final String cheDockerCustomExternalProtocol; - - /** - * Template for external addresses. - */ - private String cheDockerCustomExternalTemplate; - - +public class CustomServerEvaluationStrategy extends BaseServerEvaluationStrategy { /** * Default constructor */ @@ -82,317 +31,6 @@ public class CustomServerEvaluationStrategy extends DefaultServerEvaluationStrat @Nullable @Named("che.docker.server_evaluation_strategy.custom.template") String cheDockerCustomExternalTemplate, @Nullable @Named("che.docker.server_evaluation_strategy.custom.external.protocol") String cheDockerCustomExternalProtocol, @Named("che.port") String chePort) { - super(cheDockerIp, cheDockerIpExternal); - this.chePort = chePort; - this.cheDockerCustomExternalTemplate = cheDockerCustomExternalTemplate; - this.cheDockerCustomExternalProtocol = cheDockerCustomExternalProtocol; + super(cheDockerIp, cheDockerIpExternal, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, false); } - - /** - * Override the host for all ports by using the external template. - */ - @Override - protected Map getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) { - - // create Rendering evaluation - RenderingEvaluation renderingEvaluation = getOnlineRenderingEvaluation(containerInfo, internalHost); - - // get current ports - Map> ports = containerInfo.getNetworkSettings().getPorts(); - - return ports.keySet().stream() - .collect(Collectors.toMap(portKey -> portKey, - portKey -> renderingEvaluation.render(cheDockerCustomExternalTemplate, portKey))); - } - - - /** - * Constructs a map of {@link ServerImpl} from provided parameters, using selected strategy - * for evaluating addresses and ports. - * - *

Keys consist of port number and transport protocol (tcp or udp) separated by - * a forward slash (e.g. 8080/tcp) - * - * @param containerInfo - * the {@link ContainerInfo} describing the container. - * @param internalHost - * alternative hostname to use, if address cannot be obtained from containerInfo - * @param serverConfMap - * additional Map of {@link ServerConfImpl}. Configurations here override those found - * in containerInfo. - * @return a Map of the servers exposed by the container. - */ - public Map getServers(ContainerInfo containerInfo, - String internalHost, - Map serverConfMap) { - Map servers = super.getServers(containerInfo, internalHost, serverConfMap); - return servers.entrySet().stream().collect(Collectors.toMap(map -> map.getKey(), map -> updateServer(map.getValue()))); - } - - - /** - * Updates the protocol for the given server by using given protocol (like https) for http URLs. - * @param server the server to update - * @return updated server object - */ - protected ServerImpl updateServer(ServerImpl server) { - if (!Strings.isNullOrEmpty(cheDockerCustomExternalProtocol)) { - if ("http".equals(server.getProtocol())) { - server.setProtocol(cheDockerCustomExternalProtocol); - String url = server.getUrl(); - int length = "http".length(); - server.setUrl(cheDockerCustomExternalProtocol.concat(url.substring(length))); - } - } - return server; - } - - - /** - * Allow to get the rendering outside of the evaluation strategies. - * It is called online as in this case we have access to container info - */ - public RenderingEvaluation getOnlineRenderingEvaluation(ContainerInfo containerInfo, String internalHost) { - return new OnlineRenderingEvaluation(containerInfo).withInternalHost(internalHost); - } - - /** - * Allow to get the rendering outside of the evaluation strategies. - * It is called offline as without container info, user need to provide merge of container and images data - */ - public RenderingEvaluation getOfflineRenderingEvaluation(Map labels, Set exposedPorts, String[] env) { - return new OfflineRenderingEvaluation(labels, exposedPorts, env); - } - - /** - * Simple interface for performing the rendering for a given portby using the given template - * - * @author Florent Benoit - */ - public interface RenderingEvaluation { - /** - * Gets the template rendering for the given port and using the given template - * - * @param template - * which can include - * @param port - * the port for the mapping - * @return the rendering of the template - */ - String render(String template, String port); - } - - /** - * Online implementation (using the container info) - */ - protected class OnlineRenderingEvaluation extends OfflineRenderingEvaluation implements RenderingEvaluation { - - private String gatewayAddressContainer; - private String internalHost; - - protected OnlineRenderingEvaluation(ContainerInfo containerInfo) { - super(containerInfo.getConfig().getLabels(), containerInfo.getConfig().getExposedPorts().keySet(), - containerInfo.getConfig().getEnv()); - this.gatewayAddressContainer = containerInfo.getNetworkSettings().getGateway(); - } - - protected OnlineRenderingEvaluation withInternalHost(String internalHost) { - this.internalHost = internalHost; - return this; - } - - @Override - protected String getExternalAddress() { - return externalAddressProperty != null ? - externalAddressProperty : - internalAddressProperty != null ? - internalAddressProperty : - !isNullOrEmpty(gatewayAddressContainer) ? - gatewayAddressContainer : - this.internalHost; - } - } - - /** - * Offline implementation (container not yet created) - */ - protected class OfflineRenderingEvaluation extends DefaultRenderingEvaluation implements RenderingEvaluation { - - public OfflineRenderingEvaluation(Map labels, Set exposedPorts, String[] env) { - super(labels, exposedPorts, env); - } - } - - /** - * Inner class used to perform the rendering - */ - protected abstract class DefaultRenderingEvaluation implements RenderingEvaluation { - - /** - * Labels - */ - private Map labels; - - /** - * Ports - */ - private Set exposedPorts; - - /** - * Environment variables - */ - private final String[] env; - - /** - * Map with properties for all ports - */ - private Map globalPropertiesMap = new HashMap<>(); - - /** - * Mapping between a port and the server ref name - */ - private Map portsToRefName; - - /** - * Data initialized ? - */ - private boolean initialized; - - /** - * Default constructor. - */ - protected DefaultRenderingEvaluation(Map labels, Set exposedPorts, String[] env) { - this.labels = labels; - this.exposedPorts = exposedPorts; - this.env = env; - } - - /** - * Initialize data - */ - protected void init() { - this.initPortMapping(); - this.populateGlobalProperties(); - } - - /** - * Compute port mapping with server ref name - */ - protected void initPortMapping() { - // ok, so now we have a map of labels and a map of exposed ports - // need to extract the name of the ref (if defined in a label) or then pickup default name "Server--" - Pattern pattern = Pattern.compile(LABEL_CHE_SERVER_REF_KEY); - Map portsToKnownRefName = labels.entrySet().stream() - .filter(map -> pattern.matcher(map.getKey()).matches()) - .collect(Collectors.toMap(p -> { - Matcher matcher = pattern.matcher(p.getKey()); - matcher.matches(); - String val = matcher.group(1); - return val.contains("/") ? val : val.concat("/tcp"); - }, p -> p.getValue())); - - // add to this map only port without a known ref name - Map portsToUnkownRefName = - exposedPorts.stream().filter((port) -> !portsToKnownRefName.containsKey(port)) - .collect(Collectors.toMap(p -> p, p -> "Server-" + p.replace('/', '-'))); - - // list of all ports with refName (known/unknown) - this.portsToRefName = new HashMap(portsToKnownRefName); - portsToRefName.putAll(portsToUnkownRefName); - } - - /** - * Gets default external address. - */ - protected String getExternalAddress() { - return externalAddressProperty != null ? - externalAddressProperty : internalAddressProperty; - } - - /** - * Populate the template properties - */ - protected void populateGlobalProperties() { - String externalAddress = getExternalAddress(); - String externalIP = getExternalIp(externalAddress); - globalPropertiesMap.put("internalIp", internalAddressProperty); - globalPropertiesMap.put("externalAddress", externalAddress); - globalPropertiesMap.put("externalIP", externalIP); - globalPropertiesMap.put("workspaceId", getWorkspaceId()); - globalPropertiesMap.put("machineName", getMachineName()); - globalPropertiesMap.put("wildcardNipDomain", getWildcardNipDomain(externalAddress)); - globalPropertiesMap.put("wildcardXipDomain", getWildcardXipDomain(externalAddress)); - globalPropertiesMap.put("chePort", chePort); - } - - /** - * Rendering - */ - @Override - public String render(String template, String port) { - if (!this.initialized) { - init(); - this.initialized = true; - } - ST stringTemplate = new ST(template); - globalPropertiesMap.forEach((key, value) -> stringTemplate.add(key, value)); - stringTemplate.add("serverName", portsToRefName.get(port)); - return stringTemplate.render(); - } - - /** - * Gets the workspace ID from the config of the given container - * - * @return workspace ID - */ - protected String getWorkspaceId() { - return Arrays.stream(env).filter(env -> env.startsWith(CHE_WORKSPACE_ID_PROPERTY)) - .map(s -> s.substring(CHE_WORKSPACE_ID_PROPERTY.length())) - .findFirst().get(); - } - - /** - * Gets the workspace Machine Name from the config of the given container - * - * @return machine name of the workspace - */ - protected String getMachineName() { - return Arrays.stream(env).filter(env -> env.startsWith(CHE_MACHINE_NAME_PROPERTY)) - .map(s -> s.substring(CHE_MACHINE_NAME_PROPERTY.length())) - .findFirst().get(); - } - - /** - * Gets the IP address of the external address - * - * @return IP Address - */ - protected String getExternalIp(String externalAddress) { - try { - return InetAddress.getByName(externalAddress).getHostAddress(); - } catch (UnknownHostException e) { - throw new UnsupportedOperationException("Unable to find the IP for the address '" + externalAddress + "'", e); - } - } - - /** - * Gets a Wildcard domain based on the ip using an external provider nip.io - * - * @return wildcard domain - */ - protected String getWildcardNipDomain(String externalAddress) { - return String.format("%s.%s", getExternalIp(externalAddress), "nip.io"); - } - - /** - * Gets a Wildcard domain based on the ip using an external provider xip.io - * - * @return wildcard domain - */ - protected String getWildcardXipDomain(String externalAddress) { - return String.format("%s.%s", getExternalIp(externalAddress), "xip.io"); - } - - } - } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DefaultServerEvaluationStrategy.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DefaultServerEvaluationStrategy.java index 1f5eba9e94..2998f72d26 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DefaultServerEvaluationStrategy.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DefaultServerEvaluationStrategy.java @@ -31,42 +31,11 @@ import java.util.Map; * @author Alexander Garagatyi * @see ServerEvaluationStrategy */ -public class DefaultServerEvaluationStrategy extends ServerEvaluationStrategy { - - /** - * Used to store the address set by property {@code che.docker.ip}, if applicable. - */ - protected String internalAddressProperty; - - /** - * Used to store the address set by property {@code che.docker.ip.external}. if applicable. - */ - protected String externalAddressProperty; +public class DefaultServerEvaluationStrategy extends BaseServerEvaluationStrategy { @Inject public DefaultServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String internalAddress, @Nullable @Named("che.docker.ip.external") String externalAddress) { - this.internalAddressProperty = internalAddress; - this.externalAddressProperty = externalAddress; - } - - @Override - protected Map getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) { - String internalAddress = internalAddressProperty != null ? - internalAddressProperty : - internalHost; - - return getExposedPortsToAddressPorts(internalAddress, containerInfo.getNetworkSettings().getPorts()); - } - - @Override - protected Map getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) { - String externalAddress = externalAddressProperty != null ? - externalAddressProperty : - internalAddressProperty != null ? - internalAddressProperty : - internalHost; - - return super.getExposedPortsToAddressPorts(externalAddress, containerInfo.getNetworkSettings().getPorts()); + super(internalAddress, externalAddress, null, null, null, false); } } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceRuntimeInfo.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceRuntimeInfo.java index 0cb32f70ac..bb1ad21831 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceRuntimeInfo.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceRuntimeInfo.java @@ -68,6 +68,11 @@ public class DockerInstanceRuntimeInfo implements MachineRuntimeInfo { */ public static final String CHE_MACHINE_NAME = "CHE_MACHINE_NAME"; + /** + * Environment variable that will contain Name of the machine + */ + public static final String CHE_IS_DEV_MACHINE = "CHE_IS_DEV_MACHINE"; + /** * Default HOSTNAME that will be added in all docker containers that are started. This host will container the Docker host's ip * reachable inside the container. diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java index c5307e3baf..dfedab5e84 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java @@ -33,6 +33,7 @@ public class DockerMachineModule extends AbstractModule { protected void configure() { bind(org.eclipse.che.plugin.docker.machine.cleaner.DockerAbandonedResourcesCleaner.class); bind(org.eclipse.che.plugin.docker.machine.cleaner.RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber.class); + bind(org.eclipse.che.plugin.docker.machine.idle.ServerIdleDetector.class); @SuppressWarnings("unused") Multibinder devMachineEnvVars = Multibinder.newSetBinder(binder(), diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategy.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategy.java new file mode 100644 index 0000000000..22330d416e --- /dev/null +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategy.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2016-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; + +import com.google.inject.Inject; +import com.google.inject.name.Named; + +import org.eclipse.che.api.machine.server.model.impl.ServerImpl; +import org.eclipse.che.commons.annotation.Nullable; + + +/** + * Represents a server evaluation strategy for the configuration where the workspace server and workspace + * containers are running on the same Docker network and are exposed through the same single port. + * + * This server evaluation strategy will return a completed {@link ServerImpl} with internal addresses set + * as {@link LocalDockerServerEvaluationStrategy} does. Contrary external addresses will be managed by the + * `custom` evaluation strategy,and its template property `che.docker.server_evaluation_strategy.custom.template` + * + *

cheExternalAddress can be set using property {@code che.docker.ip.external}. + * This strategy is useful when Che and the workspace servers need to be exposed on the same single TCP port + * + * @author Mario Loriedo + * @see ServerEvaluationStrategy + */ +public class LocalDockerCustomServerEvaluationStrategy extends BaseServerEvaluationStrategy { + + @Inject + public LocalDockerCustomServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String internalAddress, + @Nullable @Named("che.docker.ip.external") String externalAddress, + @Nullable @Named("che.docker.server_evaluation_strategy.custom.template") String cheDockerCustomExternalTemplate, + @Nullable @Named("che.docker.server_evaluation_strategy.custom.external.protocol") String cheDockerCustomExternalProtocol, + @Named("che.port") String chePort) { + super(internalAddress, externalAddress, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, true); + } +} diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerServerEvaluationStrategy.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerServerEvaluationStrategy.java index e89e0d6439..ef37c21ead 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerServerEvaluationStrategy.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/LocalDockerServerEvaluationStrategy.java @@ -16,14 +16,9 @@ import com.google.inject.name.Named; import org.eclipse.che.api.machine.server.model.impl.ServerImpl; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.plugin.docker.client.json.ContainerInfo; -import org.eclipse.che.plugin.docker.client.json.PortBinding; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import static com.google.common.base.Strings.isNullOrEmpty; - /** * Represents a server evaluation strategy for the configuration where the workspace server and * workspace containers are running on the same Docker network. Calling @@ -36,63 +31,11 @@ import static com.google.common.base.Strings.isNullOrEmpty; * @author Angel Misevski * @see ServerEvaluationStrategy */ -public class LocalDockerServerEvaluationStrategy extends ServerEvaluationStrategy { - - /** - * Used to store the address set by property {@code che.docker.ip}, if applicable. - */ - protected String internalAddressProperty; - - /** - * Used to store the address set by property {@code che.docker.ip.external}. if applicable. - */ - protected String externalAddressProperty; +public class LocalDockerServerEvaluationStrategy extends BaseServerEvaluationStrategy { @Inject public LocalDockerServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String internalAddress, @Nullable @Named("che.docker.ip.external") String externalAddress) { - this.internalAddressProperty = internalAddress; - this.externalAddressProperty = externalAddress; - } - - @Override - protected Map getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) { - String internalAddressContainer = containerInfo.getNetworkSettings().getIpAddress(); - - String internalAddress; - boolean useExposedPorts = true; - if (!isNullOrEmpty(internalAddressContainer)) { - internalAddress = internalAddressContainer; - } else { - internalAddress = internalHost; - useExposedPorts = false; - } - - Map> portBindings = containerInfo.getNetworkSettings().getPorts(); - - Map addressesAndPorts = new HashMap<>(); - for (Map.Entry> portEntry : portBindings.entrySet()) { - String exposedPort = portEntry.getKey().split("/")[0]; - String ephemeralPort = portEntry.getValue().get(0).getHostPort(); - if (useExposedPorts) { - addressesAndPorts.put(portEntry.getKey(), internalAddress + ":" + exposedPort); - } else { - addressesAndPorts.put(portEntry.getKey(), internalAddress + ":" + ephemeralPort); - } - } - return addressesAndPorts; - } - - @Override - protected Map getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) { - String externalAddressContainer = containerInfo.getNetworkSettings().getGateway(); - - String externalAddress = externalAddressProperty != null ? - externalAddressProperty : - !isNullOrEmpty(externalAddressContainer) ? - externalAddressContainer : - internalHost; - - return getExposedPortsToAddressPorts(externalAddress, containerInfo.getNetworkSettings().getPorts()); + super(internalAddress, externalAddress, null, null, null, true); } } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/MachineProviderImpl.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/MachineProviderImpl.java index f907deab0a..085de32e76 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/MachineProviderImpl.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/MachineProviderImpl.java @@ -666,6 +666,7 @@ public class MachineProviderImpl implements MachineInstanceProvider { // register workspace ID and Machine Name env.put(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID, workspaceId); env.put(DockerInstanceRuntimeInfo.CHE_MACHINE_NAME, machineName); + env.put(DockerInstanceRuntimeInfo.CHE_IS_DEV_MACHINE, Boolean.toString(isDev)); composeService.getExpose().addAll(portsToExpose); composeService.getEnvironment().putAll(env); diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategy.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategy.java index e244ff4cae..8f2147638b 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategy.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategy.java @@ -10,6 +10,12 @@ *******************************************************************************/ package org.eclipse.che.plugin.docker.machine; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + import org.eclipse.che.api.core.model.machine.ServerProperties; import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl; import org.eclipse.che.api.machine.server.model.impl.ServerImpl; @@ -17,12 +23,6 @@ import org.eclipse.che.api.machine.server.model.impl.ServerPropertiesImpl; import org.eclipse.che.plugin.docker.client.json.ContainerInfo; import org.eclipse.che.plugin.docker.client.json.PortBinding; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - /** * Represents a strategy for resolving Servers associated with workspace containers. * Used to extract relevant information from e.g. {@link ContainerInfo} into a map of @@ -30,14 +30,26 @@ import java.util.Map; * * @author Angel Misevski * @author Alexander Garagatyi + * @author Ilya Buziuk * @see ServerEvaluationStrategyProvider */ public abstract class ServerEvaluationStrategy { + private static final String HTTP = "http"; + private static final String HTTPS = "https"; protected static final String SERVER_CONF_LABEL_REF_KEY = "che:server:%s:ref"; protected static final String SERVER_CONF_LABEL_PROTOCOL_KEY = "che:server:%s:protocol"; protected static final String SERVER_CONF_LABEL_PATH_KEY = "che:server:%s:path"; + + /** + * @return true if external addresses need to be exposed against https, false otherwise + */ + protected boolean useHttpsForExternalUrls() { + return false; + } + + /** * Gets a map of all internal addresses exposed by the container in the form of * {@code "

:"} @@ -112,7 +124,11 @@ public abstract class ServerEvaluationStrategy { // Add protocol and path to internal/external address, if applicable String internalUrl = null; String externalUrl = null; - if (serverConf.getProtocol() != null) { + + String internalProtocol = serverConf.getProtocol(); + String externalProtocol = getProtocolForExternalUrl(internalProtocol); + + if (internalProtocol != null) { String pathSuffix = serverConf.getPath(); if (pathSuffix != null && !pathSuffix.isEmpty()) { if (pathSuffix.charAt(0) != '/') { @@ -121,8 +137,9 @@ public abstract class ServerEvaluationStrategy { } else { pathSuffix = ""; } - internalUrl = serverConf.getProtocol() + "://" + internalAddressAndPort + pathSuffix; - externalUrl = serverConf.getProtocol() + "://" + externalAddressAndPort + pathSuffix; + + internalUrl = internalProtocol + "://" + internalAddressAndPort + pathSuffix; + externalUrl = externalProtocol + "://" + externalAddressAndPort + pathSuffix; } ServerProperties properties = new ServerPropertiesImpl(serverConf.getPath(), @@ -130,7 +147,7 @@ public abstract class ServerEvaluationStrategy { internalUrl); servers.put(portProtocol, new ServerImpl(serverConf.getRef(), - serverConf.getProtocol(), + externalProtocol, externalAddressAndPort, externalUrl, properties)); @@ -156,7 +173,7 @@ public abstract class ServerEvaluationStrategy { * @return {@code ServerConfImpl}, obtained from {@code serverConfMap} if possible, * or from {@code labels} if there is no entry in {@code serverConfMap}. */ - private ServerConfImpl getServerConfImpl(String portProtocol, + protected ServerConfImpl getServerConfImpl(String portProtocol, Map labels, Map serverConfMap) { // Label can be specified without protocol -- e.g. 4401 refers to 4401/tcp @@ -226,14 +243,37 @@ public abstract class ServerEvaluationStrategy { * "9090/udp" : "my-host.com:32722" * } * } + * */ - protected Map getExposedPortsToAddressPorts(String address, Map> ports) { + protected Map getExposedPortsToAddressPorts(String address, Map> ports, boolean useExposedPorts) { Map addressesAndPorts = new HashMap<>(); for (Map.Entry> portEntry : ports.entrySet()) { + String exposedPort = portEntry.getKey().split("/")[0]; // there is one value always - String port = portEntry.getValue().get(0).getHostPort(); - addressesAndPorts.put(portEntry.getKey(), address + ":" + port); + String ephemeralPort = portEntry.getValue().get(0).getHostPort(); + if (useExposedPorts) { + addressesAndPorts.put(portEntry.getKey(), address + ":" + exposedPort); + } else { + addressesAndPorts.put(portEntry.getKey(), address + ":" + ephemeralPort); + } } return addressesAndPorts; } + + protected Map getExposedPortsToAddressPorts(String address, Map> ports) { + return getExposedPortsToAddressPorts(address, ports, false); + } + + + /** + * @param protocolForInternalUrl + * @return https, if {@link #useHttpsForExternalUrls()} method in sub-class returns true and protocol for internal Url is http + */ + private String getProtocolForExternalUrl(final String protocolForInternalUrl) { + if (useHttpsForExternalUrls() && HTTP.equals(protocolForInternalUrl)) { + return HTTPS; + } + return protocolForInternalUrl; + } + } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/idle/ServerIdleDetector.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/idle/ServerIdleDetector.java new file mode 100644 index 0000000000..0694849296 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/idle/ServerIdleDetector.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * 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.idle; + +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.eclipse.che.api.core.event.ServerIdleEvent; +import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.core.notification.EventSubscriber; +import org.eclipse.che.api.workspace.server.WorkspaceManager; +import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Inject; +/** + * Notifies about idling the che server + * Fires {@link org.eclipse.che.api.core.event.ServerIdleEvent} if no workspace + * is run for che.openshift.server.inactive.stop.timeout.ms milliseconds + */ +@Singleton +public class ServerIdleDetector implements EventSubscriber { + private static final Logger LOG = LoggerFactory.getLogger(ServerIdleDetector.class); + private static final String IDLING_CHE_SERVER_SCHEDULED = "Idling che server scheduled [timeout=%s] seconds]"; + + private final long timeout; + private ScheduledFuture future; + private ScheduledExecutorService executor; + private WorkspaceManager workspaceManager; + private final EventService eventService; + + @Inject + public ServerIdleDetector(WorkspaceManager workspaceManager, + EventService eventService, + @Named("che.openshift.server.inactive.stop.timeout.ms") long timeout) { + this.timeout = timeout; + this.eventService = eventService; + this.workspaceManager = workspaceManager; + if (timeout > 0) { + this.executor = Executors.newSingleThreadScheduledExecutor(); + this.future = executor.schedule(this::run, timeout, TimeUnit.MILLISECONDS); + LOG.info(String.format(IDLING_CHE_SERVER_SCHEDULED, timeout/1000)); + } + } + + @Override + public void onEvent(WorkspaceStatusEvent event) { + if (future != null) { + String workspaceId = event.getWorkspaceId(); + switch (event.getEventType()) { + case RUNNING: + if (!future.isCancelled()) { + future.cancel(true); + LOG.info("Idling che server canceled"); + } + break; + case STOPPED: + Set ids = workspaceManager.getRunningWorkspacesIds(); + ids.remove(workspaceId); + if (ids.size() <= 0) { + if (!future.isCancelled()) { + future.cancel(true); + } + future = executor.schedule(this::run, timeout, TimeUnit.MILLISECONDS); + LOG.info(String.format(IDLING_CHE_SERVER_SCHEDULED, timeout/1000)); + } + break; + default: + break; + } + } + } + + private void run() { + Set ids = workspaceManager.getRunningWorkspacesIds(); + if (ids.size() <= 0) { + eventService.publish(new ServerIdleEvent(timeout)); + } + } + + @PostConstruct + private void subscribe() { + eventService.subscribe(this); + } + + @PreDestroy + private void unsubscribe() { + eventService.unsubscribe(this); + if (future != null && !future.isCancelled()) { + future.cancel(true); + } + if (executor != null && !executor.isShutdown()) { + executor.shutdown(); + } + } + +} diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java index c3d0cab74a..684b4d9276 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java @@ -23,6 +23,7 @@ import org.eclipse.che.plugin.docker.client.DockerConnector; import org.eclipse.che.plugin.docker.machine.DockerInstance; import org.eclipse.che.plugin.docker.machine.DockerInstanceRuntimeInfo; import org.eclipse.che.plugin.docker.machine.DockerProcess; +import org.eclipse.che.plugin.docker.machine.LocalDockerCustomServerEvaluationStrategy; import org.eclipse.che.plugin.docker.machine.ServerEvaluationStrategy; import org.eclipse.che.plugin.docker.machine.node.DockerNode; import org.eclipse.che.plugin.openshift.client.OpenShiftConnector; @@ -56,6 +57,8 @@ public class LocalDockerModule extends AbstractModule { .to(org.eclipse.che.plugin.docker.machine.DefaultServerEvaluationStrategy.class); strategies.addBinding("docker-local") .to(org.eclipse.che.plugin.docker.machine.LocalDockerServerEvaluationStrategy.class); + strategies.addBinding("docker-local-custom") + .to(LocalDockerCustomServerEvaluationStrategy.class); strategies.addBinding("custom") .to(org.eclipse.che.plugin.docker.machine.CustomServerEvaluationStrategy.class); diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategyTest.java b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategyTest.java index 1e8fc9aef0..4200cb14c2 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategyTest.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/CustomServerEvaluationStrategyTest.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static org.eclipse.che.plugin.docker.machine.CustomServerEvaluationStrategy.CHE_WORKSPACE_ID_PREFIX; import static org.mockito.Mockito.when; /** @@ -43,11 +44,19 @@ public class CustomServerEvaluationStrategyTest { private static final String ALL_IP_ADDRESS = "0.0.0.0"; - private static final String WORKSPACE_ID_VALUE = "work123"; - private static final String WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID=" + WORKSPACE_ID_VALUE; + private static final String WORKSPACE_ID_WITHOUT_PREFIX_VALUE = "ABCDEFG"; + + private static final String WORKSPACE_ID_VALUE = CHE_WORKSPACE_ID_PREFIX + WORKSPACE_ID_WITHOUT_PREFIX_VALUE; + private static final String WORKSPACE_ID_PROPERTY_PREFIX = "CHE_WORKSPACE_ID="; + private static final String WORKSPACE_ID_PROPERTY = WORKSPACE_ID_PROPERTY_PREFIX + WORKSPACE_ID_VALUE; private static final String MACHINE_NAME_VALUE = "myMachine"; - private static final String MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=" + MACHINE_NAME_VALUE; + private static final String MACHINE_NAME_PROPERTY_PREFIX = "CHE_MACHINE_NAME="; + private static final String MACHINE_NAME_PROPERTY = MACHINE_NAME_PROPERTY_PREFIX + MACHINE_NAME_VALUE; + + private static final String IS_DEV_MACHINE_PROPERTY_PREFIX = "CHE_IS_DEV_MACHINE="; + private static final String IS_DEV_MACHINE_PROPERTY_TRUE = IS_DEV_MACHINE_PROPERTY_PREFIX + "true"; + private static final String IS_DEV_MACHINE_PROPERTY_FALSE = IS_DEV_MACHINE_PROPERTY_PREFIX + "false"; @Mock private ContainerConfig containerConfig; @@ -76,7 +85,7 @@ public class CustomServerEvaluationStrategyTest { when(containerConfig.getLabels()).thenReturn(containerLabels); when(containerConfig.getExposedPorts()).thenReturn(containerExposedPorts); - envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY}; + envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE}; when(containerConfig.getEnv()).thenReturn(envContainerConfig); when(containerInfo.getNetworkSettings()).thenReturn(networkSettings); @@ -126,6 +135,52 @@ public class CustomServerEvaluationStrategyTest { Assert.assertEquals(portMapping.get("4401/tcp"), WORKSPACE_ID_VALUE); } + /** + * Check workspace Id without prefix template + */ + @Test + public void testWorkspaceIdWithoutPrefixRule() throws Throwable { + this.customServerEvaluationStrategy = + new CustomServerEvaluationStrategy("10.0.0.1", "192.168.1.1", "", "http", "8080"); + + Map portMapping = this.customServerEvaluationStrategy.getExternalAddressesAndPorts(containerInfo, "localhost"); + + Assert.assertTrue(portMapping.containsKey("4401/tcp")); + Assert.assertEquals(portMapping.get("4401/tcp"), WORKSPACE_ID_WITHOUT_PREFIX_VALUE); + } + + /** + * Check the isDevMachine macro in template + */ + @Test + public void testIsDevMachineWhenTrue() throws Throwable { + this.customServerEvaluationStrategy = + new CustomServerEvaluationStrategy("10.0.0.1", "192.168.1.1", + "", "http", "8080"); + + Map portMapping = this.customServerEvaluationStrategy.getExternalAddressesAndPorts(containerInfo, "localhost"); + + Assert.assertTrue(portMapping.containsKey("4401/tcp")); + Assert.assertEquals(portMapping.get("4401/tcp"), WORKSPACE_ID_VALUE); + } + + /** + * Check the isDevMachine macro in template + */ + @Test + public void testIsDevMachineWhenFalse() throws Throwable { + this.envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_FALSE}; + when(containerConfig.getEnv()).thenReturn(envContainerConfig); + + this.customServerEvaluationStrategy = + new CustomServerEvaluationStrategy("10.0.0.1", "192.168.1.1", + "", "http", "8080"); + + Map portMapping = this.customServerEvaluationStrategy.getExternalAddressesAndPorts(containerInfo, "localhost"); + + Assert.assertTrue(portMapping.containsKey("4401/tcp")); + Assert.assertEquals(portMapping.get("4401/tcp"), MACHINE_NAME_VALUE); + } /** * Check workspace Id template @@ -213,7 +268,7 @@ public class CustomServerEvaluationStrategyTest { exposedPorts.add("4401/tcp"); exposedPorts.add("4411/tcp"); exposedPorts.add("8080/tcp"); - List env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY); + List env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE); this.customServerEvaluationStrategy = new CustomServerEvaluationStrategy("127.0.0.1", null, "-", "https", "8080"); CustomServerEvaluationStrategy.RenderingEvaluation renderingEvaluation = this.customServerEvaluationStrategy @@ -233,7 +288,7 @@ public class CustomServerEvaluationStrategyTest { exposedPorts.add("4401/tcp"); exposedPorts.add("4411/tcp"); exposedPorts.add("8080/tcp"); - List env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY); + List env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE); this.customServerEvaluationStrategy = new CustomServerEvaluationStrategy("127.0.0.1", "127.0.0.1", "-", "https", "8080"); CustomServerEvaluationStrategy.RenderingEvaluation renderingEvaluation = this.customServerEvaluationStrategy @@ -253,7 +308,7 @@ public class CustomServerEvaluationStrategyTest { exposedPorts.add("4401/tcp"); exposedPorts.add("4411/tcp"); exposedPorts.add("8080/tcp"); - List env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY); + List env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE); this.customServerEvaluationStrategy = new CustomServerEvaluationStrategy("127.0.0.1", "300.300.300.300", "-", "https", "8080"); CustomServerEvaluationStrategy.RenderingEvaluation renderingEvaluation = this.customServerEvaluationStrategy diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategyTest.java b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategyTest.java new file mode 100644 index 0000000000..7d297c4bf7 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/LocalDockerCustomServerEvaluationStrategyTest.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2016-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; + +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl; +import org.eclipse.che.api.machine.server.model.impl.ServerImpl; +import org.eclipse.che.api.machine.server.model.impl.ServerPropertiesImpl; +import org.eclipse.che.plugin.docker.client.json.ContainerConfig; +import org.eclipse.che.plugin.docker.client.json.ContainerInfo; +import org.eclipse.che.plugin.docker.client.json.NetworkSettings; +import org.eclipse.che.plugin.docker.client.json.PortBinding; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +@Listeners(MockitoTestNGListener.class) +public class LocalDockerCustomServerEvaluationStrategyTest { + + private static final String CHE_DOCKER_IP_EXTERNAL = "container-host-ext.com"; + private static final String ALL_IP_ADDRESS = "0.0.0.0"; + private static final String CONTAINERCONFIG_HOSTNAME = "che-ws-y6jwknht0efzczit-4086112300-fm0aj"; + private static final String WORKSPACE_ID = "79rfwhqaztq2ru2k"; + + private static final String WORKSPACE_ID_VALUE = WORKSPACE_ID; + private static final String WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID=" + WORKSPACE_ID_VALUE; + + private static final String MACHINE_NAME_VALUE = "myMachine"; + private static final String MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=" + MACHINE_NAME_VALUE; + + private static final String IS_DEV_MACHINE_VALUE = "true"; + private static final String IS_DEV_MACHINE_PROPERTY = "CHE_IS_DEV_MACHINE=" + IS_DEV_MACHINE_VALUE; + + private static final String CHE_DOCKER_SERVER_EVALUATION_STRATEGY_CUSTOM_TEMPLATE = "--"; + + @Mock + private ContainerInfo containerInfo; + @Mock + private ContainerConfig containerConfig; + @Mock + private NetworkSettings networkSettings; + + private ServerEvaluationStrategy strategy; + + private Map serverConfs; + + private Map> ports; + + private Map labels; + + private String[] env; + + private String[] envContainerConfig; + + + @BeforeMethod + public void setUp() { + + serverConfs = new HashMap<>(); + serverConfs.put("4301/tcp", new ServerConfImpl("sysServer1-tcp", "4301/tcp", "http", "/some/path1")); + serverConfs.put("4305/udp", new ServerConfImpl("devSysServer1-udp", "4305/udp", null, "some/path4")); + + ports = new HashMap<>(); + ports.put("4301/tcp", Collections.singletonList(new PortBinding().withHostIp(ALL_IP_ADDRESS ) + .withHostPort("32100"))); + ports.put("4305/udp", Collections.singletonList(new PortBinding().withHostIp(ALL_IP_ADDRESS ) + .withHostPort("32103"))); + + labels = new HashMap<>(); + labels.put("che:server:4301/tcp:ref", "sysServer1-tcp"); + labels.put("che:server:4305/udp:ref", "devSysServer1-udp"); + + env = new String[]{"CHE_WORKSPACE_ID="+ WORKSPACE_ID}; + + when(containerInfo.getNetworkSettings()).thenReturn(networkSettings); + when(networkSettings.getIpAddress()).thenReturn(CONTAINERCONFIG_HOSTNAME); + when(networkSettings.getPorts()).thenReturn(ports); + when(containerInfo.getConfig()).thenReturn(containerConfig); + when(containerConfig.getHostname()).thenReturn(CONTAINERCONFIG_HOSTNAME); + when(containerConfig.getEnv()).thenReturn(env); + when(containerConfig.getLabels()).thenReturn(labels); + + envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY}; + when(containerConfig.getEnv()).thenReturn(envContainerConfig); + + } + + /** + * Test: single port strategy should use . + * @throws Exception + */ + @Test + public void shouldUseServerRefToBuildAddressWhenAvailable() throws Exception { + // given + strategy = new LocalDockerCustomServerEvaluationStrategy(null, null, CHE_DOCKER_SERVER_EVALUATION_STRATEGY_CUSTOM_TEMPLATE, "http", null).withThrowOnUnknownHost(false); + + final Map expectedServers = getExpectedServers(CHE_DOCKER_IP_EXTERNAL, + CONTAINERCONFIG_HOSTNAME, + true); + + // when + final Map servers = strategy.getServers(containerInfo, + CHE_DOCKER_IP_EXTERNAL, + serverConfs); + + // then + assertEquals(servers, expectedServers); + } + + private Map getExpectedServers(String externalAddress, + String internalAddress, + boolean useExposedPorts) { + String port1; + String port2; + if (useExposedPorts) { + port1 = ":4301"; + port2 = ":4305"; + } else { + port1 = ":32100"; + port2 = ":32103"; + } + Map expectedServers = new HashMap<>(); + expectedServers.put("4301/tcp", new ServerImpl("sysServer1-tcp", + "http", + "sysServer1-tcp-" + WORKSPACE_ID + "-" + externalAddress, + "http://" + "sysServer1-tcp-" + WORKSPACE_ID + "-" + externalAddress + "/some/path1", + new ServerPropertiesImpl("/some/path1", + internalAddress + port1, + "http://" + internalAddress + port1 + "/some/path1"))); + expectedServers.put("4305/udp", new ServerImpl("devSysServer1-udp", + null, + "devSysServer1-udp-" + WORKSPACE_ID + "-" + externalAddress, + null, + new ServerPropertiesImpl("some/path4", + internalAddress + port2, + null))); + return expectedServers; + } + +} diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategyTest.java b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategyTest.java index af22597eb4..f9bf96e14b 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategyTest.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ServerEvaluationStrategyTest.java @@ -83,7 +83,7 @@ public class ServerEvaluationStrategyTest { expected.put("9090/udp", DEFAULT_HOSTNAME + ":" + "32101"); // when - Map actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports); + Map actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports, false); // then assertEquals(actual, expected); @@ -108,7 +108,7 @@ public class ServerEvaluationStrategyTest { expected.put("9090/udp", DEFAULT_HOSTNAME + ":" + "32101"); // when - Map actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports); + Map actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports, false); // then assertEquals(actual, expected); @@ -375,7 +375,7 @@ public class ServerEvaluationStrategyTest { .withHostPort("32101"))); when(networkSettings.getPorts()).thenReturn(ports); Map exposedPortsToAddressPorts = - strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports); + strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports, false); when(strategy.getExternalAddressesAndPorts(containerInfo, DEFAULT_HOSTNAME)) .thenReturn(exposedPortsToAddressPorts); when(strategy.getInternalAddressesAndPorts(containerInfo, DEFAULT_HOSTNAME)) @@ -396,5 +396,10 @@ public class ServerEvaluationStrategyTest { String internalAddress) { return null; } + + @Override + protected boolean useHttpsForExternalUrls() { + return false; + } } } diff --git a/plugins/plugin-docker/che-plugin-openshift-client/pom.xml b/plugins/plugin-docker/che-plugin-openshift-client/pom.xml index 80111272a7..29ea7465c0 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/pom.xml +++ b/plugins/plugin-docker/che-plugin-openshift-client/pom.xml @@ -55,6 +55,22 @@ javax.inject javax.inject + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-api-model + + + org.eclipse.che.core + che-core-api-workspace + + + org.eclipse.che.core + che-core-commons-annotations + org.eclipse.che.plugin che-plugin-docker-client diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnector.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnector.java index 42c80507c3..d4e1b2acb7 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnector.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnector.java @@ -11,16 +11,29 @@ package org.eclipse.che.plugin.openshift.client; +import static com.google.common.base.Strings.isNullOrEmpty; + +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URLEncoder; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TimeZone; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -28,10 +41,16 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; +import org.eclipse.che.api.core.event.ServerIdleEvent; +import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.core.notification.EventSubscriber; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.plugin.docker.client.DockerApiVersionPathPrefixProvider; import org.eclipse.che.plugin.docker.client.DockerConnector; import org.eclipse.che.plugin.docker.client.DockerConnectorConfiguration; import org.eclipse.che.plugin.docker.client.DockerRegistryAuthResolver; +import org.eclipse.che.plugin.docker.client.Exec; +import org.eclipse.che.plugin.docker.client.LogMessage; import org.eclipse.che.plugin.docker.client.MessageProcessor; import org.eclipse.che.plugin.docker.client.ProgressMonitor; import org.eclipse.che.plugin.docker.client.connection.DockerConnectionFactory; @@ -40,31 +59,35 @@ import org.eclipse.che.plugin.docker.client.json.ContainerConfig; import org.eclipse.che.plugin.docker.client.json.ContainerCreated; import org.eclipse.che.plugin.docker.client.json.ContainerInfo; import org.eclipse.che.plugin.docker.client.json.ContainerListEntry; +import org.eclipse.che.plugin.docker.client.json.ContainerState; import org.eclipse.che.plugin.docker.client.json.Event; import org.eclipse.che.plugin.docker.client.json.Filters; import org.eclipse.che.plugin.docker.client.json.HostConfig; -import org.eclipse.che.plugin.docker.client.json.ImageConfig; import org.eclipse.che.plugin.docker.client.json.ImageInfo; import org.eclipse.che.plugin.docker.client.json.NetworkCreated; import org.eclipse.che.plugin.docker.client.json.NetworkSettings; import org.eclipse.che.plugin.docker.client.json.PortBinding; import org.eclipse.che.plugin.docker.client.json.network.ContainerInNetwork; +import org.eclipse.che.plugin.docker.client.json.network.EndpointConfig; import org.eclipse.che.plugin.docker.client.json.network.Ipam; import org.eclipse.che.plugin.docker.client.json.network.IpamConfig; import org.eclipse.che.plugin.docker.client.json.network.Network; import org.eclipse.che.plugin.docker.client.params.CommitParams; import org.eclipse.che.plugin.docker.client.params.CreateContainerParams; +import org.eclipse.che.plugin.docker.client.params.CreateExecParams; +import org.eclipse.che.plugin.docker.client.params.GetContainerLogsParams; import org.eclipse.che.plugin.docker.client.params.GetEventsParams; import org.eclipse.che.plugin.docker.client.params.GetResourceParams; +import org.eclipse.che.plugin.docker.client.params.InspectImageParams; import org.eclipse.che.plugin.docker.client.params.KillContainerParams; +import org.eclipse.che.plugin.docker.client.params.PullParams; import org.eclipse.che.plugin.docker.client.params.PutResourceParams; import org.eclipse.che.plugin.docker.client.params.RemoveContainerParams; import org.eclipse.che.plugin.docker.client.params.RemoveImageParams; import org.eclipse.che.plugin.docker.client.params.network.RemoveNetworkParams; import org.eclipse.che.plugin.docker.client.params.StartContainerParams; +import org.eclipse.che.plugin.docker.client.params.StartExecParams; import org.eclipse.che.plugin.docker.client.params.StopContainerParams; -import org.eclipse.che.plugin.docker.client.params.InspectImageParams; -import org.eclipse.che.plugin.docker.client.params.PullParams; import org.eclipse.che.plugin.docker.client.params.TagParams; import org.eclipse.che.plugin.docker.client.params.network.ConnectContainerToNetworkParams; import org.eclipse.che.plugin.docker.client.params.network.CreateNetworkParams; @@ -74,7 +97,9 @@ import org.eclipse.che.plugin.docker.client.params.network.InspectNetworkParams; import org.eclipse.che.plugin.openshift.client.exception.OpenShiftException; import org.eclipse.che.plugin.openshift.client.kubernetes.KubernetesContainer; import org.eclipse.che.plugin.openshift.client.kubernetes.KubernetesEnvVar; +import org.eclipse.che.plugin.openshift.client.kubernetes.KubernetesExecHolder; import org.eclipse.che.plugin.openshift.client.kubernetes.KubernetesLabelConverter; +import org.eclipse.che.plugin.openshift.client.kubernetes.KubernetesOutputAdapter; import org.eclipse.che.plugin.openshift.client.kubernetes.KubernetesService; import org.eclipse.che.plugin.openshift.client.kubernetes.KubernetesStringUtils; import org.slf4j.Logger; @@ -82,12 +107,24 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ContainerBuilder; +import io.fabric8.kubernetes.api.model.ContainerStateRunning; +import io.fabric8.kubernetes.api.model.ContainerStateTerminated; +import io.fabric8.kubernetes.api.model.ContainerStateWaiting; +import io.fabric8.kubernetes.api.model.ContainerStatus; +import io.fabric8.kubernetes.api.model.DoneableEndpoints; +import io.fabric8.kubernetes.api.model.Endpoints; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimBuilder; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimList; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSource; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodList; import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.PodSpecBuilder; import io.fabric8.kubernetes.api.model.Probe; import io.fabric8.kubernetes.api.model.ProbeBuilder; +import io.fabric8.kubernetes.api.model.Quantity; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceList; import io.fabric8.kubernetes.api.model.ServicePort; @@ -97,12 +134,23 @@ import io.fabric8.kubernetes.api.model.VolumeMount; import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.extensions.Deployment; import io.fabric8.kubernetes.api.model.extensions.DeploymentBuilder; +import io.fabric8.kubernetes.api.model.extensions.ReplicaSet; +import io.fabric8.kubernetes.client.KubernetesClientException; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.dsl.ExecWatch; +import io.fabric8.kubernetes.client.dsl.LogWatch; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.utils.InputStreamPumper; +import io.fabric8.openshift.api.model.DeploymentConfig; +import io.fabric8.openshift.api.model.DoneableDeploymentConfig; +import io.fabric8.openshift.api.model.Image; import io.fabric8.openshift.api.model.ImageStream; import io.fabric8.openshift.api.model.ImageStreamTag; +import io.fabric8.openshift.api.model.Route; +import io.fabric8.openshift.api.model.RouteList; import io.fabric8.openshift.client.DefaultOpenShiftClient; import io.fabric8.openshift.client.OpenShiftClient; - -import static com.google.common.base.Strings.isNullOrEmpty; +import io.fabric8.openshift.client.dsl.DeployableScalableResource; /** * Client for OpenShift API. @@ -114,47 +162,137 @@ import static com.google.common.base.Strings.isNullOrEmpty; @Singleton public class OpenShiftConnector extends DockerConnector { private static final Logger LOG = LoggerFactory.getLogger(OpenShiftConnector.class); + public static final String CHE_OPENSHIFT_RESOURCES_PREFIX = "che-ws-"; + public static final String OPENSHIFT_DEPLOYMENT_LABEL = "deployment"; + private static final String CHE_CONTAINER_IDENTIFIER_LABEL_KEY = "cheContainerIdentifier"; private static final String CHE_DEFAULT_EXTERNAL_ADDRESS = "172.17.0.1"; - private static final String CHE_OPENSHIFT_RESOURCES_PREFIX = "che-ws-"; private static final String CHE_WORKSPACE_ID_ENV_VAR = "CHE_WORKSPACE_ID"; + private static final String CHE_IS_DEV_MACHINE_ENV_VAR = "CHE_IS_DEV_MACHINE"; private static final int CHE_WORKSPACE_AGENT_PORT = 4401; private static final int CHE_TERMINAL_AGENT_PORT = 4411; private static final String DOCKER_PROTOCOL_PORT_DELIMITER = "/"; - private static final String OPENSHIFT_SERVICE_TYPE_NODE_PORT = "NodePort"; private static final int OPENSHIFT_WAIT_POD_DELAY = 1000; private static final int OPENSHIFT_WAIT_POD_TIMEOUT = 240; private static final int OPENSHIFT_IMAGESTREAM_WAIT_DELAY = 2000; private static final int OPENSHIFT_IMAGESTREAM_MAX_WAIT_COUNT = 30; private static final String OPENSHIFT_POD_STATUS_RUNNING = "Running"; - private static final String OPENSHIFT_DEPLOYMENT_LABEL = "deployment"; + private static final String OPENSHIFT_VOLUME_STORAGE_CLASS = "volume.beta.kubernetes.io/storage-class"; + private static final String OPENSHIFT_VOLUME_STORAGE_CLASS_NAME = "che-workspace"; private static final String OPENSHIFT_IMAGE_PULL_POLICY_IFNOTPRESENT = "IfNotPresent"; - private static final Long UID_ROOT = Long.valueOf(0); - private static final Long UID_USER = Long.valueOf(1000); - private final OpenShiftClient openShiftClient; + private static final String IDLING_ALPHA_OPENSHIFT_IO_IDLED_AT = "idling.alpha.openshift.io/idled-at"; + private static final String IDLING_ALPHA_OPENSHIFT_IO_PREVIOUS_SCALE = "idling.alpha.openshift.io/previous-scale"; + private static final String OPENSHIFT_CHE_SERVER_DEPLOYMENT_NAME = "che"; + private static final String OPENSHIFT_CHE_SERVER_SERVICE_NAME = "che-host"; + private static final String IDLING_ALPHA_OPENSHIFT_IO_UNIDLE_TARGETS = "idling.alpha.openshift.io/unidle-targets"; + private static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX"; + + private Map execMap = new HashMap<>(); + private final String openShiftCheProjectName; - private final String openShiftCheServiceAccount; private final int openShiftLivenessProbeDelay; private final int openShiftLivenessProbeTimeout; + private final String workspacesPersistentVolumeClaim; + private final String workspacesPvcQuantity; + private final String cheWorkspaceStorage; + private final String cheWorkspaceProjectsStorage; + private final String cheServerExternalAddress; + private final String cheWorkspaceMemoryLimit; + private final String cheWorkspaceMemoryRequest; + private final boolean secureRoutes; + private final boolean createWorkspaceDirs; + private final OpenShiftPvcHelper openShiftPvcHelper; @Inject public OpenShiftConnector(DockerConnectorConfiguration connectorConfiguration, DockerConnectionFactory connectionFactory, DockerRegistryAuthResolver authResolver, DockerApiVersionPathPrefixProvider dockerApiVersionPathPrefixProvider, + OpenShiftPvcHelper openShiftPvcHelper, + EventService eventService, + @Nullable @Named("che.docker.ip.external") String cheServerExternalAddress, @Named("che.openshift.project") String openShiftCheProjectName, - @Named("che.openshift.serviceaccountname") String openShiftCheServiceAccount, @Named("che.openshift.liveness.probe.delay") int openShiftLivenessProbeDelay, - @Named("che.openshift.liveness.probe.timeout") int openShiftLivenessProbeTimeout) { + @Named("che.openshift.liveness.probe.timeout") int openShiftLivenessProbeTimeout, + @Named("che.openshift.workspaces.pvc.name") String workspacesPersistentVolumeClaim, + @Named("che.openshift.workspaces.pvc.quantity") String workspacesPvcQuantity, + @Named("che.workspace.storage") String cheWorkspaceStorage, + @Named("che.workspace.projects.storage") String cheWorkspaceProjectsStorage, + @Nullable @Named("che.openshift.workspace.memory.request") String cheWorkspaceMemoryRequest, + @Nullable @Named("che.openshift.workspace.memory.override") String cheWorkspaceMemoryLimit, + @Named("che.openshift.secure.routes") boolean secureRoutes, + @Named("che.openshift.precreate.workspace.dirs") boolean createWorkspaceDirs) { super(connectorConfiguration, connectionFactory, authResolver, dockerApiVersionPathPrefixProvider); + this.cheServerExternalAddress = cheServerExternalAddress; this.openShiftCheProjectName = openShiftCheProjectName; - this.openShiftCheServiceAccount = openShiftCheServiceAccount; this.openShiftLivenessProbeDelay = openShiftLivenessProbeDelay; this.openShiftLivenessProbeTimeout = openShiftLivenessProbeTimeout; + this.workspacesPersistentVolumeClaim = workspacesPersistentVolumeClaim; + this.workspacesPvcQuantity = workspacesPvcQuantity; + this.cheWorkspaceStorage = cheWorkspaceStorage; + this.cheWorkspaceProjectsStorage = cheWorkspaceProjectsStorage; + this.cheWorkspaceMemoryRequest = cheWorkspaceMemoryRequest; + this.cheWorkspaceMemoryLimit = cheWorkspaceMemoryLimit; + this.secureRoutes = secureRoutes; + this.createWorkspaceDirs = createWorkspaceDirs; + this.openShiftPvcHelper = openShiftPvcHelper; + eventService.subscribe(new EventSubscriber() { - this.openShiftClient = new DefaultOpenShiftClient(); + @Override + public void onEvent(ServerIdleEvent event) { + idleCheServer(event); + } + }); + } + + private void idleCheServer(ServerIdleEvent event) { + try (DefaultOpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + DeployableScalableResource deploymentConfigResource = openShiftClient.deploymentConfigs() + .inNamespace(openShiftCheProjectName) + .withName(OPENSHIFT_CHE_SERVER_DEPLOYMENT_NAME); + DeploymentConfig deploymentConfig = deploymentConfigResource.get(); + if (deploymentConfig == null) { + LOG.warn(String.format("Deployment config %s not found", OPENSHIFT_CHE_SERVER_DEPLOYMENT_NAME)); + return; + } + Integer replicas = deploymentConfig.getSpec().getReplicas(); + if (replicas != null && replicas > 0) { + Resource endpointResource = openShiftClient.endpoints() + .inNamespace(openShiftCheProjectName) + .withName(OPENSHIFT_CHE_SERVER_SERVICE_NAME); + Endpoints endpoint = endpointResource.get(); + if (endpoint == null) { + LOG.warn(String.format("Endpoint %s not found", OPENSHIFT_CHE_SERVER_SERVICE_NAME)); + return; + } + Map annotations = deploymentConfig.getMetadata().getAnnotations(); + if (annotations == null) { + annotations = new HashMap<>(); + deploymentConfig.getMetadata().setAnnotations(annotations); + } + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat(ISO_8601_DATE_FORMAT); + df.setTimeZone(tz); + String idle = df.format(new Date()); + annotations.put(IDLING_ALPHA_OPENSHIFT_IO_IDLED_AT, idle); + annotations.put(IDLING_ALPHA_OPENSHIFT_IO_PREVIOUS_SCALE, "1"); + deploymentConfig.getSpec().setReplicas(0); + deploymentConfigResource.patch(deploymentConfig); + Map endpointAnnotations = endpoint.getMetadata().getAnnotations(); + if (endpointAnnotations == null) { + endpointAnnotations = new HashMap<>(); + endpoint.getMetadata().setAnnotations(endpointAnnotations); + } + endpointAnnotations.put(IDLING_ALPHA_OPENSHIFT_IO_IDLED_AT, idle); + endpointAnnotations.put(IDLING_ALPHA_OPENSHIFT_IO_UNIDLE_TARGETS, + "[{\"kind\":\"DeploymentConfig\",\"name\":\"" + OPENSHIFT_CHE_SERVER_DEPLOYMENT_NAME + + "\",\"replicas\":1}]"); + endpointResource.patch(endpoint); + LOG.info("Che server has been idled"); + } + } } /** @@ -167,9 +305,6 @@ public class OpenShiftConnector extends DockerConnector { String containerName = KubernetesStringUtils.convertToContainerName(createContainerParams.getContainerName()); String workspaceID = getCheWorkspaceId(createContainerParams); - // Generate workspaceID if CHE_WORKSPACE_ID env var does not exist - workspaceID = workspaceID.isEmpty() ? KubernetesStringUtils.generateWorkspaceID() : workspaceID; - // imageForDocker is the docker version of the image repository. It's needed for other // OpenShiftConnector API methods, but is not acceptable as an OpenShift name String imageForDocker = createContainerParams.getContainerConfig().getImage(); @@ -186,12 +321,15 @@ public class OpenShiftConnector extends DockerConnector { // Next we need to get the address of the registry where the ImageStreamTag is stored String imageStreamName = KubernetesStringUtils.getImageStreamNameFromPullSpec(imageStreamTagPullSpec); - ImageStream imageStream = openShiftClient.imageStreams() - .inNamespace(openShiftCheProjectName) - .withName(imageStreamName) - .get(); - if (imageStream == null) { - throw new OpenShiftException("ImageStream not found"); + ImageStream imageStream; + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + imageStream = openShiftClient.imageStreams() + .inNamespace(openShiftCheProjectName) + .withName(imageStreamName) + .get(); + if (imageStream == null) { + throw new OpenShiftException("ImageStream not found"); + } } String registryAddress = imageStream.getStatus() .getDockerImageRepository() @@ -207,35 +345,72 @@ public class OpenShiftConnector extends DockerConnector { .getConfig().getExposedPorts().keySet(); Set exposedPorts = getExposedPorts(containerExposedPorts, imageExposedPorts); - boolean runContainerAsRoot = runContainerAsRoot(imageForDocker); - String[] envVariables = createContainerParams.getContainerConfig().getEnv(); String[] volumes = createContainerParams.getContainerConfig().getHostConfig().getBinds(); Map additionalLabels = createContainerParams.getContainerConfig().getLabels(); + String networkName = createContainerParams.getContainerConfig().getHostConfig().getNetworkMode(); + EndpointConfig endpointConfig = createContainerParams.getContainerConfig().getNetworkingConfig().getEndpointsConfig().get(networkName); + String[] endpointAliases = endpointConfig != null ? endpointConfig.getAliases() : new String[0]; + + Map resourceLimits = new HashMap<>(); + if (!isNullOrEmpty(cheWorkspaceMemoryLimit)) { + LOG.info("Che property 'che.openshift.workspace.memory.override' " + + "used to override workspace memory limit to {}.", cheWorkspaceMemoryLimit); + resourceLimits.put("memory", new Quantity(cheWorkspaceMemoryLimit)); + } else { + long memoryLimitBytes = createContainerParams.getContainerConfig().getHostConfig().getMemory(); + String memoryLimit = Long.toString(memoryLimitBytes / 1048576) + "Mi"; + LOG.info("Creating workspace pod with memory limit of {}.", memoryLimit); + resourceLimits.put("memory", new Quantity(cheWorkspaceMemoryLimit)); + } + + Map resourceRequests = new HashMap<>(); + if (!isNullOrEmpty(cheWorkspaceMemoryRequest)) { + resourceRequests.put("memory", new Quantity(cheWorkspaceMemoryRequest)); + } + + String deploymentName; + String serviceName; + if (isDevMachine(createContainerParams)) { + serviceName = deploymentName = CHE_OPENSHIFT_RESOURCES_PREFIX + workspaceID; + } else { + if (endpointAliases.length > 0) { + serviceName = endpointAliases[0]; + deploymentName = CHE_OPENSHIFT_RESOURCES_PREFIX + serviceName; + } else { + // Should never happen + serviceName = deploymentName = CHE_OPENSHIFT_RESOURCES_PREFIX + KubernetesStringUtils.generateWorkspaceID(); + } + } + String containerID; - try { - createOpenShiftService(workspaceID, exposedPorts, additionalLabels); - String deploymentName = createOpenShiftDeployment(workspaceID, - dockerPullSpec, - containerName, - exposedPorts, - envVariables, - volumes, - runContainerAsRoot); + OpenShiftClient openShiftClient = new DefaultOpenShiftClient(); + try { + createOpenShiftService(deploymentName, serviceName, exposedPorts, additionalLabels, endpointAliases); + createOpenShiftDeployment(deploymentName, + dockerPullSpec, + containerName, + exposedPorts, + envVariables, + volumes, + resourceLimits, + resourceRequests); containerID = waitAndRetrieveContainerID(deploymentName); if (containerID == null) { throw new OpenShiftException("Failed to get the ID of the container running in the OpenShift pod"); } - } catch (IOException e) { + } catch (IOException | KubernetesClientException e) { // Make sure we clean up deployment and service in case of an error -- otherwise Che can end up // in an inconsistent state. LOG.info("Error while creating Pod, removing deployment"); - String deploymentName = CHE_OPENSHIFT_RESOURCES_PREFIX + workspaceID; + LOG.info(e.getMessage()); cleanUpWorkspaceResources(deploymentName); openShiftClient.resource(imageStreamTag).delete(); throw e; + } finally { + openShiftClient.close(); } return new ContainerCreated(containerID, null); @@ -367,10 +542,14 @@ public class OpenShiftConnector extends DockerConnector { @Override public Network inspectNetwork(InspectNetworkParams params) throws IOException { String netId = params.getNetworkId(); + ServiceList services; + + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + services = openShiftClient.services() + .inNamespace(this.openShiftCheProjectName) + .list(); + } - ServiceList services = openShiftClient.services() - .inNamespace(this.openShiftCheProjectName) - .list(); Map containers = new HashMap<>(); for (Service svc : services.getItems()) { String selector = svc.getSpec().getSelector().get(OPENSHIFT_DEPLOYMENT_LABEL); @@ -378,10 +557,13 @@ public class OpenShiftConnector extends DockerConnector { continue; } - PodList pods = openShiftClient.pods() - .inNamespace(openShiftCheProjectName) - .withLabel(OPENSHIFT_DEPLOYMENT_LABEL, selector) - .list(); + PodList pods; + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + pods = openShiftClient.pods() + .inNamespace(openShiftCheProjectName) + .withLabel(OPENSHIFT_DEPLOYMENT_LABEL, selector) + .list(); + } for (Pod pod : pods.getItems()) { String podName = pod.getMetadata() @@ -456,28 +638,34 @@ public class OpenShiftConnector extends DockerConnector { String tag = params.getTag(); // e.g. latest, usually String imageStreamName = KubernetesStringUtils.convertPullSpecToImageStreamName(repo); + ImageStream existingImageStream; + + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + existingImageStream = openShiftClient.imageStreams() + .inNamespace(openShiftCheProjectName) + .withName(imageStreamName) + .get(); + } - ImageStream existingImageStream = openShiftClient.imageStreams() - .inNamespace(openShiftCheProjectName) - .withName(imageStreamName) - .get(); if (existingImageStream == null) { - openShiftClient.imageStreams() - .inNamespace(openShiftCheProjectName) - .createNew() - .withNewMetadata() - .withName(imageStreamName) // imagestream id - .endMetadata() - .withNewSpec() - .addNewTag() - .withName(tag) - .endTag() - .withDockerImageRepository(repo) // tracking repo - .endSpec() - .withNewStatus() - .withDockerImageRepository("") - .endStatus() - .done(); + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + openShiftClient.imageStreams() + .inNamespace(openShiftCheProjectName) + .createNew() + .withNewMetadata() + .withName(imageStreamName) // imagestream id + .endMetadata() + .withNewSpec() + .addNewTag() + .withName(tag) + .endTag() + .withDockerImageRepository(repo) // tracking repo + .endSpec() + .withNewStatus() + .withDockerImageRepository("") + .endStatus() + .done(); + } } // Wait for Image metadata to be obtained. @@ -489,10 +677,13 @@ public class OpenShiftConnector extends DockerConnector { Thread.currentThread().interrupt(); } - createdImageStream = openShiftClient.imageStreams() - .inNamespace(openShiftCheProjectName) - .withName(imageStreamName) - .get(); + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + createdImageStream = openShiftClient.imageStreams() + .inNamespace(openShiftCheProjectName) + .withName(imageStreamName) + .get(); + } + if (createdImageStream != null && createdImageStream.getStatus().getDockerImageRepository() != null) { @@ -566,12 +757,12 @@ public class OpenShiftConnector extends DockerConnector { @Override public void removeImage(final RemoveImageParams params) throws IOException { - String image = KubernetesStringUtils.getImageStreamNameFromPullSpec(params.getImage()); - - String imageStreamTagName = KubernetesStringUtils.convertPullSpecToTagName(image); - ImageStreamTag imageStreamTag = getImageStreamTagFromRepo(imageStreamTagName); - - openShiftClient.resource(imageStreamTag).delete(); + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + String image = KubernetesStringUtils.getImageStreamNameFromPullSpec(params.getImage()); + String imageStreamTagName = KubernetesStringUtils.convertPullSpecToTagName(image); + ImageStreamTag imageStreamTag = getImageStreamTagFromRepo(imageStreamTagName); + openShiftClient.resource(imageStreamTag).delete(); + } } /** @@ -604,7 +795,143 @@ public class OpenShiftConnector extends DockerConnector { } @Override - public void getEvents(final GetEventsParams params, MessageProcessor messageProcessor) {} + public void getEvents(final GetEventsParams params, MessageProcessor messageProcessor) { + CountDownLatch waitForClose = new CountDownLatch(1); + Watcher eventWatcher = + new Watcher() { + @Override + public void eventReceived(Action action, io.fabric8.kubernetes.api.model.Event event) { + // Do nothing; + } + + @Override + public void onClose(KubernetesClientException e) { + if (e == null) { + LOG.error("Eventwatch Closed"); + } else { + LOG.error("Eventwatch Closed" + e.getMessage()); + } + waitForClose.countDown(); + } + }; + OpenShiftClient openShiftClient = new DefaultOpenShiftClient(); + openShiftClient.events() + .inNamespace(openShiftCheProjectName) + .watch(eventWatcher); + try { + waitForClose.await(); + } catch (InterruptedException e) { + LOG.error("Thread interrupted while waiting for eventWatcher."); + Thread.currentThread().interrupt(); + } finally { + openShiftClient.close(); + } + } + + @Override + public void getContainerLogs(final GetContainerLogsParams params, MessageProcessor containerLogsProcessor) + throws IOException { + String container = params.getContainer(); // container ID + Pod pod = getChePodByContainerId(container); + if (pod != null) { + String podName = pod.getMetadata().getName(); + boolean[] ret = new boolean[1]; + ret[0] = false; + OpenShiftClient openShiftClient = new DefaultOpenShiftClient(); + try (LogWatch watchLog = openShiftClient.pods().inNamespace(openShiftCheProjectName).withName(podName) + .watchLog()) { + Watcher watcher = new Watcher() { + + @Override + public void eventReceived(Action action, Pod resource) { + if (action == Action.DELETED) { + ret[0] = true; + } + } + + @Override + public void onClose(KubernetesClientException cause) { + ret[0] = true; + } + + }; + openShiftClient.pods().inNamespace(openShiftCheProjectName).withName(podName).watch(watcher); + Thread.sleep(5000); + InputStream is = watchLog.getOutput(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is)); + while (!ret[0]) { + String line = bufferedReader.readLine(); + containerLogsProcessor.process(new LogMessage(LogMessage.Type.DOCKER, line)); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (IOException e) { + // The kubernetes client throws an exception (Pipe not connected) when pod doesn't contain any logs. + // We can ignore it. + } finally { + openShiftClient.close(); + } + } + } + + @Override + public Exec createExec(final CreateExecParams params) throws IOException { + String[] command = params.getCmd(); + String containerId = params.getContainer(); + + Pod pod = getChePodByContainerId(containerId); + String podName = pod.getMetadata().getName(); + + String execId = KubernetesStringUtils.generateWorkspaceID(); + KubernetesExecHolder execHolder = new KubernetesExecHolder().withCommand(command) + .withPod(podName); + execMap.put(execId, execHolder); + + return new Exec(command, execId); + } + + @Override + public void startExec(final StartExecParams params, + @Nullable MessageProcessor execOutputProcessor) throws IOException { + String execId = params.getExecId(); + + KubernetesExecHolder exec = execMap.get(execId); + + String podName = exec.getPod(); + String[] command = exec.getCommand(); + for (int i = 0; i < command.length; i++) { + command[i] = URLEncoder.encode(command[i], "UTF-8"); + } + + ExecutorService executor = Executors.newFixedThreadPool(2); + OpenShiftClient openShiftClient = new DefaultOpenShiftClient(); + try (ExecWatch watch = openShiftClient.pods() + .inNamespace(openShiftCheProjectName) + .withName(podName) + .redirectingOutput() + .redirectingError() + .exec(command); + InputStreamPumper outputPump = new InputStreamPumper(watch.getOutput(), + new KubernetesOutputAdapter(LogMessage.Type.STDOUT, + execOutputProcessor)); + InputStreamPumper errorPump = new InputStreamPumper(watch.getError(), + new KubernetesOutputAdapter(LogMessage.Type.STDERR, + execOutputProcessor)) + ) { + Future outFuture = executor.submit(outputPump); + Future errFuture = executor.submit(errorPump); + // Short-term worksaround; the Futures above seem to never finish. + Thread.sleep(2500); + } catch (KubernetesClientException e) { + throw new OpenShiftException(e.getMessage()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + execMap.remove(execId); + executor.shutdown(); + openShiftClient.close(); + } + } /** * Gets the ImageStreamTag corresponding to a given tag name (i.e. without the repository) @@ -621,10 +948,13 @@ public class OpenShiftConnector extends DockerConnector { // Note: ideally, ImageStreamTags could be identified with a label, but it seems like // ImageStreamTags do not support labels. - List imageStreams = openShiftClient.imageStreamTags() - .inNamespace(openShiftCheProjectName) - .list() - .getItems(); + List imageStreams; + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + imageStreams = openShiftClient.imageStreamTags() + .inNamespace(openShiftCheProjectName) + .list() + .getItems(); + } // We only get ImageStreamTag names here, since these ImageStreamTags do not include // Docker metadata, for some reason. @@ -645,60 +975,101 @@ public class OpenShiftConnector extends DockerConnector { String imageStreamTag = imageStreamTags.get(0); // Finally, get the ImageStreamTag, with Docker metadata. - return openShiftClient.imageStreamTags() - .inNamespace(openShiftCheProjectName) - .withName(imageStreamTag) - .get(); + return getImageStreamTag(imageStreamTag); + } + + private ImageStreamTag getImageStreamTag(final String imageStreamName) { + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + return openShiftClient.imageStreamTags() + .inNamespace(openShiftCheProjectName) + .withName(imageStreamName) + .get(); + } } private Service getCheServiceBySelector(String selectorKey, String selectorValue) { - ServiceList svcs = openShiftClient.services() - .inNamespace(this.openShiftCheProjectName) - .list(); + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + ServiceList svcs = openShiftClient.services() + .inNamespace(this.openShiftCheProjectName) + .list(); - Service svc = svcs.getItems().stream() - .filter(s->s.getSpec().getSelector().containsKey(selectorKey)) - .filter(s->s.getSpec().getSelector().get(selectorKey).equals(selectorValue)).findAny().orElse(null); + Service svc = svcs.getItems().stream() + .filter(s->s.getSpec().getSelector().containsKey(selectorKey)) + .filter(s->s.getSpec().getSelector().get(selectorKey).equals(selectorValue)).findAny().orElse(null); - if (svc == null) { - LOG.warn("No Service with selector {}={} could be found", selectorKey, selectorValue); + if (svc == null) { + LOG.warn("No Service with selector {}={} could be found", selectorKey, selectorValue); + } + return svc; } - - return svc; } private Deployment getDeploymentByName(String deploymentName) throws IOException { - Deployment deployment = openShiftClient - .extensions().deployments() - .inNamespace(this.openShiftCheProjectName) - .withName(deploymentName) - .get(); - if (deployment == null) { - LOG.warn("No Deployment with name {} could be found", deploymentName); + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + Deployment deployment = openShiftClient + .extensions().deployments() + .inNamespace(this.openShiftCheProjectName) + .withName(deploymentName) + .get(); + if (deployment == null) { + LOG.warn("No Deployment with name {} could be found", deploymentName); + } + return deployment; + } + } + + private List getRoutesByLabel(String labelKey, String labelValue) throws IOException { + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + RouteList routeList = openShiftClient + .routes() + .inNamespace(this.openShiftCheProjectName) + .withLabel(labelKey, labelValue) + .list(); + + List items = routeList.getItems(); + + if (items.isEmpty()) { + LOG.warn("No Route with label {}={} could be found", labelKey, labelValue); + throw new IOException("No Route with label " + labelKey + "=" + labelValue + " could be found"); + } + + return items; + } + } + + private List getReplicaSetByLabel(String key, String value) { + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + List replicaSets = openShiftClient.extensions() + .replicaSets() + .inNamespace(openShiftCheProjectName) + .withLabel(key, value) + .list().getItems(); + return replicaSets; } - return deployment; } private Pod getChePodByContainerId(String containerId) throws IOException { - PodList pods = openShiftClient.pods() - .inNamespace(this.openShiftCheProjectName) - .withLabel(CHE_CONTAINER_IDENTIFIER_LABEL_KEY, - KubernetesStringUtils.getLabelFromContainerID(containerId)) - .list(); + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + PodList pods = openShiftClient.pods() + .inNamespace(this.openShiftCheProjectName) + .withLabel(CHE_CONTAINER_IDENTIFIER_LABEL_KEY, + KubernetesStringUtils.getLabelFromContainerID(containerId)) + .list(); - List items = pods.getItems(); + List items = pods.getItems(); - if (items.isEmpty()) { - LOG.error("An OpenShift Pod with label {}={} could not be found", CHE_CONTAINER_IDENTIFIER_LABEL_KEY, containerId); - throw new IOException("An OpenShift Pod with label " + CHE_CONTAINER_IDENTIFIER_LABEL_KEY + "=" + containerId +" could not be found"); + if (items.isEmpty()) { + LOG.error("An OpenShift Pod with label {}={} could not be found", CHE_CONTAINER_IDENTIFIER_LABEL_KEY, containerId); + throw new IOException("An OpenShift Pod with label " + CHE_CONTAINER_IDENTIFIER_LABEL_KEY + "=" + containerId +" could not be found"); + } + + if (items.size() > 1) { + LOG.error("There are {} pod with label {}={} (just one was expected)", items.size(), CHE_CONTAINER_IDENTIFIER_LABEL_KEY, containerId ); + throw new IOException("There are " + items.size() + " pod with label " + CHE_CONTAINER_IDENTIFIER_LABEL_KEY + "=" + containerId + " (just one was expeced)"); + } + + return items.get(0); } - - if (items.size() > 1) { - LOG.error("There are {} pod with label {}={} (just one was expeced)", items.size(), CHE_CONTAINER_IDENTIFIER_LABEL_KEY, containerId ); - throw new IOException("There are " + items.size() + " pod with label " + CHE_CONTAINER_IDENTIFIER_LABEL_KEY + "=" + containerId + " (just one was expeced)"); - } - - return items.get(0); } /** @@ -714,12 +1085,21 @@ public class OpenShiftConnector extends DockerConnector { // except that the capitalization is inconsistent, breaking deserialization. Top level elements // are lowercased with underscores, while nested elements conform to FieldNamingPolicy.UPPER_CAMEL_CASE. // We're only converting the config fields for brevity; this means that other fields are null. - String dockerImageConfig = imageStreamTag.getImage().getDockerImageConfig(); - ImageInfo info = GSON.fromJson(dockerImageConfig.replaceFirst("config", "Config") - .replaceFirst("container_config", "ContainerConfig"), - ImageInfo.class); + Image tagImage = imageStreamTag.getImage(); + String dockerImageConfig = tagImage.getDockerImageConfig(); - return info; + if (!isNullOrEmpty(dockerImageConfig)) { + LOG.info("imageStreamTag dockerImageConfig is not empty. Using it to get image info"); + ImageInfo info = GSON.fromJson(dockerImageConfig.replaceFirst("config", "Config") + .replaceFirst("container_config", "ContainerConfig"), + ImageInfo.class); + return info; + } else { + LOG.info("imageStreamTag dockerImageConfig empty. Using dockerImageMetadata to get image info"); + String dockerImageMetadata = GSON.toJson(tagImage.getAdditionalProperties().get("dockerImageMetadata")); + ImageInfo info = GSON.fromJson(dockerImageMetadata, ImageInfo.class); + return info; + } } protected String getCheWorkspaceId(CreateContainerParams createContainerParams) { @@ -731,46 +1111,77 @@ public class OpenShiftConnector extends DockerConnector { return workspaceID.replaceFirst("workspace",""); } - private void createOpenShiftService(String workspaceID, + private boolean isDevMachine(CreateContainerParams createContainerParams) { + Stream env = Arrays.stream(createContainerParams.getContainerConfig().getEnv()); + return Boolean.parseBoolean(env.filter(v -> v.startsWith(CHE_IS_DEV_MACHINE_ENV_VAR) && v.contains("=")) + .map(v -> v.split("=",2)[1]) + .findFirst() + .orElse("false")); + } + + private void createOpenShiftService(String deploymentName, + String serviceName, Set exposedPorts, - Map additionalLabels) { - - Map selector = Collections.singletonMap(OPENSHIFT_DEPLOYMENT_LABEL, CHE_OPENSHIFT_RESOURCES_PREFIX + workspaceID); + Map additionalLabels, + String[] endpointAliases) { + Map selector = Collections.singletonMap(OPENSHIFT_DEPLOYMENT_LABEL, deploymentName); List ports = KubernetesService.getServicePortsFrom(exposedPorts); - Service service = openShiftClient - .services() - .inNamespace(this.openShiftCheProjectName) - .createNew() - .withNewMetadata() - .withName(CHE_OPENSHIFT_RESOURCES_PREFIX + workspaceID) + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + Service service = openShiftClient + .services() + .inNamespace(this.openShiftCheProjectName) + .createNew() + .withNewMetadata() + .withName(serviceName) .withAnnotations(KubernetesLabelConverter.labelsToNames(additionalLabels)) - .endMetadata() - .withNewSpec() - .withType(OPENSHIFT_SERVICE_TYPE_NODE_PORT) + .endMetadata() + .withNewSpec() .withSelector(selector) .withPorts(ports) - .endSpec() - .done(); + .endSpec() + .done(); - LOG.info("OpenShift service {} created", service.getMetadata().getName()); + LOG.info("OpenShift service {} created", service.getMetadata().getName()); + + for (ServicePort port : ports) { + createOpenShiftRoute(serviceName, deploymentName, port.getName()); + } + } } - private String createOpenShiftDeployment(String workspaceID, + private void createOpenShiftRoute(String serviceName, + String deploymentName, + String serverRef) { + String routeId = serviceName.replaceFirst(CHE_OPENSHIFT_RESOURCES_PREFIX, ""); + OpenShiftRouteCreator.createRoute(openShiftCheProjectName, + cheServerExternalAddress, + serverRef, + serviceName, + deploymentName, + routeId, + secureRoutes); + } + + private void createOpenShiftDeployment(String deploymentName, String imageName, String sanitizedContainerName, Set exposedPorts, String[] envVariables, String[] volumes, - boolean runContainerAsRoot) { + Map resourceLimits, + Map resourceRequests) throws OpenShiftException { - String deploymentName = CHE_OPENSHIFT_RESOURCES_PREFIX + workspaceID; LOG.info("Creating OpenShift deployment {}", deploymentName); Map selector = Collections.singletonMap(OPENSHIFT_DEPLOYMENT_LABEL, deploymentName); LOG.info("Adding container {} to OpenShift deployment {}", sanitizedContainerName, deploymentName); - Long UID = runContainerAsRoot ? UID_ROOT : UID_USER; + + if (createWorkspaceDirs) { + createWorkspaceDir(volumes); + } + Container container = new ContainerBuilder() .withName(sanitizedContainerName) .withImage(imageName) @@ -778,17 +1189,19 @@ public class OpenShiftConnector extends DockerConnector { .withPorts(KubernetesContainer.getContainerPortsFrom(exposedPorts)) .withImagePullPolicy(OPENSHIFT_IMAGE_PULL_POLICY_IFNOTPRESENT) .withNewSecurityContext() - .withRunAsUser(UID) - .withPrivileged(true) + .withPrivileged(false) .endSecurityContext() .withLivenessProbe(getLivenessProbeFrom(exposedPorts)) - .withVolumeMounts(getVolumeMountsFrom(volumes, workspaceID)) + .withVolumeMounts(getVolumeMountsFrom(volumes)) + .withNewResources() + .withLimits(resourceLimits) + .withRequests(resourceRequests) + .endResources() .build(); PodSpec podSpec = new PodSpecBuilder() .withContainers(container) - .withVolumes(getVolumesFrom(volumes, workspaceID)) - .withServiceAccountName(this.openShiftCheServiceAccount) + .withVolumes(getVolumesFrom(volumes)) .build(); Deployment deployment = new DeploymentBuilder() @@ -810,13 +1223,14 @@ public class OpenShiftConnector extends DockerConnector { .endSpec() .build(); - deployment = openShiftClient.extensions() - .deployments() - .inNamespace(this.openShiftCheProjectName) - .create(deployment); + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + deployment = openShiftClient.extensions() + .deployments() + .inNamespace(this.openShiftCheProjectName) + .create(deployment); + } LOG.info("OpenShift deployment {} created", deploymentName); - return deployment.getMetadata().getName(); } /** @@ -829,7 +1243,8 @@ public class OpenShiftConnector extends DockerConnector { */ private ImageStreamTag createImageStreamTag(String sourceImageWithTag, String imageStreamTagName) throws IOException { - try { + + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { openShiftClient.imageStreamTags() .inNamespace(openShiftCheProjectName) .createOrReplaceWithNew() @@ -876,11 +1291,12 @@ public class OpenShiftConnector extends DockerConnector { * @param pod * @param containerId * @return + * @throws OpenShiftException */ private ContainerInfo createContainerInfo(Service svc, ImageInfo imageInfo, Pod pod, - String containerId) { + String containerId) throws OpenShiftException { // In Che on OpenShift, we only have one container per pod. Container container = pod.getSpec().getContainers().get(0); @@ -889,7 +1305,6 @@ public class OpenShiftConnector extends DockerConnector { // HostConfig HostConfig hostConfig = new HostConfig(); hostConfig.setBinds(new String[0]); - hostConfig.setMemory(imageInfo.getConfig().getMemory()); // Env vars List imageEnv = Arrays.asList(imageContainerConfig.getEnv()); @@ -935,27 +1350,69 @@ public class OpenShiftConnector extends DockerConnector { info.setNetworkSettings(networkSettings); info.setHostConfig(hostConfig); info.setImage(imageInfo.getConfig().getImage()); + + // In Che on OpenShift, we only have one container per pod. + info.setState(getContainerStates(pod).get(0)); return info; } + private List getContainerStates(final Pod pod) throws OpenShiftException { + List containerStates = new ArrayList<>(); + List containerStatuses = pod.getStatus().getContainerStatuses(); + for (ContainerStatus status : containerStatuses) { + io.fabric8.kubernetes.api.model.ContainerState state = status.getState(); + + ContainerStateTerminated terminated = state.getTerminated(); + ContainerStateWaiting waiting = state.getWaiting(); + ContainerStateRunning running = state.getRunning(); + + ContainerState containerState = new ContainerState(); + + if (terminated != null) { + containerState.setStatus("exited"); + } else if (waiting != null) { + containerState.setStatus("paused"); + } else if (running != null) { + containerState.setStatus("running"); + } else { + throw new OpenShiftException("Fail to detect the state of container with id " + status.getContainerID()); + } + containerStates.add(containerState); + } + return containerStates; + } private void cleanUpWorkspaceResources(String deploymentName) throws IOException { Deployment deployment = getDeploymentByName(deploymentName); Service service = getCheServiceBySelector(OPENSHIFT_DEPLOYMENT_LABEL, deploymentName); + List routes = getRoutesByLabel(OPENSHIFT_DEPLOYMENT_LABEL, deploymentName); + List replicaSets = getReplicaSetByLabel(OPENSHIFT_DEPLOYMENT_LABEL, deploymentName); - if (service != null) { - LOG.info("Removing OpenShift Service {}", service.getMetadata().getName()); - openShiftClient.resource(service).delete(); - } + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + if (routes != null) { + for (Route route: routes) { + LOG.info("Removing OpenShift Route {}", route.getMetadata().getName()); + openShiftClient.resource(route).delete(); + } + } - if (deployment != null) { - LOG.info("Removing OpenShift Deployment {}", deployment.getMetadata().getName()); - openShiftClient.resource(deployment).delete(); - } + if (service != null) { + LOG.info("Removing OpenShift Service {}", service.getMetadata().getName()); + openShiftClient.resource(service).delete(); + } - // Wait for all pods to terminate before returning. - try { + if (deployment != null) { + LOG.info("Removing OpenShift Deployment {}", deployment.getMetadata().getName()); + openShiftClient.resource(deployment).delete(); + } + + if (replicaSets != null && replicaSets.size() > 0) { + LOG.info("Removing OpenShift ReplicaSets for deployment {}", deploymentName); + replicaSets.forEach(rs -> openShiftClient.resource(rs).delete()); + } + + // Wait for all pods to terminate before returning. for (int waitCount = 0; waitCount < OPENSHIFT_WAIT_POD_TIMEOUT; waitCount++) { List pods = openShiftClient.pods() .inNamespace(openShiftCheProjectName) @@ -975,92 +1432,162 @@ public class OpenShiftConnector extends DockerConnector { throw new OpenShiftException("Timeout while waiting for pods to terminate"); } - private List getVolumeMountsFrom(String[] volumes, String workspaceID) { - List vms = new ArrayList<>(); - for (String volume : volumes) { - String mountPath = volume.split(":",3)[1]; - String volumeName = getVolumeName(volume); + private void createWorkspaceDir(String[] volumes) throws OpenShiftException { + PersistentVolumeClaim pvc = getClaimCheWorkspace(); + String workspaceSubpath = getWorkspaceSubpath(volumes); + if (pvc != null && !isNullOrEmpty(workspaceSubpath)) { + LOG.info("Making sure directory exists for workspace {}", workspaceSubpath); + boolean succeeded = openShiftPvcHelper.createJobPod(workspacesPersistentVolumeClaim, + openShiftCheProjectName, + "create-", + OpenShiftPvcHelper.Command.MAKE, + workspaceSubpath); + if (!succeeded) { + LOG.error("Failed to create workspace directory {} in PVC {}", workspaceSubpath, + workspacesPersistentVolumeClaim); + throw new OpenShiftException("Failed to create workspace directory in PVC"); + } + } + } - VolumeMount vm = new VolumeMountBuilder() - .withMountPath(mountPath) - .withName("ws-" + workspaceID + "-" + volumeName) + /** + * Gets the workspace subpath from an array of volumes. Since volumes provided are + * those used when running Che in Docker, most of the volume spec is ignored; this + * method returns the subpath within the hostpath that refers to the workspace. + *

+ * E.g. for a volume {@code /data/workspaces/wksp-8z00:/projects:Z}, this method will return + * "wksp-8z00". + * + * @param volumes + * @return + */ + private String getWorkspaceSubpath(String[] volumes) { + String workspaceSubpath = null; + for (String volume : volumes) { + // Volumes are structured ::. + // We first check that matches the mount path for projects + // and then extract the hostpath directory. The first part of the volume + // String will be structured /workspaceName. + String mountPath = volume.split(":", 3)[1]; + if (cheWorkspaceProjectsStorage.equals(mountPath)) { + workspaceSubpath = volume.split(":", 3)[0].replaceAll(cheWorkspaceStorage, ""); + if (workspaceSubpath.startsWith("/")) { + workspaceSubpath = workspaceSubpath.substring(1); + } + } + } + return workspaceSubpath; + } + + private List getVolumeMountsFrom(String[] volumes) { + List vms = new ArrayList<>(); + PersistentVolumeClaim pvc = getClaimCheWorkspace(); + if (pvc != null) { + String subPath = getWorkspaceSubpath(volumes); + if (subPath != null) { + VolumeMount vm = new VolumeMountBuilder() + .withMountPath(cheWorkspaceProjectsStorage) + .withName(workspacesPersistentVolumeClaim) + .withSubPath(subPath) .build(); - vms.add(vm); + vms.add(vm); + } } return vms; } - private List getVolumesFrom(String[] volumes, String workspaceID) { + private List getVolumesFrom(String[] volumes) { List vs = new ArrayList<>(); - for (String volume : volumes) { - String hostPath = volume.split(":",3)[0]; - String volumeName = getVolumeName(volume); - - Volume v = new VolumeBuilder() - .withNewHostPath(hostPath) - .withName("ws-" + workspaceID + "-" + volumeName) - .build(); - vs.add(v); + PersistentVolumeClaim pvc = getClaimCheWorkspace(); + if (pvc != null) { + for (String volume : volumes) { + String mountPath = volume.split(":",3)[1]; + if (cheWorkspaceProjectsStorage.equals(mountPath)) { + PersistentVolumeClaimVolumeSource pvcs = new PersistentVolumeClaimVolumeSourceBuilder() + .withClaimName(workspacesPersistentVolumeClaim) + .build(); + Volume v = new VolumeBuilder() + .withPersistentVolumeClaim(pvcs) + .withName(workspacesPersistentVolumeClaim) + .build(); + vs.add(v); + } + } } return vs; } - private String getVolumeName(String volume) { - if (volume.contains("ws-agent")) { - return "wsagent-lib"; + private PersistentVolumeClaim getClaimCheWorkspace() { + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + PersistentVolumeClaimList pvcList = openShiftClient.persistentVolumeClaims().inNamespace(openShiftCheProjectName).list(); + for(PersistentVolumeClaim pvc: pvcList.getItems()) { + if (workspacesPersistentVolumeClaim.equals(pvc.getMetadata().getName())) { + return pvc; + } + } + Map requests = new HashMap<>(); + requests.put("storage", new Quantity(workspacesPvcQuantity)); + Map annotations = Collections.singletonMap(OPENSHIFT_VOLUME_STORAGE_CLASS, OPENSHIFT_VOLUME_STORAGE_CLASS_NAME); + PersistentVolumeClaim pvc = new PersistentVolumeClaimBuilder() + .withNewMetadata() + .withName(workspacesPersistentVolumeClaim) + .withAnnotations(annotations) + .endMetadata() + .withNewSpec() + .withAccessModes("ReadWriteOnce") + .withNewResources() + .withRequests(requests) + .endResources() + .endSpec() + .build(); + pvc = openShiftClient.persistentVolumeClaims().inNamespace(openShiftCheProjectName).create(pvc); + LOG.info("Creating OpenShift PVC {}", pvc.getMetadata().getName()); + return pvc; } - - if (volume.contains("terminal")) { - return "terminal"; - } - - if (volume.contains("workspaces")) { - return "project"; - } - - return "unknown-volume"; } private String waitAndRetrieveContainerID(String deploymentName) throws IOException { - for (int i = 0; i < OPENSHIFT_WAIT_POD_TIMEOUT; i++) { - try { - Thread.sleep(OPENSHIFT_WAIT_POD_DELAY); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + for (int i = 0; i < OPENSHIFT_WAIT_POD_TIMEOUT; i++) { + try { + Thread.sleep(OPENSHIFT_WAIT_POD_DELAY); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + + List pods = openShiftClient.pods() + .inNamespace(this.openShiftCheProjectName) + .withLabel(OPENSHIFT_DEPLOYMENT_LABEL, deploymentName) + .list() + .getItems(); + + if (pods.size() < 1) { + throw new OpenShiftException(String.format("Pod with deployment name %s not found", + deploymentName)); + } else if (pods.size() > 1) { + throw new OpenShiftException(String.format("Multiple pods with deployment name %s found", + deploymentName)); + } - List pods = openShiftClient.pods() - .inNamespace(this.openShiftCheProjectName) - .withLabel(OPENSHIFT_DEPLOYMENT_LABEL, deploymentName) - .list() - .getItems(); - - if (pods.size() < 1) { - throw new OpenShiftException(String.format("Pod with deployment name %s not found", - deploymentName)); - } else if (pods.size() > 1) { - throw new OpenShiftException(String.format("Multiple pods with deployment name %s found", - deploymentName)); - } - - Pod pod = pods.get(0); - String status = pod.getStatus().getPhase(); - if (OPENSHIFT_POD_STATUS_RUNNING.equals(status)) { - String containerID = pod.getStatus().getContainerStatuses().get(0).getContainerID(); - String normalizedID = KubernetesStringUtils.normalizeContainerID(containerID); - openShiftClient.pods() - .inNamespace(openShiftCheProjectName) - .withName(pod.getMetadata().getName()) - .edit() - .editMetadata() - .addToLabels(CHE_CONTAINER_IDENTIFIER_LABEL_KEY, - KubernetesStringUtils.getLabelFromContainerID(normalizedID)) - .endMetadata() - .done(); - return normalizedID; + Pod pod = pods.get(0); + String status = pod.getStatus().getPhase(); + if (OPENSHIFT_POD_STATUS_RUNNING.equals(status)) { + String containerID = pod.getStatus().getContainerStatuses().get(0).getContainerID(); + String normalizedID = KubernetesStringUtils.normalizeContainerID(containerID); + openShiftClient.pods() + .inNamespace(openShiftCheProjectName) + .withName(pod.getMetadata().getName()) + .edit() + .editMetadata() + .addToLabels(CHE_CONTAINER_IDENTIFIER_LABEL_KEY, + KubernetesStringUtils.getLabelFromContainerID(normalizedID)) + .endMetadata() + .done(); + return normalizedID; + } } + return null; } - return null; } /** @@ -1127,19 +1654,6 @@ public class OpenShiftConnector extends DockerConnector { return exposedPorts; } - /** - * When container is expected to be run as root, user field from {@link ImageConfig} is empty. - * For non-root user it contains "user" value - * - * @param imageName - * @return true if user property from Image config is empty string, false otherwise - * @throws IOException - */ - private boolean runContainerAsRoot(final String imageName) throws IOException { - String user = inspectImage(InspectImageParams.create(imageName)).getConfig().getUser(); - return user != null && user.isEmpty(); - } - /** * @param exposedPorts * @return true if machine exposes 4411/tcp port used by Terminal agent, diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftPvcHelper.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftPvcHelper.java new file mode 100644 index 0000000000..8bf5af0116 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftPvcHelper.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * 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.openshift.client; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.ContainerBuilder; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSource; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSourceBuilder; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.Quantity; +import io.fabric8.kubernetes.api.model.Volume; +import io.fabric8.kubernetes.api.model.VolumeBuilder; +import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; +import io.fabric8.openshift.client.DefaultOpenShiftClient; +import io.fabric8.openshift.client.OpenShiftClient; + +/** + * Helper class for executing simple commands in a Persistent Volume on Openshift. + *

+ * Creates a short-lived Pod using a CentOS image which mounts a specified PVC and + * executes a command (either {@code mkdir -p } or {@code rm -rf + * For mkdir commands, an in-memory list of created workspaces is stored and used to avoid + * calling mkdir unnecessarily. However, this list is not persisted, so dir creation is + * not tracked between restarts. + * + * @author amisevsk + */ +public class OpenShiftPvcHelper { + + private static final Logger LOG = LoggerFactory.getLogger(OpenShiftPvcHelper.class); + + private static final String POD_PHASE_SUCCEEDED = "Succeeded"; + private static final String POD_PHASE_FAILED = "Failed"; + private static final String[] MKDIR_WORKSPACE_COMMAND = new String[] {"mkdir", "-p"}; + private static final String[] RMDIR_WORKSPACE_COMMAND = new String[] {"rm", "-rf"}; + + private static final Set createdWorkspaces = ConcurrentHashMap.newKeySet(); + + private final String jobImage; + private final String jobMemoryLimit; + + protected enum Command {REMOVE, MAKE} + + @Inject + protected OpenShiftPvcHelper(@Named("che.openshift.jobs.image") String jobImage, + @Named("che.openshift.jobs.memorylimit") String jobMemoryLimit) { + this.jobImage = jobImage; + this.jobMemoryLimit = jobMemoryLimit; + } + + /** + * Creates a pod with {@code command} and reports whether it succeeded + * @param workspacesPvcName + * name of the PVC to mount + * @param projectNamespace + * OpenShift namespace + * @param jobNamePrefix + * prefix used for pod metadata name. Name structure will normally + * be {@code } if only one path is passed, or + * {@code batch} if multiple paths are provided + * @param command + * command to execute in PVC. + * @param workspaceDirs + * list of arguments attached to command. A list of directories to + * create/delete. + * @return true if Pod terminates with phase "Succeeded" or mkdir command issued + * for already created worksapce, false otherwise. + * + * @see Command + */ + protected boolean createJobPod(String workspacesPvcName, + String projectNamespace, + String jobNamePrefix, + Command command, + String... workspaceDirs) { + + if (workspaceDirs.length == 0) { + return true; + } + + if (Command.MAKE.equals(command)) { + String[] dirsToCreate = filterDirsToCreate(workspaceDirs); + if (dirsToCreate.length == 0) { + return true; + } + workspaceDirs = dirsToCreate; + } + + VolumeMount vm = new VolumeMountBuilder() + .withMountPath("/projects") + .withName(workspacesPvcName) + .build(); + + PersistentVolumeClaimVolumeSource pvcs = new PersistentVolumeClaimVolumeSourceBuilder() + .withClaimName(workspacesPvcName) + .build(); + + Volume volume = new VolumeBuilder() + .withPersistentVolumeClaim(pvcs) + .withName(workspacesPvcName) + .build(); + + String[] jobCommand = getCommand(command, "/projects/", workspaceDirs); + LOG.info("Executing command {} in PVC {} for {} dirs", jobCommand[0], workspacesPvcName, workspaceDirs.length); + + Map limit = Collections.singletonMap("memory", new Quantity(jobMemoryLimit)); + + String podName = workspaceDirs.length > 1 ? jobNamePrefix + "batch" + : jobNamePrefix + workspaceDirs[0]; + + Container container = new ContainerBuilder().withName(podName) + .withImage(jobImage) + .withImagePullPolicy("IfNotPresent") + .withNewSecurityContext() + .withPrivileged(false) + .endSecurityContext() + .withCommand(jobCommand) + .withVolumeMounts(vm) + .withNewResources() + .withLimits(limit) + .endResources() + .build(); + + Pod podSpec = new PodBuilder().withNewMetadata() + .withName(podName) + .endMetadata() + .withNewSpec() + .withContainers(container) + .withVolumes(volume) + .withRestartPolicy("Never") + .endSpec() + .build(); + + + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()){ + openShiftClient.pods().inNamespace(projectNamespace).create(podSpec); + boolean completed = false; + while(!completed) { + Pod pod = openShiftClient.pods().inNamespace(projectNamespace).withName(podName).get(); + String phase = pod.getStatus().getPhase(); + switch (phase) { + case POD_PHASE_FAILED: + LOG.info("Pod command {} failed", Arrays.toString(jobCommand)); + case POD_PHASE_SUCCEEDED: + openShiftClient.resource(pod).delete(); + updateCreatedDirs(command, phase, workspaceDirs); + return POD_PHASE_SUCCEEDED.equals(phase); + default: + Thread.sleep(1000); + } + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return false; + } + + private String[] getCommand(Command commandType, String mountPath, String... dirs) { + String[] command = new String[0]; + switch (commandType) { + case MAKE : + command = MKDIR_WORKSPACE_COMMAND; + break; + case REMOVE : + command = RMDIR_WORKSPACE_COMMAND; + break; + } + + String[] dirsWithPath = Arrays.asList(dirs).stream() + .map(dir -> mountPath + dir) + .toArray(String[]::new); + + String[] fullCommand = new String[command.length + dirsWithPath.length]; + + System.arraycopy(command, 0, fullCommand, 0, command.length); + System.arraycopy(dirsWithPath, 0, fullCommand, command.length, dirsWithPath.length); + return fullCommand; + } + + private void updateCreatedDirs(Command command, String phase, String... workspaceDirs) { + if (!POD_PHASE_SUCCEEDED.equals(phase)) { + return; + } + List dirs = Arrays.asList(workspaceDirs); + switch (command) { + case MAKE: + createdWorkspaces.addAll(dirs); + break; + case REMOVE: + createdWorkspaces.removeAll(dirs); + break; + } + } + + private String[] filterDirsToCreate(String[] allDirs) { + List dirs = Arrays.asList(allDirs); + List dirsToCreate = new ArrayList<>(); + for(String dir : dirs) { + if (!createdWorkspaces.contains(dir)) { + dirsToCreate.add(dir); + } + } + return dirsToCreate.toArray(new String[dirsToCreate.size()]); + } +} diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftRouteCreator.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftRouteCreator.java new file mode 100644 index 0000000000..05a7034ef2 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftRouteCreator.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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.openshift.client; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.fabric8.openshift.api.model.DoneableRoute; +import io.fabric8.openshift.api.model.Route; +import io.fabric8.openshift.api.model.RouteFluent.SpecNested; +import io.fabric8.openshift.client.DefaultOpenShiftClient; +import io.fabric8.openshift.client.OpenShiftClient; + +public class OpenShiftRouteCreator { + private static final Logger LOG = LoggerFactory.getLogger(OpenShiftRouteCreator.class); + private static final String TLS_TERMINATION_EDGE = "edge"; + private static final String REDIRECT_INSECURE_EDGE_TERMINATION_POLICY = "Redirect"; + + public static void createRoute (final String namespace, + final String openShiftNamespaceExternalAddress, + final String serverRef, + final String serviceName, + final String deploymentName, + final String routeId, + final boolean enableTls) { + + if (openShiftNamespaceExternalAddress == null) { + throw new IllegalArgumentException("Property che.docker.ip.external must be set when using openshift."); + } + + try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) { + String routeName = generateRouteName(routeId, serverRef); + String serviceHost = generateRouteHost(routeName, openShiftNamespaceExternalAddress); + + SpecNested routeSpec = openShiftClient + .routes() + .inNamespace(namespace) + .createNew() + .withNewMetadata() + .withName(routeName) + .addToLabels(OpenShiftConnector.OPENSHIFT_DEPLOYMENT_LABEL, deploymentName) + .endMetadata() + .withNewSpec() + .withHost(serviceHost) + .withNewTo() + .withKind("Service") + .withName(serviceName) + .endTo() + .withNewPort() + .withNewTargetPort() + .withStrVal(serverRef) + .endTargetPort() + .endPort(); + + if (enableTls) { + routeSpec.withNewTls() + .withTermination(TLS_TERMINATION_EDGE) + .withInsecureEdgeTerminationPolicy(REDIRECT_INSECURE_EDGE_TERMINATION_POLICY) + .endTls(); + } + + Route route = routeSpec.endSpec().done(); + + LOG.info("OpenShift route {} created", route.getMetadata().getName()); + } + } + + private static String generateRouteName(final String serviceName, final String serverRef) { + return serverRef + "-" + serviceName; + } + + private static String generateRouteHost(final String routeName, final String openShiftNamespaceExternalAddress) { + return routeName + "-" + openShiftNamespaceExternalAddress; + } +} diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleaner.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleaner.java new file mode 100644 index 0000000000..85afdad7e1 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleaner.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * 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.openshift.client; + +import static com.google.common.base.Strings.isNullOrEmpty; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.event.ServerIdleEvent; +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.workspace.server.WorkspaceFilesCleaner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; + +/** + * Class used to remove workspace directories in Persistent Volume when a workspace + * is delete while running on OpenShift. Deleted workspace directories are stored + * in a list. Upon Che server idling, all of these workspaces are deleted simultaneously + * from the PVC using a {@link OpenShiftPvcHelper} job. + *

+ * Since deleting a workspace does not immediately remove its files, re-creating a workspace + * with a previously used name can result in files from the previous workspace still being + * present. + * + * @see WorkspaceFilesCleaner + * @author amisevsk + */ +@Singleton +public class OpenShiftWorkspaceFilesCleaner implements WorkspaceFilesCleaner { + + private static final Logger LOG = LoggerFactory.getLogger(OpenShiftConnector.class); + private static final Set deleteQueue = ConcurrentHashMap.newKeySet(); + private final String projectNamespace; + private final String workspacesPvcName; + private final OpenShiftPvcHelper openShiftPvcHelper; + + @Inject + public OpenShiftWorkspaceFilesCleaner(EventService eventService, + OpenShiftPvcHelper openShiftPvcHelper, + @Named("che.openshift.project") String projectNamespace, + @Named("che.openshift.workspaces.pvc.name") String workspacesPvcName) { + this.projectNamespace = projectNamespace; + this.workspacesPvcName = workspacesPvcName; + this.openShiftPvcHelper = openShiftPvcHelper; + eventService.subscribe(new EventSubscriber() { + @Override + public void onEvent(ServerIdleEvent event) { + deleteWorkspacesInQueue(event); + } + }); + } + + @Override + public void clear(Workspace workspace) throws IOException, ServerException { + String workspaceName = workspace.getConfig().getName(); + if (isNullOrEmpty(workspaceName)) { + LOG.error("Could not get workspace name for files removal."); + return; + } + deleteQueue.add(workspaceName); + } + + private void deleteWorkspacesInQueue(ServerIdleEvent event) { + List deleteQueueCopy = new ArrayList<>(deleteQueue); + String[] dirsToDelete = deleteQueueCopy.toArray(new String[deleteQueueCopy.size()]); + + LOG.info("Deleting {} workspaces on PVC {}", deleteQueueCopy.size(), workspacesPvcName); + boolean successful = openShiftPvcHelper.createJobPod(workspacesPvcName, + projectNamespace, + "delete-", + OpenShiftPvcHelper.Command.REMOVE, + dirsToDelete); + if (successful) { + deleteQueue.removeAll(deleteQueueCopy); + } + } + + /** + * Clears the list of workspace directories to be deleted. Necessary for testing. + */ + @VisibleForTesting + protected static void clearDeleteQueue() { + deleteQueue.clear(); + } +} diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainer.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainer.java index dc4c0a6680..a37b59fc56 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainer.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainer.java @@ -47,7 +47,7 @@ public final class KubernetesContainer { int portNumber = Integer.parseInt(port); String portName = CheServicePorts.get().get(portNumber); - portName = isNullOrEmpty(portName) ? exposedPort.replace("/", "-") : portName; + portName = isNullOrEmpty(portName) ? "server-" + exposedPort.replace("/", "-") : portName; ContainerPort containerPort = new ContainerPortBuilder().withName(portName).withProtocol(protocol) .withContainerPort(portNumber).build(); diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesExecHolder.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesExecHolder.java new file mode 100644 index 0000000000..ad0af92e11 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesExecHolder.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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.openshift.client.kubernetes; + +import java.util.Arrays; + +import org.eclipse.che.plugin.openshift.client.OpenShiftConnector; + +/** + * Holder class for metadata about an exec, to be used with {@link OpenShiftConnector}. + * + *

In OpenShift, {@code createExec()} is not separate from {@code startExec()}, + * so this class has to be used to pass data between {@code createExec()} and + * {@code startExec()} calls. + * + * @see OpenShiftConnector#createExec(org.eclipse.che.plugin.docker.client.params.CreateExecParams) + * @see OpenShiftConnector#startExec(org.eclipse.che.plugin.docker.client.params.StartExecParams, org.eclipse.che.plugin.docker.client.MessageProcessor) + */ +public class KubernetesExecHolder { + + private String[] command; + private String podName; + + public KubernetesExecHolder withCommand(String[] command) { + this.command = command; + return this; + } + + public KubernetesExecHolder withPod(String podName) { + this.podName = podName; + return this; + } + + public String[] getCommand() { + return command; + } + + public String getPod() { + return podName; + } + + public String toString() { + return String.format("KubernetesExecHolder {command=%s, podName=%s}", + Arrays.asList(command).toString(), + podName); + } +} diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverter.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverter.java index e499117dec..2931e36ab5 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverter.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverter.java @@ -64,6 +64,9 @@ public final class KubernetesLabelConverter { */ public static Map labelsToNames(Map labels) { Map names = new HashMap<>(); + if (labels == null) { + return names; + } for (Map.Entry label : labels.entrySet()) { if (!hasConversionProblems(label)) { @@ -103,6 +106,9 @@ public final class KubernetesLabelConverter { */ public static Map namesToLabels(Map names) { Map labels = new HashMap<>(); + if (names == null) { + return labels; + } for (Map.Entry entry: names.entrySet()){ String key = entry.getKey(); String value = entry.getValue(); diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapter.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapter.java new file mode 100644 index 0000000000..2d87a77053 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapter.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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.openshift.client.kubernetes; + +import io.fabric8.kubernetes.client.Callback; +import io.fabric8.kubernetes.client.utils.InputStreamPumper; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.plugin.docker.client.LogMessage; +import org.eclipse.che.plugin.docker.client.MessageProcessor; + +/** + * Adapter class for passing data from a {@code kubernetes-client} output stream (e.g. + * for an exec call) to {@link MessageProcessor}. This class should be passed to a + * {@link InputStreamPumper} along with the output of the exec call. + * + *

Output passed in via the {@link #call(byte[])} method is parsed into lines, + * (respecting {@code '\n'} and {@code CRLF} as line separators), and + * passed to the {@link MessageProcessor} as {@link LogMessage}s. + */ +public class KubernetesOutputAdapter implements Callback { + + private LogMessage.Type type; + private MessageProcessor execOutputProcessor; + private StringBuilder lineBuffer; + + /** + * Create a new KubernetesOutputAdapter + * + * @param type + * the type of LogMessages being passed to the MessageProcessor + * @param processor + * the processor receiving LogMessages. If null, calling {@link #call(byte[])} + * will return immediately. + */ + public KubernetesOutputAdapter(LogMessage.Type type, + @Nullable MessageProcessor processor) { + this.type = type; + this.execOutputProcessor = processor; + this.lineBuffer = new StringBuilder(); + } + + @Override + public void call(byte[] data) { + if (data == null || data.length == 0 || execOutputProcessor == null) { + return; + } + int start = 0; + int offset = 0; + + for (int pos = 0; pos < data.length; pos++) { + if (data[pos] == '\n' || data[pos] == '\r') { + offset = pos - start; + String line = new String(data, start, offset); + lineBuffer.append(line); + execOutputProcessor.process(new LogMessage(type, lineBuffer.toString())); + lineBuffer.setLength(0); + if (data[pos] == '\r') { + pos += 1; + } + start = pos + 1; + } + } + String trailingChars = new String(data, start, data.length - start); + lineBuffer.append(trailingChars); + } +} diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesService.java b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesService.java index 33e62b16e5..df179410df 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesService.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/main/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesService.java @@ -47,7 +47,7 @@ public final class KubernetesService { int portNumber = Integer.parseInt(port); String portName = CheServicePorts.get().get(portNumber); - portName = isNullOrEmpty(portName) ? exposedPort.replace("/", "-") : portName; + portName = isNullOrEmpty(portName) ? "server-" + exposedPort.replace("/", "-") : portName; int targetPortNumber = portNumber; ServicePort servicePort = new ServicePort(); diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnectorTest.java b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnectorTest.java index b9949ab36c..3726af54d3 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnectorTest.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftConnectorTest.java @@ -16,6 +16,7 @@ import static org.testng.Assert.assertEquals; import java.io.IOException; +import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.plugin.docker.client.DockerApiVersionPathPrefixProvider; import org.eclipse.che.plugin.docker.client.DockerConnectorConfiguration; import org.eclipse.che.plugin.docker.client.DockerRegistryAuthResolver; @@ -31,9 +32,17 @@ import org.testng.annotations.Test; public class OpenShiftConnectorTest { private static final String[] CONTAINER_ENV_VARIABLES = {"CHE_WORKSPACE_ID=abcd1234"}; private static final String CHE_DEFAULT_OPENSHIFT_PROJECT_NAME = "eclipse-che"; - private static final String CHE_DEFAULT_OPENSHIFT_SERVICEACCOUNT = "cheserviceaccount"; private static final int OPENSHIFT_LIVENESS_PROBE_DELAY = 300; private static final int OPENSHIFT_LIVENESS_PROBE_TIMEOUT = 1; + private static final String OPENSHIFT_DEFAULT_WORKSPACE_PERSISTENT_VOLUME_CLAIM = "che_claim_data"; + private static final String OPENSHIFT_DEFAULT_WORKSPACE_QUANTITY = "10Gi"; + private static final String OPENSHIFT_DEFAULT_WORKSPACE_STORAGE = "/data/workspaces"; + private static final String OPENSHIFT_DEFAULT_WORKSPACE_PROJECTS_STORAGE = "/projects"; + private static final String CHE_DEFAULT_SERVER_EXTERNAL_ADDRESS = "che.openshift.mini"; + private static final String CHE_WORKSPACE_CPU_LIMIT = "1"; + private static final boolean SECURE_ROUTES = false; + private static final boolean CREATE_WORKSPACE_DIRS = true; + @Mock private DockerConnectorConfiguration dockerConnectorConfiguration; @@ -45,6 +54,10 @@ public class OpenShiftConnectorTest { private DockerApiVersionPathPrefixProvider dockerApiVersionPathPrefixProvider; @Mock private CreateContainerParams createContainerParams; + @Mock + private EventService eventService; + @Mock + private OpenShiftPvcHelper openShiftPvcHelper; private OpenShiftConnector openShiftConnector; @@ -62,10 +75,20 @@ public class OpenShiftConnectorTest { dockerConnectionFactory, authManager, dockerApiVersionPathPrefixProvider, + openShiftPvcHelper, + eventService, + CHE_DEFAULT_SERVER_EXTERNAL_ADDRESS, CHE_DEFAULT_OPENSHIFT_PROJECT_NAME, - CHE_DEFAULT_OPENSHIFT_SERVICEACCOUNT, OPENSHIFT_LIVENESS_PROBE_DELAY, - OPENSHIFT_LIVENESS_PROBE_TIMEOUT); + OPENSHIFT_LIVENESS_PROBE_TIMEOUT, + OPENSHIFT_DEFAULT_WORKSPACE_PERSISTENT_VOLUME_CLAIM, + OPENSHIFT_DEFAULT_WORKSPACE_QUANTITY, + OPENSHIFT_DEFAULT_WORKSPACE_STORAGE, + OPENSHIFT_DEFAULT_WORKSPACE_PROJECTS_STORAGE, + CHE_WORKSPACE_CPU_LIMIT, + null, + SECURE_ROUTES, + CREATE_WORKSPACE_DIRS); String workspaceID = openShiftConnector.getCheWorkspaceId(createContainerParams); //Then diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleanerTest.java b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleanerTest.java new file mode 100644 index 0000000000..828e52ae60 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/OpenShiftWorkspaceFilesCleanerTest.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * 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.openshift.client; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.event.ServerIdleEvent; +import org.eclipse.che.api.core.model.workspace.Workspace; +import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class OpenShiftWorkspaceFilesCleanerTest { + + private static final String CHE_OPENSHIFT_PROJECT = "eclipse-che"; + private static final String WORKSPACES_PVC_NAME = "che-data-volume"; + private static final String WORKSPACE_ONE = "testworkspaceone"; + private static final String WORKSPACE_TWO = "testworkspacetwo"; + + @Mock + private OpenShiftPvcHelper pvcHelper; + @Mock + private ServerIdleEvent serverIdleEvent; + private EventService eventService; + private OpenShiftWorkspaceFilesCleaner cleaner; + + @BeforeMethod + public void setup() { + OpenShiftWorkspaceFilesCleaner.clearDeleteQueue(); + MockitoAnnotations.initMocks(this); + eventService = new EventService(); + cleaner = new OpenShiftWorkspaceFilesCleaner(eventService, + pvcHelper, + CHE_OPENSHIFT_PROJECT, + WORKSPACES_PVC_NAME); + } + + @Test + public void shouldDoNothingWithoutIdleEvent() throws ServerException, IOException { + // Given + Workspace workspace = generateWorkspace(WORKSPACE_ONE); + + // When + cleaner.clear(workspace); + + // Then + verify(pvcHelper, never()).createJobPod(anyString(), + anyString(), + anyString(), + any(OpenShiftPvcHelper.Command.class), + any(String[].class)); + } + + @Test + public void shouldDeleteWorkspaceOnIdleEvent() throws ServerException, IOException { + // Given + Workspace workspace = generateWorkspace(WORKSPACE_ONE); + + // When + cleaner.clear(workspace); + eventService.publish(serverIdleEvent); + + // Then + verify(pvcHelper, times(1)).createJobPod(anyString(), + anyString(), + anyString(), + eq(OpenShiftPvcHelper.Command.REMOVE), + eq(WORKSPACE_ONE)); + } + + @Test + public void shouldDeleteMultipleQueuedWorkspacesAtOnce() throws ServerException, IOException { + // Given + Workspace workspaceOne = generateWorkspace(WORKSPACE_ONE); + Workspace workspaceTwo = generateWorkspace(WORKSPACE_TWO); + String[] expectedDirs = new String[] {WORKSPACE_ONE, WORKSPACE_TWO}; + ArgumentCaptor dirCaptor = ArgumentCaptor.forClass(String.class); + + // When + cleaner.clear(workspaceOne); + cleaner.clear(workspaceTwo); + eventService.publish(serverIdleEvent); + + // Then + verify(pvcHelper, times(1)).createJobPod(anyString(), + anyString(), + anyString(), + eq(OpenShiftPvcHelper.Command.REMOVE), + dirCaptor.capture(), // Varargs capture doesn't seem to work. + dirCaptor.capture()); + + List dirs = dirCaptor.getAllValues(); + String[] actualDirs = dirs.toArray(new String[dirs.size()]); + // Sort arrays to ignore order + Arrays.sort(actualDirs); + Arrays.sort(expectedDirs); + assertEquals(actualDirs, expectedDirs, "Expected all dirs to be deleted when server is idled."); + } + + @Test + public void shouldRetainQueueIfDeletionFails() throws ServerException, IOException { + // Given + Workspace workspaceOne = generateWorkspace(WORKSPACE_ONE); + when(pvcHelper.createJobPod(any(), any(), any(), any(), any())).thenReturn(false); + + // When + cleaner.clear(workspaceOne); + eventService.publish(serverIdleEvent); + + // Then + verify(pvcHelper, times(1)).createJobPod(anyString(), + anyString(), + anyString(), + eq(OpenShiftPvcHelper.Command.REMOVE), + eq(WORKSPACE_ONE)); + + // When + eventService.publish(serverIdleEvent); + + // Then + verify(pvcHelper, times(2)).createJobPod(anyString(), + anyString(), + anyString(), + eq(OpenShiftPvcHelper.Command.REMOVE), + eq(WORKSPACE_ONE)); + } + + @Test + public void shouldUseProjectNamespaceAndPvcNameAsParameters() throws ServerException, IOException { + // Given + Workspace workspaceOne = generateWorkspace(WORKSPACE_ONE); + + // When + cleaner.clear(workspaceOne); + eventService.publish(serverIdleEvent); + + // Then + verify(pvcHelper, times(1)).createJobPod(eq(WORKSPACES_PVC_NAME), + eq(CHE_OPENSHIFT_PROJECT), + anyString(), + eq(OpenShiftPvcHelper.Command.REMOVE), + eq(WORKSPACE_ONE)); + } + + private Workspace generateWorkspace(String id) { + WorkspaceConfigImpl config = new WorkspaceConfigImpl(); + config.setName(id); + return new WorkspaceImpl(id, null, config); + } +} diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainerTest.java b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainerTest.java index d3cd0be897..83c0c1dc2a 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainerTest.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesContainerTest.java @@ -44,7 +44,7 @@ public class KubernetesContainerTest { map(p -> Integer.toString(p.getContainerPort()) + "/" + p.getProtocol().toLowerCase()).collect(Collectors.toList()); - assertTrue(exposedPorts.stream().anyMatch(portsAndProtocols::contains)); + assertTrue(exposedPorts.stream().allMatch(portsAndProtocols::contains)); } @Test @@ -61,7 +61,7 @@ public class KubernetesContainerTest { map(p -> Integer.toString(p.getContainerPort()) + "/" + p.getProtocol().toLowerCase()).collect(Collectors.toList()); - assertTrue(imageExposedPorts.keySet().stream().anyMatch(portsAndProtocols::contains)); + assertTrue(imageExposedPorts.keySet().stream().allMatch(portsAndProtocols::contains)); } } diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesEnvVarTest.java b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesEnvVarTest.java index 36adea1fd2..ccb63d44b1 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesEnvVarTest.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesEnvVarTest.java @@ -44,7 +44,7 @@ public class KubernetesEnvVarTest { // Then List keysAndValues = env.stream().map(k -> k.getName() + "=" + k.getValue()).collect(Collectors.toList()); - assertTrue(Arrays.stream(envVariables).anyMatch(keysAndValues::contains)); + assertTrue(Arrays.stream(envVariables).allMatch(keysAndValues::contains)); } } diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverterTest.java b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverterTest.java index bf43eefc9d..51ad72ac30 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverterTest.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesLabelConverterTest.java @@ -16,15 +16,15 @@ import static org.testng.Assert.assertTrue; import java.util.HashMap; import java.util.Map; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class KubernetesLabelConverterTest { + private final String prefix = KubernetesLabelConverter.getCheServerLabelPrefix(); + @Test public void shouldConvertLabelsToValidKubernetesLabelNames() { String validLabelRegex = "([A-Za-z0-9][-A-Za-z0-9_\\.]*)?[A-Za-z0-9]"; - String prefix = KubernetesLabelConverter.getCheServerLabelPrefix(); // Given Map labels = new HashMap<>(); @@ -46,7 +46,6 @@ public class KubernetesLabelConverterTest { @Test public void shouldBeAbleToRecoverOriginalLabelsAfterConversion() { // Given - String prefix = KubernetesLabelConverter.getCheServerLabelPrefix(); Map originalLabels = new HashMap<>(); originalLabels.put(prefix + "4401/tcp:path:", "/api"); originalLabels.put(prefix + "8000/tcp:ref:", "tomcat-debug"); @@ -59,4 +58,58 @@ public class KubernetesLabelConverterTest { assertEquals(originalLabels, unconverted); } + @Test + public void shouldIgnoreAndLogProblemLabels() { + // Given + Map originalLabels = new HashMap<>(); + Map validLabels = new HashMap<>(); + validLabels.put(prefix + "4401/tcp:path:", "/api"); + validLabels.put(prefix + "8000/tcp:ref:", "tomcat-debug"); + Map invalidLabels = new HashMap<>(); + invalidLabels.put(prefix + "9999/t.cp:path:", "/api"); + invalidLabels.put(prefix + "1111/tcp:path:", "/a_pi"); + + originalLabels.putAll(validLabels); + originalLabels.putAll(invalidLabels); + + // When + Map converted = KubernetesLabelConverter.labelsToNames(originalLabels); + Map unconverted = KubernetesLabelConverter.namesToLabels(converted); + + // Then + assertTrue(validLabels.entrySet().stream().allMatch(unconverted.entrySet()::contains), + "Valid labels should be there when converting + unconverting"); + assertTrue(invalidLabels.entrySet().stream().noneMatch(unconverted.entrySet()::contains), + "Labels with invalid characters should be ignored"); + } + + @Test + public void shouldIgnoreEmptyValues() { + // Given + Map originalLabels = new HashMap<>(); + originalLabels.put(prefix + "4401/tcp:path:", null); + originalLabels.put(prefix + "4402/tcp:path:", ""); + originalLabels.put(prefix + "4403/tcp:path:", " "); + + // When + Map converted = KubernetesLabelConverter.labelsToNames(originalLabels); + + // Then + assertTrue(converted.isEmpty(), "Labels with null, empty, or whitespace values should be ignored"); + } + + @Test + public void shouldNotIgnoreValuesWithoutPrefix() { + // Given + Map originalLabels = new HashMap<>(); + originalLabels.put("4401/tcp:path:", "/api"); + originalLabels.put(prefix + "8000/tcp:ref:", "tomcat-debug"); + + // When + Map converted = KubernetesLabelConverter.labelsToNames(originalLabels); + + // Then + // Currently we put a warning in the logs but convert these labels anyways. + assertTrue(converted.size() == 2, "Should convert labels even without prefix"); + } } diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapterTest.java b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapterTest.java new file mode 100644 index 0000000000..8dd5a571f5 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesOutputAdapterTest.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * 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.openshift.client.kubernetes; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.che.plugin.docker.client.LogMessage; +import org.eclipse.che.plugin.docker.client.MessageProcessor; + + +public class KubernetesOutputAdapterTest { + + private static LogMessage.Type LOG_TYPE = LogMessage.Type.DOCKER; + private testMessageProcessor processor; + private KubernetesOutputAdapter adapter; + + private class testMessageProcessor implements MessageProcessor { + + private List messages; + private LogMessage.Type type = null; + + public testMessageProcessor() { + this.messages = new ArrayList<>(); + } + + @Override + public void process(LogMessage message) { + LogMessage.Type messageType = message.getType(); + if (type == null) { + type = messageType; + } + messages.add(message.getContent()); + } + + public List getMessages() { + return new ArrayList<>(messages); + } + + public LogMessage.Type getType() { + return type; + } + }; + + @BeforeMethod + public void setUp() { + processor = new testMessageProcessor(); + adapter = new KubernetesOutputAdapter(LOG_TYPE, processor); + } + + @Test + public void shouldBreakLinesCorrectly() { + // Given + byte[] input = "line1\nline2\n".getBytes(); + List expected = generateExpected("line1", "line2"); + + // When + adapter.call(input); + + // Then + List actual = processor.getMessages(); + assertEquals(actual, expected, "Should break lines on \\n char"); + } + + @Test + public void shouldCacheUnfinishedLinesBetweenCalls() { + // Given + byte[] firstInput = "line1\nlin".getBytes(); + byte[] secondInput = "e2\nline3\n".getBytes(); + List expected = generateExpected("line1", "line2", "line3"); + + // When + adapter.call(firstInput); + adapter.call(secondInput); + + // Then + List actual = processor.getMessages(); + assertEquals(actual, expected, "Should store unfinished lines between calls"); + } + + @Test + public void shouldUseProvidedLogMessageType() { + for (LogMessage.Type type : LogMessage.Type.values()) { + // Given + byte[] input = "line1\n".getBytes(); + LogMessage.Type expected = type; + processor = new testMessageProcessor(); + adapter = new KubernetesOutputAdapter(type, processor); + + // When + adapter.call(input); + + // Then + LogMessage.Type actual = processor.getType(); + assertEquals(actual, expected, "Should call MessageProcessor with provided type"); + } + } + + @Test + public void shouldBreakLinesNormallyWithCarriageReturn() { + // Given + byte[] input = "line1\r\nline2\n".getBytes(); + List expected = generateExpected("line1", "line2"); + + // When + adapter.call(input); + + // Then + List actual = processor.getMessages(); + assertEquals(actual, expected, "Should break lines normally on \\r\\n characters"); + } + + @Test + public void shouldNotIgnoreEmptyLines() { + // Given + byte[] input = "line1\n\nline2\n".getBytes(); + List expected = generateExpected("line1", "", "line2"); + + // When + adapter.call(input); + + // Then + List actual = processor.getMessages(); + assertEquals(actual, expected, "Should call processor.process() with empty Strings"); + } + + @Test + public void shouldNotCallWithoutFinalNewline() { + // Given + byte[] input = "line1\nline2".getBytes(); // No trailing \n + List firstExpected = generateExpected("line1"); + List secondExpected = generateExpected("line1", "line2"); + + // When + adapter.call(input); + + // Then + List firstActual = processor.getMessages(); + assertEquals(firstActual, firstExpected, "Should only process lines when they are terminated by \\n or \\r\\n"); + + // When + adapter.call("\n".getBytes()); + + // Then + List secondActual = processor.getMessages(); + assertEquals(secondActual, secondExpected, "Should buffer lines until newline is encountered."); + + } + + @Test + public void shouldIgnoreNullCalls() { + // Given + byte[] firstInput = "line1\n".getBytes(); + byte[] secondInput = "line2\n".getBytes(); + List expected = generateExpected("line1", "line2"); + + // When + adapter.call(firstInput); + adapter.call(null); + adapter.call(secondInput); + + // Then + List actual = processor.getMessages(); + assertEquals(actual, expected, "Should ignore calls with null arguments"); + } + + @Test + public void shouldKeepBufferPastNullCalls() { + // Given + byte[] firstInput = "lin".getBytes(); + byte[] secondInput = "e1\nline2\n".getBytes(); + List expected = generateExpected("line1", "line2"); + + // When + adapter.call(firstInput); + adapter.call(null); + adapter.call(secondInput); + + // Then + List actual = processor.getMessages(); + assertEquals(actual, expected, "Should ignore calls with null arguments"); + } + + @Test + public void shouldDoNothingWhenExecOutputProcessorIsNull() { + // Given + byte[] firstInput = "line1\n".getBytes(); + byte[] secondInput = "line2\n".getBytes(); + adapter = new KubernetesOutputAdapter(LOG_TYPE, null); + + // When + adapter.call(firstInput); + adapter.call(secondInput); + + // Then + List actual = processor.getMessages(); + assertTrue(actual.isEmpty(), "Should do nothing when ExecOutputProcessor is null"); + } + + @Test + public void shouldIgnoreCallsWhenDataIsEmpty() { + // Given + byte[] emptyInput = "".getBytes(); + byte[] firstInput = "line1\n".getBytes(); + byte[] secondInput = "line2\n".getBytes(); + List expected = generateExpected("line1", "line2"); + + // When + adapter.call(emptyInput); + adapter.call(firstInput); + adapter.call(emptyInput); + adapter.call(secondInput); + adapter.call(emptyInput); + + // Then + List actual = processor.getMessages(); + assertEquals(actual, expected, "KubernetesOutputAdapter ignore empty data calls"); + + } + + private List generateExpected(String... strings) { + List expected = new ArrayList<>(); + for (String string : strings) { + expected.add(string); + } + return expected; + } + + +} diff --git a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesServiceTest.java b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesServiceTest.java index a1b575415b..ebcc02a9cf 100644 --- a/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesServiceTest.java +++ b/plugins/plugin-docker/che-plugin-openshift-client/src/test/java/org/eclipse/che/plugin/openshift/client/kubernetes/KubernetesServiceTest.java @@ -40,7 +40,7 @@ public class KubernetesServiceTest { map(p -> Integer.toString(p.getPort()) + "/" + p.getProtocol()).collect(Collectors.toList()); - assertTrue(imageExposedPorts.keySet().stream().anyMatch(portsAndProtocols::contains)); + assertTrue(imageExposedPorts.keySet().stream().allMatch(portsAndProtocols::contains)); } @Test @@ -60,7 +60,7 @@ public class KubernetesServiceTest { map(p -> Integer.toString(p.getPort()) + "/" + p.getProtocol()).collect(Collectors.toList()); - assertTrue(exposedPorts.keySet().stream().anyMatch(portsAndProtocols::contains)); + assertTrue(exposedPorts.keySet().stream().allMatch(portsAndProtocols::contains)); } @Test @@ -73,13 +73,13 @@ public class KubernetesServiceTest { exposedPorts.put("4411/tcp",null); exposedPorts.put("4412/tcp",null); exposedPorts.put("8080/tcp",null); - exposedPorts.put("8888/tcp",null); + exposedPorts.put("8000/tcp",null); exposedPorts.put("9876/tcp",null); Set expectedPortNames = new HashSet<>(); expectedPortNames.add("sshd"); expectedPortNames.add("wsagent"); - expectedPortNames.add("wsagent-pda"); + expectedPortNames.add("wsagent-jpda"); expectedPortNames.add("terminal"); expectedPortNames.add("exec-agent"); expectedPortNames.add("tomcat"); @@ -92,7 +92,7 @@ public class KubernetesServiceTest { map(p -> p.getName()).collect(Collectors.toList()); // Then - assertTrue(actualPortNames.stream().anyMatch(expectedPortNames::contains)); + assertTrue(actualPortNames.stream().allMatch(expectedPortNames::contains)); } @Test @@ -102,7 +102,7 @@ public class KubernetesServiceTest { exposedPorts.put("55/tcp",null); Set expectedPortNames = new HashSet<>(); - expectedPortNames.add("55-tcp"); + expectedPortNames.add("server-55-tcp"); // When List servicePorts = KubernetesService.getServicePortsFrom(exposedPorts.keySet()); @@ -110,7 +110,7 @@ public class KubernetesServiceTest { map(p -> p.getName()).collect(Collectors.toList()); // Then - assertTrue(actualPortNames.stream().anyMatch(expectedPortNames::contains)); + assertTrue(actualPortNames.stream().allMatch(expectedPortNames::contains)); } } diff --git a/plugins/plugin-traefik/plugin-traefik-docker/src/test/java/org/eclipse/che/plugin/traefik/TraefikCreateContainerInterceptorTest.java b/plugins/plugin-traefik/plugin-traefik-docker/src/test/java/org/eclipse/che/plugin/traefik/TraefikCreateContainerInterceptorTest.java index 32e7b9b3eb..24db5986b2 100644 --- a/plugins/plugin-traefik/plugin-traefik-docker/src/test/java/org/eclipse/che/plugin/traefik/TraefikCreateContainerInterceptorTest.java +++ b/plugins/plugin-traefik/plugin-traefik-docker/src/test/java/org/eclipse/che/plugin/traefik/TraefikCreateContainerInterceptorTest.java @@ -116,7 +116,7 @@ public class TraefikCreateContainerInterceptorTest { when(imageInfoConfig.getExposedPorts()).thenReturn(imageExposedPorts); - envContainerConfig = new String[]{"CHE_WORKSPACE_ID=work123", "CHE_MACHINE_NAME=abcd"}; + envContainerConfig = new String[]{"CHE_WORKSPACE_ID=work123", "CHE_MACHINE_NAME=abcd", "CHE_IS_DEV_MACHINE=true"}; envImageConfig = new String[]{"HELLO"}; when(containerConfig.getEnv()).thenReturn(envContainerConfig); when(imageInfoConfig.getEnv()).thenReturn(envImageConfig); From 22fecf27d0d69427742ddfa3492bc80a1d035830 Mon Sep 17 00:00:00 2001 From: Aleksandr Andriienko Date: Wed, 5 Jul 2017 12:51:34 +0300 Subject: [PATCH 09/11] CHE-4998: Update modification stamp on open and on update document. Signed-off-by: Aleksandr Andriienko --- .../che/ide/api/resources/ModificationTracker.java | 8 ++++++++ .../org/eclipse/che/ide/resources/impl/FileImpl.java | 7 ++++++- .../che/ide/editor/orion/client/OrionDocument.java | 11 +++++++++++ .../ide/editor/orion/client/OrionEditorPresenter.java | 10 ++++++++-- .../impl/file/event/detectors/EditorFileTracker.java | 1 + 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/ModificationTracker.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/ModificationTracker.java index 03017aa6a5..52e64d6139 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/ModificationTracker.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/ModificationTracker.java @@ -30,4 +30,12 @@ public interface ModificationTracker { * @return modification tracker value */ String getModificationStamp(); + + /** + * Update modification tracker value by content. Modification tracker is a value is changed by any modification of the content + * of the file. + * + * @param content actual file content + */ + void updateModificationStamp(String content); } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/FileImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/FileImpl.java index 6dd53a794a..e01f0cfa74 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/FileImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/FileImpl.java @@ -110,7 +110,7 @@ class FileImpl extends ResourceImpl implements File { /** {@inheritDoc} */ @Override public Promise updateContent(String content) { - setModificationStamp(TextUtils.md5(content)); + updateModificationStamp(content); return resourceManager.write(this, content); } @@ -140,4 +140,9 @@ class FileImpl extends ResourceImpl implements File { public String getModificationStamp() { return modificationStamp; } + + @Override + public void updateModificationStamp(String content) { + this.modificationStamp = TextUtils.md5(content); + } } diff --git a/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionDocument.java b/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionDocument.java index 5c8635774f..aec1b91114 100644 --- a/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionDocument.java +++ b/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionDocument.java @@ -12,6 +12,8 @@ package org.eclipse.che.ide.editor.orion.client; import com.google.web.bindery.event.shared.HandlerRegistration; +import org.eclipse.che.ide.api.resources.File; +import org.eclipse.che.ide.api.resources.VirtualFile; import org.eclipse.che.ide.editor.orion.client.jso.ModelChangedEventOverlay; import org.eclipse.che.ide.editor.orion.client.jso.OrionEditorOverlay; import org.eclipse.che.ide.editor.orion.client.jso.OrionPixelPositionOverlay; @@ -197,6 +199,7 @@ public class OrionDocument extends AbstractDocument { public void replace(int offset, int length, String text) { this.editorOverlay.getModel().setText(text, offset, offset + length); + updateModificationTimeStamp(); } @Override @@ -205,6 +208,14 @@ public class OrionDocument extends AbstractDocument { int lineStart = model.getLineStart(startLine); int lineEnd = model.getLineStart(endLine); editorOverlay.setText(text, lineStart + startChar, lineEnd + endChar); + updateModificationTimeStamp(); + } + + private void updateModificationTimeStamp() { + VirtualFile file = this.getFile(); + if (file instanceof File) { + ((File)file).updateModificationStamp(editorOverlay.getText()); + } } public int getContentsCharCount() { diff --git a/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java b/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java index 7d154d6457..2af23b8253 100644 --- a/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java +++ b/ide/che-core-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java @@ -1014,7 +1014,13 @@ public class OrionEditorPresenter extends AbstractEditorPresenter implements Tex editorView.setEditorWidget(editorWidget); document = editorWidget.getDocument(); - document.setFile(input.getFile()); + final VirtualFile file = input.getFile(); + document.setFile(file); + + if (file instanceof File) { + ((File)file).updateModificationStamp(content); + } + cursorModel = new OrionCursorModel(document); editorWidget.setTabSize(configuration.getTabWidth()); @@ -1031,7 +1037,7 @@ public class OrionEditorPresenter extends AbstractEditorPresenter implements Tex if (delayedFocus) { editorWidget.refresh(); editorWidget.setFocus(); - setSelection(new Selection<>(input.getFile())); + setSelection(new Selection<>(file)); delayedFocus = false; } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/EditorFileTracker.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/EditorFileTracker.java index c0b94ce77a..935d69dc0e 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/EditorFileTracker.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/EditorFileTracker.java @@ -202,6 +202,7 @@ public class EditorFileTracker { @Override public void run() { if (!Files.exists(FileWatcherUtils.toNormalPath(root.toPath(), it))) { + hashRegistry.remove(path + endpointId); FileStateUpdateDto params = newDto(FileStateUpdateDto.class).withPath(path).withType(DELETED); transmitter.newRequest() .endpointId(endpointId) From 00421dd624355630860c0d12737e6ce39b5c83d5 Mon Sep 17 00:00:00 2001 From: Aleksandr Andriienko Date: Wed, 5 Jul 2017 13:02:16 +0300 Subject: [PATCH 10/11] CHE-5424: Fix refactor rename from 'Rename' window Signed-off-by: Aleksandr Andriienko --- .../synchronization/EditorGroupSynchronizationImpl.java | 8 ++++---- .../ext/java/client/refactoring/RefactoringUpdater.java | 7 ------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSynchronizationImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSynchronizationImpl.java index 252966daff..38f2402287 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSynchronizationImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSynchronizationImpl.java @@ -168,7 +168,7 @@ public class EditorGroupSynchronizationImpl implements EditorGroupSynchronizatio }); } - private void updateContent(String newContent, String oldStamp, VirtualFile virtualFile) { + private void updateContent(String newContent, String eventModificationStamp, VirtualFile virtualFile) { final DocumentHandle documentHandle = getDocumentHandleFor(groupLeaderEditor); if (documentHandle == null) { return; @@ -184,14 +184,14 @@ public class EditorGroupSynchronizationImpl implements EditorGroupSynchronizatio } final File file = (File)virtualFile; - final String newStamp = file.getModificationStamp(); + final String currentStamp = file.getModificationStamp(); - if (oldStamp == null && !Objects.equals(newContent, oldContent)) { + if (eventModificationStamp == null && !Objects.equals(newContent, oldContent)) { replaceContent(document, newContent, oldContent, cursorPosition); return; } - if (!Objects.equals(oldStamp, newStamp)) { + if (!Objects.equals(eventModificationStamp, currentStamp)) { replaceContent(document, newContent, oldContent, cursorPosition); notificationManager.notify("External operation", "File '" + file.getName() + "' is updated", SUCCESS, EMERGE_MODE); diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/refactoring/RefactoringUpdater.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/refactoring/RefactoringUpdater.java index ec36e265a0..a31fd3c422 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/refactoring/RefactoringUpdater.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/refactoring/RefactoringUpdater.java @@ -26,7 +26,6 @@ import org.eclipse.che.ide.api.event.ng.DeletedFilesController; import org.eclipse.che.ide.api.parts.PartPresenter; import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.resources.ExternalResourceDelta; -import org.eclipse.che.ide.api.resources.ModificationTracker; import org.eclipse.che.ide.api.resources.ResourceDelta; import org.eclipse.che.ide.api.resources.VirtualFile; import org.eclipse.che.ide.ext.java.shared.dto.refactoring.ChangeInfo; @@ -167,12 +166,6 @@ public class RefactoringUpdater { private void updateFileContent(VirtualFile virtualFile) { String path = virtualFile.getLocation().toString(); - if (virtualFile instanceof ModificationTracker) { - String modificationStamp = ((ModificationTracker)virtualFile).getModificationStamp(); - eventBus.fireEvent(new FileContentUpdateEvent(path, modificationStamp)); - return; - } - eventBus.fireEvent(new FileContentUpdateEvent(path)); } From ef74274eba9ae433368505a4de3223744edc8a6b Mon Sep 17 00:00:00 2001 From: Valeriy Svydenko Date: Wed, 5 Jul 2017 16:22:51 +0300 Subject: [PATCH 11/11] CHE-5350: rework Maven plugin to avoid using Everrest Websocket (#5527) --- .../pom.xml | 12 ++ .../archetype/ArchetypeGenerator.java | 26 ++- .../archetype/ArchetypeOutputImpl.java | 14 +- .../MavenArchetypeJsonRpcMessenger.java | 84 ++++++++ .../archetype/ArchetypeGeneratorTest.java | 5 +- .../maven/client/MavenJsonRpcHandler.java | 181 +++++++++++++++++ .../comunnication/MavenMessagesHandler.java | 189 +++++++----------- .../ResolvingMavenProjectStateHolder.java | 58 +----- .../MavenMessagesHandlerTest.java | 108 ++++------ .../maven/server/core/MavenCommunication.java | 1 + .../core/MavenJsonRpcCommunication.java | 172 ++++++++++++++++ .../server/core/MavenServerNotifier.java | 32 ++- .../core/MavenWebSocketCommunication.java | 1 + .../maven/server/core/MavenWorkspace.java | 20 +- .../maven/server/inject/MavenModule.java | 4 + .../plugin/maven/server/WorkspaceTest.java | 23 +-- .../classpath/ClasspathManagerTest.java | 26 +-- .../core/reconcile/PomReconcilerTest.java | 30 +-- .../plugin/maven/shared/MavenAttributes.java | 17 +- .../maven/shared/dto/ArchetypeOutput.java | 3 + .../maven/shared/dto/MavenOutputEventDto.java | 28 +++ .../maven/shared/dto/NotificationMessage.java | 1 + .../maven/shared/dto/PercentMessageDto.java | 26 +++ .../dto/PercentUndefinedMessageDto.java | 24 +++ .../shared/dto/ProjectsUpdateMessage.java | 2 +- .../shared/dto/StartStopNotification.java | 2 +- .../maven/shared/dto/TextMessageDto.java | 27 +++ .../maven/shared/event/MavenOutputEvent.java | 27 +++ .../event/MavenPercentMessageEvent.java | 19 ++ .../event/MavenPercentUndefinedEvent.java | 18 ++ .../shared/event/MavenStartStopEvent.java | 19 ++ .../shared/event/MavenTextMessageEvent.java | 19 ++ .../maven/shared/event/MavenUpdateEvent.java | 24 +++ .../shared/impl/MavenOutputEventImpl.java | 45 +++++ .../shared/impl/MavenPercentEventImpl.java | 50 +++++ .../impl/MavenPercentUndefinedEventImpl.java | 50 +++++ .../shared/impl/MavenStartStopEventImpl.java | 50 +++++ .../impl/MavenTextMessageEventImpl.java | 49 +++++ .../shared/impl/MavenUpdateEventImpl.java | 58 ++++++ plugins/pom.xml | 2 +- 40 files changed, 1197 insertions(+), 349 deletions(-) create mode 100644 plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/MavenArchetypeJsonRpcMessenger.java create mode 100644 plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenJsonRpcHandler.java create mode 100644 plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenJsonRpcCommunication.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/MavenOutputEventDto.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentMessageDto.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentUndefinedMessageDto.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/TextMessageDto.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenOutputEvent.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentMessageEvent.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentUndefinedEvent.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenStartStopEvent.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenTextMessageEvent.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenUpdateEvent.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenOutputEventImpl.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentEventImpl.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentUndefinedEventImpl.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenStartStopEventImpl.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenTextMessageEventImpl.java create mode 100644 plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenUpdateEventImpl.java diff --git a/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml b/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml index 0d149dee4d..babf7bf85b 100644 --- a/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml @@ -30,6 +30,18 @@ com.google.code.gson gson + + com.google.guava + guava + + + com.google.inject + guice + + + javax.annotation + javax.annotation-api + javax.inject javax.inject diff --git a/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGenerator.java b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGenerator.java index 106dc3bb4c..70aaa92fba 100644 --- a/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGenerator.java +++ b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGenerator.java @@ -11,13 +11,13 @@ package org.eclipse.che.plugin.maven.generator.archetype; import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.core.util.AbstractLineConsumer; import org.eclipse.che.api.core.util.CommandLine; import org.eclipse.che.api.core.util.LineConsumer; import org.eclipse.che.api.core.util.ProcessUtil; import org.eclipse.che.api.core.util.ValueHolder; import org.eclipse.che.api.core.util.Watchdog; -import org.eclipse.che.api.core.util.WebsocketMessageConsumer; import org.eclipse.che.ide.maven.tools.MavenArtifact; import org.eclipse.che.ide.maven.tools.MavenUtils; import org.eclipse.che.plugin.maven.shared.MavenArchetype; @@ -25,6 +25,7 @@ import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.inject.Inject; import javax.inject.Singleton; import javax.validation.constraints.NotNull; import java.io.File; @@ -35,7 +36,8 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_NAME; +import static org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput.State.DONE; +import static org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput.State.ERROR; /** * Generates projects with maven-archetype-plugin. @@ -46,6 +48,13 @@ import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYP public class ArchetypeGenerator { private static final Logger LOG = LoggerFactory.getLogger(ArchetypeGenerator.class); + private EventService eventService; + + @Inject + public ArchetypeGenerator(EventService eventService) { + this.eventService = eventService; + } + /** * Generates a new project from the specified archetype by given maven artifact descriptor. * @param workDir @@ -100,12 +109,13 @@ public class ArchetypeGenerator { */ private void execute(String[] commandLine, File workDir) throws TimeoutException, IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder(commandLine).redirectErrorStream(true).directory(workDir); - WebsocketMessageConsumer websocketMessageConsumer = new WebsocketMessageConsumer(MAVEN_ARCHETYPE_CHANEL_NAME); - websocketMessageConsumer.consume(new ArchetypeOutputImpl("Start Project generation", ArchetypeOutput.State.START)); + + eventService.publish(new ArchetypeOutputImpl("Start Project generation", ArchetypeOutput.State.START)); + LineConsumer lineConsumer = new AbstractLineConsumer() { @Override public void writeLine(String line) throws IOException { - websocketMessageConsumer.consume(new ArchetypeOutputImpl(line, ArchetypeOutput.State.IN_PROGRESS)); + eventService.publish(new ArchetypeOutputImpl(line, ArchetypeOutput.State.IN_PROGRESS)); } }; @@ -122,14 +132,14 @@ public class ArchetypeGenerator { // consume logs until process ends ProcessUtil.process(process, lineConsumer); process.waitFor(); - websocketMessageConsumer.consume(new ArchetypeOutputImpl("Done", ArchetypeOutput.State.DONE)); + eventService.publish(new ArchetypeOutputImpl("Done", DONE)); if (isTimeoutExceeded.get()) { LOG.error("Generation project time expired : command-line " + Arrays.toString(commandLine)); - websocketMessageConsumer.consume(new ArchetypeOutputImpl("Generation project time expired", ArchetypeOutput.State.ERROR)); + eventService.publish(new ArchetypeOutputImpl("Generation project time expired", ERROR)); throw new TimeoutException(); } else if (process.exitValue() != 0) { LOG.error("Generation project fail : command-line " + Arrays.toString(commandLine)); - websocketMessageConsumer.consume(new ArchetypeOutputImpl("Generation project occurs error", ArchetypeOutput.State.ERROR)); + eventService.publish(new ArchetypeOutputImpl("Generation project occurs error", ERROR)); throw new IOException("Process failed. Exit code " + process.exitValue() + " command-line : " + Arrays.toString(commandLine)); } } finally { diff --git a/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeOutputImpl.java b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeOutputImpl.java index 66b92bf0d3..5414cb5268 100644 --- a/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeOutputImpl.java +++ b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeOutputImpl.java @@ -13,14 +13,12 @@ package org.eclipse.che.plugin.maven.generator.archetype; import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput; /** + * Describes information about output object of maven archetype project generation. * * @author Vitalii Parfonov */ public class ArchetypeOutputImpl implements ArchetypeOutput { - - private String output; - private State state; public ArchetypeOutputImpl(String output, State state) { @@ -37,4 +35,14 @@ public class ArchetypeOutputImpl implements ArchetypeOutput { public State getState() { return state; } + + @Override + public void setOutput(String output) { + this.output = output; + } + + @Override + public void setState(State state) { + this.state = state; + } } diff --git a/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/MavenArchetypeJsonRpcMessenger.java b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/MavenArchetypeJsonRpcMessenger.java new file mode 100644 index 0000000000..af3cd9f87d --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/main/java/org/eclipse/che/plugin/maven/generator/archetype/MavenArchetypeJsonRpcMessenger.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.generator.archetype; + +import com.google.inject.Singleton; + +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.dto.server.DtoFactory; +import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import java.util.Set; + +import static com.google.common.collect.Sets.newConcurrentHashSet; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_OUTPUT; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_UNSUBSCRIBE; + +/** + * Mechanism which sends events of maven archetype generation by using JSON RPC to the client. + */ +@Singleton +public class MavenArchetypeJsonRpcMessenger implements EventSubscriber { + private final Set endpointIds = newConcurrentHashSet(); + private EventService eventService; + private RequestTransmitter transmitter; + + @Inject + public MavenArchetypeJsonRpcMessenger(EventService eventService, RequestTransmitter transmitter) { + this.eventService = eventService; + this.transmitter = transmitter; + } + + @PostConstruct + private void subscribe() { + eventService.subscribe(this); + } + + @PreDestroy + private void unsubscribe() { + eventService.unsubscribe(this); + } + + @Inject + private void configureHandlers(RequestHandlerConfigurator configurator) { + configurator.newConfiguration() + .methodName(MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE) + .noParams() + .noResult() + .withConsumer(endpointIds::add); + + configurator.newConfiguration() + .methodName(MAVEN_ARCHETYPE_CHANEL_UNSUBSCRIBE) + .noParams() + .noResult() + .withConsumer(endpointIds::remove); + } + + @Override + public void onEvent(ArchetypeOutput event) { + ArchetypeOutput archetypeOutput = DtoFactory.newDto(ArchetypeOutput.class); + archetypeOutput.setOutput(event.getOutput()); + archetypeOutput.setState(event.getState()); + + endpointIds.forEach(it -> transmitter.newRequest() + .endpointId(it) + .methodName(MAVEN_ARCHETYPE_CHANEL_OUTPUT) + .paramsAsDto(archetypeOutput) + .sendAndSkipResult()); + } +} diff --git a/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/test/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGeneratorTest.java b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/test/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGeneratorTest.java index 5182b1348c..51420035a3 100644 --- a/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/test/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGeneratorTest.java +++ b/plugins/plugin-maven/che-plugin-maven-generator-archetype/src/test/java/org/eclipse/che/plugin/maven/generator/archetype/ArchetypeGeneratorTest.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.plugin.maven.generator.archetype; +import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.commons.lang.NameGenerator; import org.eclipse.che.ide.maven.tools.MavenArtifact; import org.eclipse.che.plugin.maven.shared.MavenArchetype; @@ -26,6 +27,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** + * Test for {@link ArchetypeGenerator} * * @author Vitalii Parfonov */ @@ -36,11 +38,12 @@ public class ArchetypeGeneratorTest { @Ignore public void generateFromArchetype() throws Exception { MavenArchetype mavenArchetype = mock(MavenArchetype.class); + EventService eventService = mock(EventService.class); when(mavenArchetype.getArtifactId()).thenReturn("tomee-webapp-archetype"); when(mavenArchetype.getGroupId()).thenReturn("org.apache.openejb.maven"); when(mavenArchetype.getVersion()).thenReturn("1.7.1"); File workDir = Files.createTempDirectory("workDir").toFile(); - ArchetypeGenerator archetypeGenerator = new ArchetypeGenerator(); + ArchetypeGenerator archetypeGenerator = new ArchetypeGenerator(eventService); String artifactId = NameGenerator.generate("artifactId", 5); String groupId = NameGenerator.generate("groupId", 5); MavenArtifact mavenArtifact = new MavenArtifact(); diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenJsonRpcHandler.java b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenJsonRpcHandler.java new file mode 100644 index 0000000000..62530277c0 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenJsonRpcHandler.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.client; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator; +import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter; +import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput; +import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto; +import org.eclipse.che.plugin.maven.shared.dto.PercentUndefinedMessageDto; +import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage; +import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification; +import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; + +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_OUTPUT; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_SUBSCRIBE; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_START_STOP_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_TEXT_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_UPDATE_METHOD; + +/** + * A mechanism for handling all messages from the Maven server and applying registered consumers. + */ +@Singleton +public class MavenJsonRpcHandler { + private static final String WS_AGENT_ENDPOINT = "ws-agent"; + + private RequestHandlerConfigurator configurator; + + private Set> textConsumers = new HashSet<>(); + private Set> startStopConsumers = new HashSet<>(); + private Set> percentUndefinedConsumers = new HashSet<>(); + private Set> percentConsumers = new HashSet<>(); + private Set> projectsUpdateConsumers = new HashSet<>(); + private Set> archetypeOutputConsumers = new HashSet<>(); + + private boolean isSubscribed = false; + + @Inject + public MavenJsonRpcHandler(RequestHandlerConfigurator configurator) { + this.configurator = configurator; + + handleMavenServerMessages(); + } + + @Inject + private void subscribe(RequestTransmitter requestTransmitter) { + if (isSubscribed) { + return; + } + + requestTransmitter.newRequest() + .endpointId(WS_AGENT_ENDPOINT) + .methodName(MAVEN_CHANEL_SUBSCRIBE) + .noParams() + .sendAndSkipResult(); + + requestTransmitter.newRequest() + .endpointId(WS_AGENT_ENDPOINT) + .methodName(MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE) + .noParams() + .sendAndSkipResult(); + + isSubscribed = true; + } + + /** + * Adds consumer for the event with {@link TextMessageDto}. + * + * @param consumer + * new consumer + */ + public void addTextHandler(Consumer consumer) { + textConsumers.add(consumer); + } + + /** + * Adds consumer for the event with {@link StartStopNotification}. + * + * @param consumer + * new consumer + */ + public void addStartStopHandler(Consumer consumer) { + startStopConsumers.add(consumer); + } + + /** + * Adds consumer for the event with {@link PercentUndefinedMessageDto}. + * + * @param consumer + * new consumer + */ + public void addPercentUndefinedHandler(Consumer consumer) { + percentUndefinedConsumers.add(consumer); + } + + /** + * Adds consumer for the event with {@link PercentMessageDto}. + * + * @param consumer + * new consumer + */ + public void addPercentHandler(Consumer consumer) { + percentConsumers.add(consumer); + } + + /** + * Adds consumer for the event with {@link ProjectsUpdateMessage}. + * + * @param consumer + * new consumer + */ + public void addProjectsUpdateHandler(Consumer consumer) { + projectsUpdateConsumers.add(consumer); + } + + /** + * Adds consumer for the event with {@link ArchetypeOutput}. + * + * @param consumer + * new consumer + */ + public void addArchetypeOutputHandler(Consumer consumer) { + archetypeOutputConsumers.add(consumer); + } + + private void handleMavenServerMessages() { + configurator.newConfiguration() + .methodName(MAVEN_OUTPUT_TEXT_METHOD) + .paramsAsDto(TextMessageDto.class) + .noResult() + .withConsumer(textNotification -> textConsumers.forEach(it -> it.accept(textNotification))); + + configurator.newConfiguration() + .methodName(MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD) + .paramsAsDto(PercentUndefinedMessageDto.class) + .noResult() + .withConsumer(percentUndefinedMessage -> percentUndefinedConsumers.forEach(it -> it.accept(percentUndefinedMessage))); + + configurator.newConfiguration() + .methodName(MAVEN_OUTPUT_PERCENT_METHOD) + .paramsAsDto(PercentMessageDto.class) + .noResult() + .withConsumer(percentMessage -> percentConsumers.forEach(it -> it.accept(percentMessage))); + + configurator.newConfiguration() + .methodName(MAVEN_OUTPUT_START_STOP_METHOD) + .paramsAsDto(StartStopNotification.class) + .noResult() + .withConsumer(startStopNotification -> startStopConsumers.forEach(it -> it.accept(startStopNotification))); + + configurator.newConfiguration() + .methodName(MAVEN_OUTPUT_UPDATE_METHOD) + .paramsAsDto(ProjectsUpdateMessage.class) + .noResult() + .withConsumer(projectsUpdateMessage -> projectsUpdateConsumers.forEach(it -> it.accept(projectsUpdateMessage))); + + configurator.newConfiguration() + .methodName(MAVEN_ARCHETYPE_CHANEL_OUTPUT) + .paramsAsDto(ArchetypeOutput.class) + .noResult() + .withConsumer(archetypeOutput -> archetypeOutputConsumers.forEach(it -> it.accept(archetypeOutput))); + } +} diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandler.java b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandler.java index 09eda6d3db..a294c7c58f 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandler.java +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandler.java @@ -10,41 +10,27 @@ *******************************************************************************/ package org.eclipse.che.plugin.maven.client.comunnication; -import elemental.json.Json; -import elemental.json.JsonObject; - import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.machine.WsAgentStateController; -import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; -import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; import org.eclipse.che.ide.console.CommandConsoleFactory; import org.eclipse.che.ide.console.DefaultOutputConsole; -import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; -import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.MessageBus; -import org.eclipse.che.ide.websocket.WebSocketException; -import org.eclipse.che.ide.websocket.events.MessageHandler; +import org.eclipse.che.plugin.maven.client.MavenJsonRpcHandler; import org.eclipse.che.plugin.maven.client.comunnication.progressor.background.BackgroundLoaderPresenter; -import org.eclipse.che.plugin.maven.shared.MessageType; import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput; -import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage; +import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto; import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage; import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification; +import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto; import java.util.List; import java.util.Set; import static java.util.stream.Collectors.toSet; -import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_NAME; -import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_NAME; /** * Handler which receives messages from the maven server. @@ -54,127 +40,70 @@ import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_N */ @Singleton public class MavenMessagesHandler { - private final EventBus eventBus; - private final DtoFactory factory; private final BackgroundLoaderPresenter dependencyResolver; private final PomEditorReconciler pomEditorReconciler; private final ProcessesPanelPresenter processesPanelPresenter; - private final CommandConsoleFactory commandConsoleFactory; private final AppContext appContext; + private DefaultOutputConsole outputConsole; + @Inject public MavenMessagesHandler(EventBus eventBus, - DtoFactory factory, + MavenJsonRpcHandler mavenJsonRpcHandler, BackgroundLoaderPresenter dependencyResolver, PomEditorReconciler pomEditorReconciler, - WsAgentStateController wsAgentStateController, ProcessesPanelPresenter processesPanelPresenter, CommandConsoleFactory commandConsoleFactory, AppContext appContext) { this.eventBus = eventBus; - this.factory = factory; - this.dependencyResolver = dependencyResolver; this.pomEditorReconciler = pomEditorReconciler; this.processesPanelPresenter = processesPanelPresenter; - this.commandConsoleFactory = commandConsoleFactory; this.appContext = appContext; - handleOperations(wsAgentStateController); + mavenJsonRpcHandler.addTextHandler(this::handleTextNotification); + mavenJsonRpcHandler.addStartStopHandler(this::handleStartStop); + mavenJsonRpcHandler.addPercentHandler(this::handlePercentNotification); + mavenJsonRpcHandler.addProjectsUpdateHandler(this::handleUpdate); + mavenJsonRpcHandler.addArchetypeOutputHandler(this::onMavenArchetypeReceive); + + handleOperations(); + outputConsole = (DefaultOutputConsole)commandConsoleFactory.create("Maven Archetype"); } - private void handleOperations(final WsAgentStateController wsAgentStateController) { - eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() { - @Override - public void onWsAgentStarted(WsAgentStateEvent event) { - wsAgentStateController.getMessageBus().then(new Operation() { - @Override - public void apply(MessageBus messageBus) throws OperationException { - try { - handleMavenServerEvents(messageBus); - handleMavenArchetype(messageBus); - } catch (WebSocketException e) { - dependencyResolver.hide(); - Log.error(getClass(), e); - } - } - }); - } - - @Override - public void onWsAgentStopped(WsAgentStateEvent event) { - dependencyResolver.hide(); - } - }); - + private void handleOperations() { eventBus.addHandler(WorkspaceStoppedEvent.TYPE, event -> dependencyResolver.hide()); } - - private void handleMavenServerEvents(final MessageBus messageBus) throws WebSocketException { - messageBus.subscribe(MAVEN_CHANEL_NAME, new MessageHandler() { - @Override - public void onMessage(String message) { - final JsonObject jsonObject = Json.parse(message); - final int type = (int)jsonObject.getNumber("$type"); - MessageType messageType = MessageType.valueOf(type); - switch (messageType) { - case NOTIFICATION: - NotificationMessage dto = factory.createDtoFromJson(message, NotificationMessage.class); - handleNotification(dto); - break; - - case UPDATE: - handleUpdate(factory.createDtoFromJson(message, ProjectsUpdateMessage.class)); - break; - - case START_STOP: - handleStartStop(factory.createDtoFromJson(message, StartStopNotification.class)); - break; - - default: - Log.error(getClass(), "Unknown message type:" + messageType); - } - } - }); + /** + * Updates progress bar when the percent of project resolving is changed. + * + * @param percentMessageDto + * object with value of percent + */ + protected void handlePercentNotification(PercentMessageDto percentMessageDto) { + dependencyResolver.updateProgressBar((int)(percentMessageDto.getPercent() * 100)); } - private void handleMavenArchetype(final MessageBus messageBus) { - final DefaultOutputConsole outputConsole = (DefaultOutputConsole)commandConsoleFactory.create("Maven Archetype"); - - try { - messageBus.subscribe(MAVEN_ARCHETYPE_CHANEL_NAME, new MessageHandler() { - @Override - public void onMessage(String message) { - Log.info(getClass(), message); - ArchetypeOutput archetypeOutput = factory.createDtoFromJson(message, ArchetypeOutput.class); - processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole); - switch (archetypeOutput.getState()) { - case START: - outputConsole.clearOutputsButtonClicked(); - outputConsole.printText(archetypeOutput.getOutput(), "green"); - break; - case IN_PROGRESS: - outputConsole.printText(archetypeOutput.getOutput()); - break; - case DONE: - outputConsole.printText(archetypeOutput.getOutput(), "green"); - break; - case ERROR: - outputConsole.printText(archetypeOutput.getOutput(), "red"); - break; - default: - break; - } - } - }); - } catch (WebSocketException e) { - e.printStackTrace(); - } + /** + * Updates progress label when the resolved project is changed. + * + * @param textMessageDto + * object with name of new label + */ + protected void handleTextNotification(TextMessageDto textMessageDto) { + dependencyResolver.show(); + dependencyResolver.setProgressLabel(textMessageDto.getText()); } - private void handleStartStop(StartStopNotification dto) { + /** + * Hides or shows a progress bar. + * + * @param dto + * describes a state of the project resolving + */ + protected void handleStartStop(StartStopNotification dto) { if (dto.isStart()) { dependencyResolver.show(); } else { @@ -182,7 +111,13 @@ public class MavenMessagesHandler { } } - private void handleUpdate(ProjectsUpdateMessage dto) { + /** + * Updates the tree of projects which were modified. + * + * @param dto + * describes a projects which were modified + */ + protected void handleUpdate(ProjectsUpdateMessage dto) { List updatedProjects = dto.getUpdatedProjects(); Set projectToRefresh = computeUniqueHiLevelProjects(updatedProjects); for (final String path : projectToRefresh) { @@ -196,24 +131,38 @@ public class MavenMessagesHandler { pomEditorReconciler.reconcilePoms(updatedProjects); } + private void onMavenArchetypeReceive(ArchetypeOutput output) { + String message = output.getOutput(); + switch (output.getState()) { + case START: + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole); + outputConsole.clearOutputsButtonClicked(); + outputConsole.printText(message, "green"); + break; + case IN_PROGRESS: + outputConsole.printText(message); + break; + case DONE: + outputConsole.printText(message, "green"); + break; + case ERROR: + outputConsole.printText(message, "red"); + break; + default: + break; + } + } + private Set computeUniqueHiLevelProjects(List updatedProjects) { return updatedProjects.stream().filter(each -> shouldBeUpdated(updatedProjects, each)).collect(toSet()); } private boolean shouldBeUpdated(List updatedProjects, String project) { for (String each : updatedProjects) { - if (!project.equals(each) && project.startsWith(each)){ + if (!project.equals(each) && project.startsWith(each)) { return false; } } return true; } - - private void handleNotification(NotificationMessage message) { - if (message.getPercent() != 0) { - dependencyResolver.updateProgressBar((int)(message.getPercent() * 100)); - } else { - dependencyResolver.setProgressLabel(message.getText()); - } - } } diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/project/ResolvingMavenProjectStateHolder.java b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/project/ResolvingMavenProjectStateHolder.java index 822bcaca96..e4c4cde838 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/project/ResolvingMavenProjectStateHolder.java +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/project/ResolvingMavenProjectStateHolder.java @@ -15,19 +15,8 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.ide.api.machine.WsAgentStateController; -import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; -import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; -import org.eclipse.che.ide.collections.Jso; -import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.project.ResolvingProjectStateHolder; -import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.MessageBus; -import org.eclipse.che.ide.websocket.WebSocketException; -import org.eclipse.che.ide.websocket.events.MessageHandler; -import org.eclipse.che.plugin.maven.shared.MessageType; +import org.eclipse.che.plugin.maven.client.MavenJsonRpcHandler; import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification; import java.util.HashSet; @@ -35,9 +24,7 @@ import java.util.HashSet; import static org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState.IN_PROGRESS; import static org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState.NOT_RESOLVED; import static org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState.RESOLVED; -import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_NAME; import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ID; -import static org.eclipse.che.plugin.maven.shared.MessageType.START_STOP; /** * Keeper for the state of Resolving Project process. @@ -51,22 +38,16 @@ import static org.eclipse.che.plugin.maven.shared.MessageType.START_STOP; * @author Roman Nikitenko */ @Singleton -public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHolder, WsAgentStateHandler { - private final DtoFactory factory; - private final WsAgentStateController wsAgentStateController; +public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHolder { private ResolvingProjectState state; private HashSet listeners; @Inject - public ResolvingMavenProjectStateHolder(DtoFactory factory, - EventBus eventBus, - WsAgentStateController wsAgentStateController) { - this.factory = factory; - this.wsAgentStateController = wsAgentStateController; + public ResolvingMavenProjectStateHolder(MavenJsonRpcHandler mavenJsonRpcHandler, EventBus eventBus) { this.state = NOT_RESOLVED; this.listeners = new HashSet<>(); - eventBus.addHandler(WsAgentStateEvent.TYPE, this); + mavenJsonRpcHandler.addStartStopHandler(this::handleStartStop); } @Override @@ -89,36 +70,6 @@ public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHo listeners.remove(listener); } - @Override - public void onWsAgentStarted(WsAgentStateEvent event) { - wsAgentStateController.getMessageBus().then(new Operation() { - @Override - public void apply(MessageBus messageBus) throws OperationException { - try { - messageBus.subscribe(MAVEN_CHANEL_NAME, new MessageHandler() { - @Override - public void onMessage(String message) { - Jso jso = Jso.deserialize(message); - int type = jso.getFieldCastedToInteger("$type"); - MessageType messageType = MessageType.valueOf(type); - - if (messageType == START_STOP) { - handleStartStop(factory.createDtoFromJson(message, StartStopNotification.class)); - } - } - }); - } catch (WebSocketException e) { - Log.error(getClass(), e); - } - } - }); - } - - @Override - public void onWsAgentStopped(WsAgentStateEvent event) { - - } - private void handleStartStop(StartStopNotification startStopNotification) { if (startStopNotification.isStart()) { state = IN_PROGRESS; @@ -138,4 +89,5 @@ public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHo } } }; + } diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandlerTest.java b/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandlerTest.java index 2a6d942677..6c99811831 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandlerTest.java +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/comunnication/MavenMessagesHandlerTest.java @@ -13,107 +13,69 @@ package org.eclipse.che.plugin.maven.client.comunnication; import com.google.common.base.Optional; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.machine.WsAgentStateController; -import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; -import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.console.CommandConsoleFactory; -import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; -import org.eclipse.che.ide.websocket.MessageBus; -import org.eclipse.che.ide.websocket.events.MessageHandler; +import org.eclipse.che.plugin.maven.client.MavenJsonRpcHandler; import org.eclipse.che.plugin.maven.client.comunnication.progressor.background.BackgroundLoaderPresenter; +import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto; import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage; +import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import java.util.Arrays; import java.util.List; -import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_NAME; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class MavenMessagesHandlerTest { - private static final String JSON_MESSAGE = "{\n" + - " \"deletedProjects\": [],\n" + - " \"updatedProjects\": [\n" + - " \"/che/core\",\n" + - " \"/project\",\n" + - " \"/che/core/che-core-db-vendor-postgresql\",\n" + - " \"/che/plugins/plugin-svn\",\n" + - " \"/che/samples/sample-plugin-json\",\n" + - " \"/che/wsmaster/che-core-api-auth\",\n" + - " \"/project/api\",\n" + - " \"/che/wsagent\",\n" + - " \"/che\",\n" + - " \"/che/plugins/plugin-github/che-plugin-github-pullrequest\",\n" + - " \"/che/plugins/plugin-java-debugger\"\n" + - " ],\n" + - " \"$type\": 2\n" + - "}"; @Mock private EventBus eventBus; @Mock - private DtoFactory factory; - @Mock private BackgroundLoaderPresenter dependencyResolver; @Mock private PomEditorReconciler pomEditorReconciler; @Mock - private WsAgentStateController wsAgentStateController; - @Mock private ProcessesPanelPresenter processesPanelPresenter; @Mock private CommandConsoleFactory commandConsoleFactory; @Mock + private MavenJsonRpcHandler mavenJsonRpcHandler; + @Mock private AppContext appContext; @Mock - private WsAgentStateEvent wsAgentStateEvent; + private ProjectsUpdateMessage projectsUpdateMessage; @Mock - private ProjectsUpdateMessage projectsUpdateMessage; + private Promise> optionalContainer; @Mock - private Promise messageBusPromise; - @Mock - private Promise> optionalContainer; - @Mock - private MessageBus messageBus; - @Mock - private Container rootContainer; - @Captor - private ArgumentCaptor wsAgentStateHandlerArgumentCaptor; - @Captor - private ArgumentCaptor> operationArgumentCaptor; - @Captor - private ArgumentCaptor messageHandlerArgumentCaptor; + private Container rootContainer; + + private MavenMessagesHandler mavenMessagesHandler; @Before public void setUp() throws Exception { - when(wsAgentStateController.getMessageBus()).thenReturn(messageBusPromise); when(appContext.getWorkspaceRoot()).thenReturn(rootContainer); - new MavenMessagesHandler(eventBus, - factory, - dependencyResolver, - pomEditorReconciler, - wsAgentStateController, - processesPanelPresenter, - commandConsoleFactory, - appContext); - - + mavenMessagesHandler = new MavenMessagesHandler(eventBus, + mavenJsonRpcHandler, + dependencyResolver, + pomEditorReconciler, + processesPanelPresenter, + commandConsoleFactory, + appContext); } @Test @@ -130,22 +92,34 @@ public class MavenMessagesHandlerTest { "/che/plugins/plugin-github/che-plugin-github-pullrequest", "/che/plugins/plugin-java-debugger"); - when(factory.createDtoFromJson(eq(JSON_MESSAGE), eq(ProjectsUpdateMessage.class))).thenReturn(projectsUpdateMessage); when(projectsUpdateMessage.getUpdatedProjects()).thenReturn(updatedProjects); when(rootContainer.getContainer(anyString())).thenReturn(optionalContainer); - verify(eventBus).addHandler(eq(WsAgentStateEvent.TYPE), wsAgentStateHandlerArgumentCaptor.capture()); - wsAgentStateHandlerArgumentCaptor.getValue().onWsAgentStarted(wsAgentStateEvent); + mavenMessagesHandler.handleUpdate(projectsUpdateMessage); - verify(messageBusPromise).then(operationArgumentCaptor.capture()); - operationArgumentCaptor.getValue().apply(messageBus); - - verify(messageBus).subscribe(eq(MAVEN_CHANEL_NAME), messageHandlerArgumentCaptor.capture()); - messageHandlerArgumentCaptor.getValue().onMessage(JSON_MESSAGE); - - verify(factory).createDtoFromJson(JSON_MESSAGE, ProjectsUpdateMessage.class); verify(pomEditorReconciler).reconcilePoms(updatedProjects); verify(rootContainer).getContainer(eq("/che")); verify(rootContainer).getContainer(eq("/project")); } + + @Test + public void percentNotificationShouldBeHandled() throws Exception { + PercentMessageDto percentMessageDto = Mockito.mock(PercentMessageDto.class); + when(percentMessageDto.getPercent()).thenReturn(0.7); + + mavenMessagesHandler.handlePercentNotification(percentMessageDto); + + verify(dependencyResolver).updateProgressBar(70); + } + + @Test + public void textNotificationShouldBeUpdated() throws Exception { + TextMessageDto textMessageDto = mock(TextMessageDto.class); + String textMessage = "textMessage"; + when(textMessageDto.getText()).thenReturn(textMessage); + + mavenMessagesHandler.handleTextNotification(textMessageDto); + + verify(dependencyResolver).setProgressLabel(textMessage); + } } diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenCommunication.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenCommunication.java index 65e30c4100..5aa93e4a04 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenCommunication.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenCommunication.java @@ -26,6 +26,7 @@ import java.util.Set; * @author Evgen Vidolob */ @ImplementedBy(MavenWebSocketCommunication.class) +@Deprecated public interface MavenCommunication { void sendUpdateMassage(Set updated, List removed); diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenJsonRpcCommunication.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenJsonRpcCommunication.java new file mode 100644 index 0000000000..c779700b84 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenJsonRpcCommunication.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.core; + +import com.google.inject.Singleton; + +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.dto.server.DtoFactory; +import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto; +import org.eclipse.che.plugin.maven.shared.dto.PercentUndefinedMessageDto; +import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage; +import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification; +import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto; +import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent; +import org.eclipse.che.plugin.maven.shared.event.MavenPercentMessageEvent; +import org.eclipse.che.plugin.maven.shared.event.MavenPercentUndefinedEvent; +import org.eclipse.che.plugin.maven.shared.event.MavenStartStopEvent; +import org.eclipse.che.plugin.maven.shared.event.MavenTextMessageEvent; +import org.eclipse.che.plugin.maven.shared.event.MavenUpdateEvent; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import java.util.List; +import java.util.Set; + +import static com.google.common.collect.Sets.newConcurrentHashSet; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_SUBSCRIBE; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_UNSUBSCRIBE; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_START_STOP_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_TEXT_METHOD; +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_UPDATE_METHOD; +import static org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent.TYPE.PERCENT; +import static org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent.TYPE.PERCENT_UNDEFINED; +import static org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent.TYPE.START_STOP; + +/** + * Send maven events using JSON RPC to the clients. + */ +@Singleton +public class MavenJsonRpcCommunication implements EventSubscriber { + private final Set endpointIds = newConcurrentHashSet(); + private EventService eventService; + private RequestTransmitter transmitter; + + @Inject + public MavenJsonRpcCommunication(EventService eventService, RequestTransmitter transmitter) { + this.eventService = eventService; + this.transmitter = transmitter; + } + + @PostConstruct + private void subscribe() { + eventService.subscribe(this); + } + + @PreDestroy + private void unsubscribe() { + eventService.unsubscribe(this); + } + + @Inject + private void configureHandlers(RequestHandlerConfigurator configurator) { + configurator.newConfiguration() + .methodName(MAVEN_CHANEL_SUBSCRIBE) + .noParams() + .noResult() + .withConsumer(endpointIds::add); + + configurator.newConfiguration() + .methodName(MAVEN_CHANEL_UNSUBSCRIBE) + .noParams() + .noResult() + .withConsumer(endpointIds::remove); + } + + @Override + public void onEvent(MavenOutputEvent event) { + switch (event.getType()) { + case TEXT: + sendTextNotification((MavenTextMessageEvent)event); + break; + case UPDATE: + sendUpdateNotification((MavenUpdateEvent)event); + break; + case START_STOP: + sendStartStopNotification((MavenStartStopEvent)event); + break; + case PERCENT: + senPercentNotification((MavenPercentMessageEvent)event); + break; + case PERCENT_UNDEFINED: + sendPercentUndefinedNotification((MavenPercentUndefinedEvent)event); + break; + } + } + + private void senPercentNotification(MavenPercentMessageEvent event) { + PercentMessageDto percentMessageDto = DtoFactory.newDto(PercentMessageDto.class).withPercent(event.getPercent()); + percentMessageDto.setType(PERCENT); + + endpointIds.forEach(it -> transmitter.newRequest() + .endpointId(it) + .methodName(MAVEN_OUTPUT_PERCENT_METHOD) + .paramsAsDto(percentMessageDto) + .sendAndSkipResult()); + } + + private void sendPercentUndefinedNotification(MavenPercentUndefinedEvent event) { + PercentUndefinedMessageDto percentUndefinedMessageDto = DtoFactory.newDto(PercentUndefinedMessageDto.class); + percentUndefinedMessageDto.setPercentUndefined(event.isPercentUndefined()); + percentUndefinedMessageDto.setType(PERCENT_UNDEFINED); + + endpointIds.forEach(it -> transmitter.newRequest() + .endpointId(it) + .methodName(MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD) + .paramsAsDto(percentUndefinedMessageDto) + .sendAndSkipResult()); + } + + private void sendStartStopNotification(MavenStartStopEvent event) { + StartStopNotification startEventDto = DtoFactory.newDto(StartStopNotification.class); + startEventDto.setStart(event.isStart()); + startEventDto.setType(START_STOP); + + endpointIds.forEach(it -> transmitter.newRequest() + .endpointId(it) + .methodName(MAVEN_OUTPUT_START_STOP_METHOD) + .paramsAsDto(startEventDto) + .sendAndSkipResult()); + } + + private void sendUpdateNotification(MavenUpdateEvent event) { + ProjectsUpdateMessage updateEventDto = DtoFactory.newDto(ProjectsUpdateMessage.class); + List updatedPaths = event.getUpdatedProjects(); + List removedPaths = event.getRemovedProjects(); + updateEventDto.setUpdatedProjects(updatedPaths); + updateEventDto.setDeletedProjects(removedPaths); + + updateEventDto.setType(MavenOutputEvent.TYPE.UPDATE); + + endpointIds.forEach(it -> transmitter.newRequest() + .endpointId(it) + .methodName(MAVEN_OUTPUT_UPDATE_METHOD) + .paramsAsDto(updateEventDto) + .sendAndSkipResult()); + } + + private void sendTextNotification(MavenTextMessageEvent event) { + TextMessageDto notification = DtoFactory.newDto(TextMessageDto.class).withText(event.getMessage()); + notification.setType(MavenOutputEvent.TYPE.TEXT); + + endpointIds.forEach(it -> transmitter.newRequest() + .endpointId(it) + .methodName(MAVEN_OUTPUT_TEXT_METHOD) + .paramsAsDto(notification) + .sendAndSkipResult()); + } +} diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenServerNotifier.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenServerNotifier.java index d356ed60bf..29c32efc7c 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenServerNotifier.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenServerNotifier.java @@ -13,11 +13,13 @@ package org.eclipse.che.plugin.maven.server.core; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.eclipse.che.dto.server.DtoFactory; -import org.eclipse.che.plugin.maven.shared.MessageType; -import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage; -import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification; +import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.maven.server.MavenServerProgressNotifier; +import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent; +import org.eclipse.che.plugin.maven.shared.impl.MavenPercentEventImpl; +import org.eclipse.che.plugin.maven.shared.impl.MavenPercentUndefinedEventImpl; +import org.eclipse.che.plugin.maven.shared.impl.MavenStartStopEventImpl; +import org.eclipse.che.plugin.maven.shared.impl.MavenTextMessageEventImpl; /** * Default implementation of {@link MavenServerProgressNotifier} @@ -27,32 +29,26 @@ import org.eclipse.che.maven.server.MavenServerProgressNotifier; @Singleton public class MavenServerNotifier implements MavenProgressNotifier { - private final MavenCommunication communication; + private EventService eventService; @Inject - public MavenServerNotifier(MavenCommunication communication) { - this.communication = communication; + public MavenServerNotifier(EventService eventService) { + this.eventService = eventService; } @Override public void setText(String text) { - NotificationMessage dto = DtoFactory.newDto(NotificationMessage.class); - dto.setText(text); - communication.sendNotification(dto); + eventService.publish(new MavenTextMessageEventImpl(text, MavenOutputEvent.TYPE.TEXT)); } @Override public void setPercent(double percent) { - NotificationMessage dto = DtoFactory.newDto(NotificationMessage.class); - dto.setPercent(percent); - communication.sendNotification(dto); + eventService.publish(new MavenPercentEventImpl(percent, MavenOutputEvent.TYPE.PERCENT)); } @Override public void setPercentUndefined(boolean undefined) { - NotificationMessage dto = DtoFactory.newDto(NotificationMessage.class); - dto.setPercentUndefined(undefined); - communication.sendNotification(dto); + eventService.publish(new MavenPercentUndefinedEventImpl(undefined, MavenOutputEvent.TYPE.PERCENT_UNDEFINED)); } @Override @@ -66,9 +62,7 @@ public class MavenServerNotifier implements MavenProgressNotifier { } private void sendStartStop(boolean isStart) { - StartStopNotification dto = DtoFactory.newDto(StartStopNotification.class); - dto.setStart(isStart); - communication.send(DtoFactory.getInstance().toJsonElement(dto).getAsJsonObject(), MessageType.START_STOP); + eventService.publish(new MavenStartStopEventImpl(isStart, MavenOutputEvent.TYPE.START_STOP)); } @Override diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWebSocketCommunication.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWebSocketCommunication.java index d218ddaf79..8ed2faaa8a 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWebSocketCommunication.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWebSocketCommunication.java @@ -34,6 +34,7 @@ import java.util.stream.Collectors; * @author Evgen Vidolob */ @Singleton +@Deprecated public class MavenWebSocketCommunication implements MavenCommunication { private static final Logger LOG = LoggerFactory.getLogger(MavenWebSocketCommunication.class); diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWorkspace.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWorkspace.java index a8a181faa1..40bb5851ea 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWorkspace.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenWorkspace.java @@ -30,7 +30,10 @@ import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager; import org.eclipse.che.plugin.maven.server.core.project.MavenProject; import org.eclipse.che.plugin.maven.server.core.project.MavenProjectModifications; import org.eclipse.che.plugin.maven.shared.MavenAttributes; +import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent; +import org.eclipse.che.plugin.maven.shared.impl.MavenUpdateEventImpl; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IJavaModelStatusConstants; @@ -50,6 +53,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; +import static java.util.stream.Collectors.toList; import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ID; /** @@ -62,7 +66,6 @@ public class MavenWorkspace { private final MavenProjectManager manager; private final Provider projectRegistryProvider; - private final MavenCommunication communication; private final ClasspathManager classpathManager; private MavenTaskExecutor resolveExecutor; @@ -76,12 +79,10 @@ public class MavenWorkspace { MavenProgressNotifier notifier, MavenExecutorService executorService, Provider projectRegistryProvider, - MavenCommunication communication, ClasspathManager classpathManager, EventService eventService, EclipseWorkspaceProvider workspaceProvider) { this.projectRegistryProvider = projectRegistryProvider; - this.communication = communication; this.classpathManager = classpathManager; this.manager = manager; resolveExecutor = new MavenTaskExecutor(executorService, notifier); @@ -110,9 +111,20 @@ public class MavenWorkspace { List needResolve = manager.findDependentProjects(allChangedProjects); needResolve.addAll(updated.keySet()); + List updatedPaths = updated.keySet().stream() + .map(MavenProject::getProject) + .map(IResource::getFullPath) + .map(IPath::toOSString) + .collect(toList()); + List removedPaths = removed.stream() + .map(MavenProject::getProject) + .map(IResource::getFullPath) + .map(IPath::toOSString) + .collect(toList()); + addResolveProjects(needResolve); - communication.sendUpdateMassage(updated.keySet(), removed); + eventService.publish(new MavenUpdateEventImpl(updatedPaths, removedPaths, MavenOutputEvent.TYPE.UPDATE)); } }); } diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/inject/MavenModule.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/inject/MavenModule.java index 94049d07eb..4dcdeb5141 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/inject/MavenModule.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/inject/MavenModule.java @@ -19,7 +19,9 @@ import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ValueProviderFactory; import org.eclipse.che.inject.DynaModule; import org.eclipse.che.maven.server.MavenTerminal; +import org.eclipse.che.plugin.maven.generator.archetype.MavenArchetypeJsonRpcMessenger; import org.eclipse.che.plugin.maven.server.PomModificationDetector; +import org.eclipse.che.plugin.maven.server.core.MavenJsonRpcCommunication; import org.eclipse.che.plugin.maven.server.core.MavenProgressNotifier; import org.eclipse.che.plugin.maven.server.core.MavenServerNotifier; import org.eclipse.che.plugin.maven.server.core.MavenTerminalImpl; @@ -60,6 +62,8 @@ public class MavenModule extends AbstractModule { bind(MavenProgressNotifier.class).to(MavenServerNotifier.class).in(Singleton.class); bind(MavenServerService.class); + bind(MavenJsonRpcCommunication.class); + bind(MavenArchetypeJsonRpcMessenger.class); bind(PomChangeListener.class).asEagerSingleton(); bind(PomModificationDetector.class).asEagerSingleton(); diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/WorkspaceTest.java b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/WorkspaceTest.java index 6e2c99918d..dbfe7d0488 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/WorkspaceTest.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/WorkspaceTest.java @@ -10,8 +10,8 @@ *******************************************************************************/ package org.eclipse.che.plugin.maven.server; -import com.google.gson.JsonObject; import com.google.inject.Provider; + import org.eclipse.che.api.project.server.FolderEntry; import org.eclipse.che.api.project.server.ProjectRegistry; import org.eclipse.che.api.project.server.RegisteredProject; @@ -22,15 +22,12 @@ import org.eclipse.che.maven.data.MavenArtifact; import org.eclipse.che.maven.data.MavenKey; import org.eclipse.che.maven.server.MavenTerminal; import org.eclipse.che.plugin.maven.server.core.EclipseWorkspaceProvider; -import org.eclipse.che.plugin.maven.server.core.MavenCommunication; import org.eclipse.che.plugin.maven.server.core.MavenExecutorService; import org.eclipse.che.plugin.maven.server.core.MavenProjectManager; import org.eclipse.che.plugin.maven.server.core.MavenWorkspace; import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager; import org.eclipse.che.plugin.maven.server.core.project.MavenProject; import org.eclipse.che.plugin.maven.server.rmi.MavenServerManagerTest; -import org.eclipse.che.plugin.maven.shared.MessageType; -import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; @@ -51,7 +48,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ListIterator; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -92,22 +88,7 @@ public class WorkspaceTest extends BaseTest { mavenNotifier, new MavenExecutorService(), projectRegistryProvider, - new MavenCommunication() { - @Override - public void sendUpdateMassage(Set updated, List removed) { - - } - - @Override - public void sendNotification(NotificationMessage message) { - System.out.println(message.toString()); - } - - @Override - public void send(JsonObject object, MessageType type) { - - } - }, new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal, + new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal, mavenNotifier), eventService, new EclipseWorkspaceProvider()); } diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/classpath/ClasspathManagerTest.java b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/classpath/ClasspathManagerTest.java index b3cebd2e54..c8a9bf3cbc 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/classpath/ClasspathManagerTest.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/classpath/ClasspathManagerTest.java @@ -10,24 +10,19 @@ *******************************************************************************/ package org.eclipse.che.plugin.maven.server.classpath; -import com.google.gson.JsonObject; import com.google.inject.Provider; import org.eclipse.che.api.project.server.ProjectRegistry; import org.eclipse.che.commons.lang.IoUtil; +import org.eclipse.che.maven.server.MavenTerminal; import org.eclipse.che.plugin.maven.server.BaseTest; import org.eclipse.che.plugin.maven.server.MavenWrapperManager; import org.eclipse.che.plugin.maven.server.core.EclipseWorkspaceProvider; -import org.eclipse.che.plugin.maven.server.core.MavenCommunication; import org.eclipse.che.plugin.maven.server.core.MavenExecutorService; import org.eclipse.che.plugin.maven.server.core.MavenProjectManager; import org.eclipse.che.plugin.maven.server.core.MavenWorkspace; import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager; -import org.eclipse.che.plugin.maven.server.core.project.MavenProject; import org.eclipse.che.plugin.maven.server.rmi.MavenServerManagerTest; -import org.eclipse.che.plugin.maven.shared.MessageType; -import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage; -import org.eclipse.che.maven.server.MavenTerminal; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.jdt.core.IJavaProject; @@ -40,8 +35,6 @@ import org.testng.annotations.Test; import java.io.File; import java.util.Collections; -import java.util.List; -import java.util.Set; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -81,22 +74,7 @@ public class ClasspathManagerTest extends BaseTest { new MavenProjectManager(wrapperManager, mavenServerManager, terminal, mavenNotifier, new EclipseWorkspaceProvider()); classpathManager = new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal, mavenNotifier); mavenWorkspace = new MavenWorkspace(mavenProjectManager, mavenNotifier, new MavenExecutorService(), projectRegistryProvider, - new MavenCommunication() { - @Override - public void sendUpdateMassage(Set updated, List removed) { - - } - - @Override - public void sendNotification(NotificationMessage message) { - System.out.println(message.toString()); - } - - @Override - public void send(JsonObject object, MessageType type) { - - } - }, classpathManager, eventService, new EclipseWorkspaceProvider()); + classpathManager, eventService, new EclipseWorkspaceProvider()); } @AfterMethod diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/core/reconcile/PomReconcilerTest.java b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/core/reconcile/PomReconcilerTest.java index 8558562272..b21fd76355 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/core/reconcile/PomReconcilerTest.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/core/reconcile/PomReconcilerTest.java @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.che.plugin.maven.server.core.reconcile; -import com.google.gson.JsonObject; import com.google.inject.Provider; import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter; @@ -24,15 +23,11 @@ import org.eclipse.che.maven.server.MavenTerminal; import org.eclipse.che.plugin.maven.server.BaseTest; import org.eclipse.che.plugin.maven.server.MavenWrapperManager; import org.eclipse.che.plugin.maven.server.core.EclipseWorkspaceProvider; -import org.eclipse.che.plugin.maven.server.core.MavenCommunication; import org.eclipse.che.plugin.maven.server.core.MavenExecutorService; import org.eclipse.che.plugin.maven.server.core.MavenProjectManager; import org.eclipse.che.plugin.maven.server.core.MavenWorkspace; import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager; -import org.eclipse.che.plugin.maven.server.core.project.MavenProject; import org.eclipse.che.plugin.maven.server.rmi.MavenServerManagerTest; -import org.eclipse.che.plugin.maven.shared.MessageType; -import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.testng.annotations.BeforeMethod; @@ -42,7 +37,6 @@ import java.io.File; import java.rmi.RemoteException; import java.util.Collections; import java.util.List; -import java.util.Set; import static java.lang.String.format; import static org.fest.assertions.Assertions.assertThat; @@ -89,23 +83,13 @@ public class PomReconcilerTest extends BaseTest { ClasspathManager classpathManager = new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal, mavenNotifier); - mavenWorkspace = new MavenWorkspace(mavenProjectManager, mavenNotifier, new MavenExecutorService(), projectRegistryProvider, - new MavenCommunication() { - @Override - public void sendUpdateMassage(Set updated, List removed) { - - } - - @Override - public void sendNotification(NotificationMessage message) { - System.out.println(message.toString()); - } - - @Override - public void send(JsonObject object, MessageType type) { - - } - }, classpathManager, eventService, new EclipseWorkspaceProvider()); + mavenWorkspace = new MavenWorkspace(mavenProjectManager, + mavenNotifier, + new MavenExecutorService(), + projectRegistryProvider, + classpathManager, + eventService, + new EclipseWorkspaceProvider()); EditorWorkingCopyManager editorWorkingCopyManager = new EditorWorkingCopyManager(projectManagerProvider, eventService, requestTransmitter); pomReconciler = diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/MavenAttributes.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/MavenAttributes.java index a0cfe63bb4..86fb09bbf7 100644 --- a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/MavenAttributes.java +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/MavenAttributes.java @@ -36,7 +36,7 @@ public interface MavenAttributes { String PARENT_VERSION = "maven.parent.version"; String TEST_SOURCE_FOLDER = "maven.test.source.folder"; - String RESOURCE_FOLDER = "maven.resource.folder"; + String RESOURCE_FOLDER = "maven.resource.folder"; String DEFAULT_SOURCE_FOLDER = "src/main/java"; String DEFAULT_RESOURCES_FOLDER = "src/main/resources"; @@ -50,6 +50,17 @@ public interface MavenAttributes { /** Name of WebSocket chanel */ String MAVEN_CHANEL_NAME = "maven:workspace"; - /** Name of WebSocket chanel for Maven Archetype output */ - String MAVEN_ARCHETYPE_CHANEL_NAME = "maven:archetype:output"; + + + String MAVEN_CHANEL_UNSUBSCRIBE = "mavenOutput/subscribe"; + String MAVEN_CHANEL_SUBSCRIBE = "mavenOutput/unsubscribe"; + String MAVEN_OUTPUT_TEXT_METHOD = "mavenOutput/text"; + String MAVEN_OUTPUT_UPDATE_METHOD = "mavenOutput/update"; + String MAVEN_OUTPUT_START_STOP_METHOD = "mavenOutput/start_stop"; + String MAVEN_OUTPUT_PERCENT_METHOD = "mavenOutput/percent"; + String MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD = "mavenOutput/percentUndefined"; + + String MAVEN_ARCHETYPE_CHANEL_UNSUBSCRIBE = "mavenArchetype/unsubscribe"; + String MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE = "mavenArchetype/subscribe"; + String MAVEN_ARCHETYPE_CHANEL_OUTPUT = "mavenArchetype/output"; } diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ArchetypeOutput.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ArchetypeOutput.java index 9925c1bf74..bf1d103173 100644 --- a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ArchetypeOutput.java +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ArchetypeOutput.java @@ -41,4 +41,7 @@ public interface ArchetypeOutput { */ State getState(); + void setOutput(String output); + + void setState(State state); } diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/MavenOutputEventDto.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/MavenOutputEventDto.java new file mode 100644 index 0000000000..7ea20ea94f --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/MavenOutputEventDto.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.dto; + +import org.eclipse.che.dto.shared.DTO; +import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent; + +/** + * DTO object which describes base maven output event. + */ +@DTO +public interface MavenOutputEventDto extends MavenOutputEvent { + + TYPE getType(); + + /** Returns a type of the output event. */ + void setType(TYPE type); + + MavenOutputEventDto withType(TYPE type); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/NotificationMessage.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/NotificationMessage.java index 47fe816cda..d262a9d38e 100644 --- a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/NotificationMessage.java +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/NotificationMessage.java @@ -18,6 +18,7 @@ import org.eclipse.che.dto.shared.DTO; * @author Evgen Vidolob */ @DTO +@Deprecated public interface NotificationMessage { String getText(); diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentMessageDto.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentMessageDto.java new file mode 100644 index 0000000000..aa9faed306 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentMessageDto.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.dto; + +import org.eclipse.che.dto.shared.DTO; + +/** + * Message for translating value of percent of resolving from MavenServerNotifier. + */ +@DTO +public interface PercentMessageDto extends MavenOutputEventDto { + + double getPercent(); + + void setPercent(double percent); + + PercentMessageDto withPercent(double percent); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentUndefinedMessageDto.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentUndefinedMessageDto.java new file mode 100644 index 0000000000..24502bdd86 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/PercentUndefinedMessageDto.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.dto; + +import org.eclipse.che.dto.shared.DTO; + +/** + * Message for translating value of percent undefined from MavenServerNotifier. + */ +@DTO +public interface PercentUndefinedMessageDto extends MavenOutputEventDto { + + boolean isPercentUndefined(); + + void setPercentUndefined(boolean percentUndefined); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ProjectsUpdateMessage.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ProjectsUpdateMessage.java index a5cf58a671..94948f61f5 100644 --- a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ProjectsUpdateMessage.java +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/ProjectsUpdateMessage.java @@ -19,7 +19,7 @@ import java.util.List; * @author Evgen Vidolob */ @DTO -public interface ProjectsUpdateMessage { +public interface ProjectsUpdateMessage extends MavenOutputEventDto { List getUpdatedProjects(); diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/StartStopNotification.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/StartStopNotification.java index ae23a31641..30b3794905 100644 --- a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/StartStopNotification.java +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/StartStopNotification.java @@ -18,7 +18,7 @@ import org.eclipse.che.dto.shared.DTO; * @author Evgen Vidolob */ @DTO -public interface StartStopNotification { +public interface StartStopNotification extends MavenOutputEventDto{ boolean isStart(); diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/TextMessageDto.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/TextMessageDto.java new file mode 100644 index 0000000000..43bb78c2f3 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/dto/TextMessageDto.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.dto; + +import org.eclipse.che.dto.shared.DTO; + +/** + * Message for translating text message from MavenServerNotifier + */ +@DTO +public interface TextMessageDto extends MavenOutputEventDto { + + String getText(); + + /** Returns text message of the output event. */ + void setText(String text); + + TextMessageDto withText(String text); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenOutputEvent.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenOutputEvent.java new file mode 100644 index 0000000000..9572e9cfd6 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenOutputEvent.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.event; + +/** + * Base maven output event. + */ +public interface MavenOutputEvent { + /**Returns typ of the event. */ + TYPE getType(); + + enum TYPE { + START_STOP, + PERCENT, + PERCENT_UNDEFINED, + UPDATE, + TEXT + } +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentMessageEvent.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentMessageEvent.java new file mode 100644 index 0000000000..b59dbb005b --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentMessageEvent.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.event; + +/** + * Event that describes Maven notification output. + */ +public interface MavenPercentMessageEvent extends MavenOutputEvent { + /** Returns percent of the project resolving. */ + double getPercent(); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentUndefinedEvent.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentUndefinedEvent.java new file mode 100644 index 0000000000..8eaf5ee684 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenPercentUndefinedEvent.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.event; + +/** + * Event that describes Maven start notification. + */ +public interface MavenPercentUndefinedEvent extends MavenOutputEvent { + boolean isPercentUndefined(); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenStartStopEvent.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenStartStopEvent.java new file mode 100644 index 0000000000..3081d2d4de --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenStartStopEvent.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.event; + +/** + * Event that describes Maven start notification. + */ +public interface MavenStartStopEvent extends MavenOutputEvent { + /** Returns {@code true} if the process of resolving is started otherwise returns {@code false}. */ + boolean isStart(); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenTextMessageEvent.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenTextMessageEvent.java new file mode 100644 index 0000000000..a5cea284ab --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenTextMessageEvent.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.event; + +/** + * Event that describes Maven notification output. + */ +public interface MavenTextMessageEvent extends MavenOutputEvent { + /** Returns text message. */ + String getMessage(); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenUpdateEvent.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenUpdateEvent.java new file mode 100644 index 0000000000..dc3edc0cdc --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/event/MavenUpdateEvent.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.event; + +import java.util.List; + +/** + * Event that describes Maven notification output. + */ +public interface MavenUpdateEvent extends MavenOutputEvent { + /** Returns list of projects which were modified. */ + List getUpdatedProjects(); + + /** Returns list of projects which were removed. */ + List getRemovedProjects(); +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenOutputEventImpl.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenOutputEventImpl.java new file mode 100644 index 0000000000..028c198ecd --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenOutputEventImpl.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.impl; + + +import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent; + +/** + * Implementation of base maven output event. + */ +public class MavenOutputEventImpl implements MavenOutputEvent { + private final TYPE type; + + public MavenOutputEventImpl(TYPE type) { + this.type = type; + } + + @Override + public TYPE getType() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MavenOutputEventImpl)) return false; + + MavenOutputEventImpl that = (MavenOutputEventImpl)o; + + return type == that.type; + } + + @Override + public int hashCode() { + return type != null ? type.hashCode() : 0; + } +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentEventImpl.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentEventImpl.java new file mode 100644 index 0000000000..087021585d --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentEventImpl.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.impl; + + +import org.eclipse.che.plugin.maven.shared.event.MavenPercentMessageEvent; + +/** + * Implementation of the event which describes percent of the project resolving. + */ +public class MavenPercentEventImpl extends MavenOutputEventImpl implements MavenPercentMessageEvent { + private final double percent; + + public MavenPercentEventImpl(double percent, TYPE type) { + super(type); + this.percent = percent; + } + + @Override + public double getPercent() { + return percent; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MavenPercentEventImpl)) return false; + if (!super.equals(o)) return false; + + MavenPercentEventImpl that = (MavenPercentEventImpl)o; + + return percent == that.percent; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Double.hashCode(percent); + return result; + } + +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentUndefinedEventImpl.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentUndefinedEventImpl.java new file mode 100644 index 0000000000..6aa4ef44bc --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenPercentUndefinedEventImpl.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.impl; + + +import org.eclipse.che.plugin.maven.shared.event.MavenPercentUndefinedEvent; + +/** + * Implementation of the {@link MavenPercentUndefinedEvent}. + */ +public class MavenPercentUndefinedEventImpl extends MavenOutputEventImpl implements MavenPercentUndefinedEvent { + private final boolean isPercentUndefined; + + public MavenPercentUndefinedEventImpl(boolean isPercentUndefined, TYPE type) { + super(type); + this.isPercentUndefined = isPercentUndefined; + } + + @Override + public boolean isPercentUndefined() { + return isPercentUndefined; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MavenPercentUndefinedEventImpl)) return false; + if (!super.equals(o)) return false; + + MavenPercentUndefinedEventImpl that = (MavenPercentUndefinedEventImpl)o; + + return isPercentUndefined == that.isPercentUndefined; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (isPercentUndefined ? 1 : 0); + return result; + } + +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenStartStopEventImpl.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenStartStopEventImpl.java new file mode 100644 index 0000000000..a1017c436c --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenStartStopEventImpl.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.impl; + + +import org.eclipse.che.plugin.maven.shared.event.MavenStartStopEvent; + +/** + * Implementation of the {@link MavenStartStopEvent}. + */ +public class MavenStartStopEventImpl extends MavenOutputEventImpl implements MavenStartStopEvent { + private final boolean isStart; + + public MavenStartStopEventImpl(boolean isStart, TYPE type) { + super(type); + this.isStart = isStart; + } + + @Override + public boolean isStart() { + return isStart; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MavenStartStopEventImpl)) return false; + if (!super.equals(o)) return false; + + MavenStartStopEventImpl that = (MavenStartStopEventImpl)o; + + return isStart == that.isStart; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (isStart ? 1 : 0); + return result; + } + +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenTextMessageEventImpl.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenTextMessageEventImpl.java new file mode 100644 index 0000000000..08dc09210f --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenTextMessageEventImpl.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.impl; + + +import org.eclipse.che.plugin.maven.shared.event.MavenTextMessageEvent; + +/** + * Implementation of the {@link MavenTextMessageEvent}. + */ +public class MavenTextMessageEventImpl extends MavenOutputEventImpl implements MavenTextMessageEvent { + private final String message; + + public MavenTextMessageEventImpl(String message, TYPE type) { + super(type); + this.message = message; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MavenTextMessageEventImpl)) return false; + if (!super.equals(o)) return false; + + MavenTextMessageEventImpl that = (MavenTextMessageEventImpl)o; + + return message.equals(that.message); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (message != null ? message.hashCode() : 0); + return result; + } +} diff --git a/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenUpdateEventImpl.java b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenUpdateEventImpl.java new file mode 100644 index 0000000000..3b04b93b89 --- /dev/null +++ b/plugins/plugin-maven/che-plugin-maven-shared/src/main/java/org/eclipse/che/plugin/maven/shared/impl/MavenUpdateEventImpl.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2012-2017 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.shared.impl; + + +import org.eclipse.che.plugin.maven.shared.event.MavenUpdateEvent; + +import java.util.List; + +/** + * Implementation of the {@link MavenUpdateEvent}. + */ +public class MavenUpdateEventImpl extends MavenOutputEventImpl implements MavenUpdateEvent { + private final List updated; + private final List removed; + + public MavenUpdateEventImpl(List updated, List removed, TYPE type) { + super(type); + this.removed = removed; + this.updated = updated; + } + + @Override + public List getUpdatedProjects() { + return updated; + } + + @Override + public List getRemovedProjects() { + return removed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MavenUpdateEventImpl)) return false; + if (!super.equals(o)) return false; + + MavenUpdateEventImpl that = (MavenUpdateEventImpl)o; + return removed.equals(that.removed) && updated.equals(that.updated); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (removed != null ? removed.hashCode() : 0) + (updated != null ? updated.hashCode() : 0); + return result; + } + +} diff --git a/plugins/pom.xml b/plugins/pom.xml index 863944100b..7011196616 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -57,7 +57,7 @@ plugin-zend-debugger plugin-testing plugin-testing-java - plugin-testing-php + plugin-testing-php plugin-pullrequest-parent plugin-traefik