From 88f788b28d6caf3ad8aedc8acf85cd3637287984 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Fri, 18 Nov 2016 15:16:32 +0200 Subject: [PATCH 01/74] CHE-2870 Fix get git config property value (#3077) Fix get() method of JGitConfigImpl class. Previous behavior: If the same property is present in the global git config file, and in the git repository config file, execution of gitConnection.getConfig().get() returnes property from global git config file. --- .../org/eclipse/che/git/impl/ConfigTest.java | 2 +- .../che/git/impl/jgit/JGitConfigImpl.java | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/wsagent/che-core-api-git/src/test/java/org/eclipse/che/git/impl/ConfigTest.java b/wsagent/che-core-api-git/src/test/java/org/eclipse/che/git/impl/ConfigTest.java index 2912ad6bf1e..a72bec90502 100644 --- a/wsagent/che-core-api-git/src/test/java/org/eclipse/che/git/impl/ConfigTest.java +++ b/wsagent/che-core-api-git/src/test/java/org/eclipse/che/git/impl/ConfigTest.java @@ -74,7 +74,7 @@ public void testShouldWarnOnInvalidPropertySetting(GitConnectionFactory connecti } @Test(expectedExceptions = GitException.class, expectedExceptionsMessageRegExp = "Can not find property '" + PROPERTY_NAME + - "' in repository configuration", + "' in Git configuration settings.", dataProvider = "GitConnectionFactory", dataProviderClass = org.eclipse.che.git.impl.GitConnectionFactoryProvider.class) public void testShouldReturnEmptyValueForParameter(GitConnectionFactory connectionFactory) throws Exception { GitConnection connection = connectToInitializedGitRepository(connectionFactory, repository); diff --git a/wsagent/che-core-git-impl-jgit/src/main/java/org/eclipse/che/git/impl/jgit/JGitConfigImpl.java b/wsagent/che-core-git-impl-jgit/src/main/java/org/eclipse/che/git/impl/jgit/JGitConfigImpl.java index 7d1ce1748ee..b09c0bb3f15 100644 --- a/wsagent/che-core-git-impl-jgit/src/main/java/org/eclipse/che/git/impl/jgit/JGitConfigImpl.java +++ b/wsagent/che-core-git-impl-jgit/src/main/java/org/eclipse/che/git/impl/jgit/JGitConfigImpl.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Set; +import static java.lang.String.format; import static java.lang.System.lineSeparator; /** @@ -31,6 +32,8 @@ */ class JGitConfigImpl extends Config { + private final String CONFIGURATION_NOT_FOUND_MESSAGE = "Can not find property '%s' in Git configuration settings."; + private final Repository repository; JGitConfigImpl(Repository repository) throws GitException { @@ -40,22 +43,22 @@ class JGitConfigImpl extends Config { @Override public String get(String name) throws GitException { - return getInternalValues(name)[0]; + ConfigKey key = parseName(name); + String value = repository.getConfig().getString(key.section, key.subsection, key.name); + if (value == null) { + throw new GitException(format(CONFIGURATION_NOT_FOUND_MESSAGE, name)); + } + return value; } @Override public List getAll(String name) throws GitException { - return Arrays.asList(getInternalValues(name)); - } - - private String[] getInternalValues(String name) throws GitException { ConfigKey key = parseName(name); String[] values = repository.getConfig().getStringList(key.section, key.subsection, key.name); - // Make sure the property exists if (values == null || values.length == 0) { - throw new GitException("Can not find property '" + name + "' in repository configuration"); + throw new GitException(format(CONFIGURATION_NOT_FOUND_MESSAGE, name)); } - return values; + return Arrays.asList(values); } @Override From 0e687558505b0be0e32acf5e2b24b8d7eb35776a Mon Sep 17 00:00:00 2001 From: Oleksii Orel Date: Thu, 17 Nov 2016 16:21:18 +0200 Subject: [PATCH 02/74] debugger improvement Signed-off-by: Oleksii Orel --- .../debugger/ide/debug/AbstractDebugger.java | 23 ++++++++---- .../nodejsdbg/server/NodeJsDebugger.java | 37 +------------------ 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java index 932ac683306..0db4bb49257 100644 --- a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java @@ -159,8 +159,9 @@ public void apply(DebugSessionDto arg) throws OperationException { }).catchError(new Operation() { @Override public void apply(PromiseError arg) throws OperationException { - invalidateDebugSession(); - preserveDebuggerState(); + if (isConnected()) { + invalidateDebugSession(); + } } }); } @@ -508,7 +509,8 @@ public void stepInto() { for (DebuggerObserver observer : observers) { observer.onPreStepInto(); } - currentLocation = null; + removeCurrentLocation(); + preserveDebuggerState(); StepIntoActionDto action = dtoFactory.createDto(StepIntoActionDto.class); action.setType(Action.TYPE.STEP_INTO); @@ -529,7 +531,8 @@ public void stepOver() { for (DebuggerObserver observer : observers) { observer.onPreStepOver(); } - currentLocation = null; + removeCurrentLocation(); + preserveDebuggerState(); StepOverActionDto action = dtoFactory.createDto(StepOverActionDto.class); action.setType(Action.TYPE.STEP_OVER); @@ -550,7 +553,8 @@ public void stepOut() { for (DebuggerObserver observer : observers) { observer.onPreStepOut(); } - currentLocation = null; + removeCurrentLocation(); + preserveDebuggerState(); StepOutActionDto action = dtoFactory.createDto(StepOutActionDto.class); action.setType(Action.TYPE.STEP_OUT); @@ -571,7 +575,8 @@ public void resume() { for (DebuggerObserver observer : observers) { observer.onPreResume(); } - currentLocation = null; + removeCurrentLocation(); + preserveDebuggerState(); ResumeActionDto action = dtoFactory.createDto(ResumeActionDto.class); action.setType(Action.TYPE.RESUME); @@ -646,7 +651,11 @@ protected void setDebugSession(DebugSessionDto debugSessionDto) { private void invalidateDebugSession() { this.debugSessionDto = null; - this.currentLocation = null; + this.removeCurrentLocation(); + } + + private void removeCurrentLocation() { + currentLocation = null; } /** diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugger.java b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugger.java index 960e8baeff9..07c2a461ef4 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugger.java +++ b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugger.java @@ -22,7 +22,6 @@ import org.eclipse.che.api.debug.shared.model.action.StepIntoAction; import org.eclipse.che.api.debug.shared.model.action.StepOutAction; import org.eclipse.che.api.debug.shared.model.action.StepOverAction; -import org.eclipse.che.api.debug.shared.model.impl.BreakpointImpl; import org.eclipse.che.api.debug.shared.model.impl.DebuggerInfoImpl; import org.eclipse.che.api.debug.shared.model.impl.SimpleValueImpl; import org.eclipse.che.api.debug.shared.model.impl.StackFrameDumpImpl; @@ -40,11 +39,7 @@ import java.net.URI; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.regex.Pattern; /** * Server side NodeJs debugger. @@ -63,7 +58,6 @@ public class NodeJsDebugger implements Debugger { private final NodeJsDebugProcess nodeJsDebugProcess; private final DebuggerCallback debuggerCallback; private final NodeJsDebugCommandsLibrary library; - private final Set pendingBreakpoints; NodeJsDebugger(@Nullable Integer pid, @Nullable URI uri, @@ -78,7 +72,6 @@ public class NodeJsDebugger implements Debugger { this.name = library.getName(); this.version = library.getVersion(); this.debuggerCallback = debuggerCallback; - this.pendingBreakpoints = new CopyOnWriteArraySet<>(); } public static NodeJsDebugger newInstance(@Nullable Integer pid, @@ -113,9 +106,8 @@ public void disconnect() { public void addBreakpoint(Breakpoint breakpoint) throws DebuggerException { try { Location location = breakpoint.getLocation(); - pendingBreakpoints.add(location); library.setBreakpoint(location.getTarget(), location.getLineNumber()); - checkActivatedBreakpoints(); + debuggerCallback.onEvent(new BreakpointActivatedEventImpl(breakpoint)); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); throw e; @@ -127,7 +119,6 @@ public void addBreakpoint(Breakpoint breakpoint) throws DebuggerException { @Override public void deleteBreakpoint(Location location) throws DebuggerException { try { - pendingBreakpoints.remove(location); library.clearBreakpoint(location.getTarget(), location.getLineNumber()); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); @@ -147,7 +138,6 @@ public void deleteAllBreakpoints() throws DebuggerException { LOG.error("Can't delete breakpoint: {}", breakpoint.getLocation(), e); } } - pendingBreakpoints.clear(); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); throw e; @@ -174,11 +164,10 @@ public void start(StartAction action) throws DebuggerException { for (Breakpoint breakpoint : action.getBreakpoints()) { Location location = breakpoint.getLocation(); library.setBreakpoint(location.getTarget(), location.getLineNumber()); - pendingBreakpoints.add(location); + debuggerCallback.onEvent(new BreakpointActivatedEventImpl(breakpoint)); } debuggerCallback.onEvent(new SuspendEventImpl(library.backtrace())); - checkActivatedBreakpoints(); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); throw e; @@ -191,7 +180,6 @@ public void start(StartAction action) throws DebuggerException { public void stepOver(StepOverAction action) throws DebuggerException { try { debuggerCallback.onEvent(new SuspendEventImpl(library.next())); - checkActivatedBreakpoints(); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); throw e; @@ -204,7 +192,6 @@ public void stepOver(StepOverAction action) throws DebuggerException { public void stepInto(StepIntoAction action) throws DebuggerException { try { debuggerCallback.onEvent(new SuspendEventImpl(library.stepIn())); - checkActivatedBreakpoints(); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); throw e; @@ -217,7 +204,6 @@ public void stepInto(StepIntoAction action) throws DebuggerException { public void stepOut(StepOutAction action) throws DebuggerException { try { debuggerCallback.onEvent(new SuspendEventImpl(library.stepOut())); - checkActivatedBreakpoints(); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); throw e; @@ -230,7 +216,6 @@ public void stepOut(StepOutAction action) throws DebuggerException { public void resume(ResumeAction action) throws DebuggerException { try { debuggerCallback.onEvent(new SuspendEventImpl(library.cont())); - checkActivatedBreakpoints(); } catch (NodeJsDebuggerTerminatedException e) { disconnect(); throw e; @@ -288,22 +273,4 @@ public String evaluate(String expression) throws DebuggerException { public StackFrameDump dumpStackFrame() throws DebuggerException { return new StackFrameDumpImpl(Collections.emptyList(), Collections.emptyList()); } - - private void checkActivatedBreakpoints() throws DebuggerException { - Set brk2Remove = new HashSet<>(); - for (Breakpoint breakpoint : library.getBreakpoints()) { - for (Location pending : pendingBreakpoints) { - Location added = breakpoint.getLocation(); - if (added.getLineNumber() == pending.getLineNumber() && - Pattern.compile(added.getTarget()).matcher(pending.getTarget()).matches()) { - - BreakpointImpl brkToSend = new BreakpointImpl(pending, breakpoint.isEnabled(), breakpoint.getCondition()); - debuggerCallback.onEvent(new BreakpointActivatedEventImpl(brkToSend)); - brk2Remove.add(pending); - } - } - } - - pendingBreakpoints.removeAll(brk2Remove); - } } From a6bbd6f240db2e1ef05f4fe0e916ff797e8c57c9 Mon Sep 17 00:00:00 2001 From: Oleksii Orel Date: Thu, 17 Nov 2016 16:52:15 +0200 Subject: [PATCH 03/74] code cleanup Signed-off-by: Oleksii Orel --- .../debugger/ide/debug/AbstractDebugger.java | 165 +++++++++--------- 1 file changed, 85 insertions(+), 80 deletions(-) diff --git a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java index 0db4bb49257..d7c958ead3c 100644 --- a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/AbstractDebugger.java @@ -136,35 +136,36 @@ private void addHandlers(final MessageBusProvider messageBusProvider) { public void onWsAgentStarted(WsAgentStateEvent event) { messageBus = messageBusProvider.getMachineMessageBus(); - if (isConnected()) { - Promise promise = service.getSessionInfo(debugSessionDto.getId()); - promise.then(new Operation() { - @Override - public void apply(DebugSessionDto arg) throws OperationException { - debuggerManager.setActiveDebugger(AbstractDebugger.this); - setDebugSession(arg); - - DebuggerInfo debuggerInfo = arg.getDebuggerInfo(); - String info = debuggerInfo.getName() + " " + debuggerInfo.getVersion(); - String address = debuggerInfo.getHost() + ":" + debuggerInfo.getPort(); - DebuggerDescriptor debuggerDescriptor = new DebuggerDescriptor(info, address); - JsPromise promise = Promises.resolve(null); - - for (DebuggerObserver observer : observers) { - observer.onDebuggerAttached(debuggerDescriptor, promise); - } - - startCheckingEvents(); + if (!isConnected()) { + return; + } + Promise promise = service.getSessionInfo(debugSessionDto.getId()); + promise.then(new Operation() { + @Override + public void apply(DebugSessionDto arg) throws OperationException { + debuggerManager.setActiveDebugger(AbstractDebugger.this); + setDebugSession(arg); + + DebuggerInfo debuggerInfo = arg.getDebuggerInfo(); + String info = debuggerInfo.getName() + " " + debuggerInfo.getVersion(); + String address = debuggerInfo.getHost() + ":" + debuggerInfo.getPort(); + DebuggerDescriptor debuggerDescriptor = new DebuggerDescriptor(info, address); + JsPromise promise = Promises.resolve(null); + + for (DebuggerObserver observer : observers) { + observer.onDebuggerAttached(debuggerDescriptor, promise); } - }).catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - if (isConnected()) { - invalidateDebugSession(); - } + + startCheckingEvents(); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError arg) throws OperationException { + if (!isConnected()) { + invalidateDebugSession(); } - }); - } + } + }); } @Override @@ -175,28 +176,30 @@ public void onWsAgentStopped(WsAgentStateEvent event) { this.debuggerEventsHandler = new SubscriptionHandler(new DebuggerEventUnmarshaller(dtoFactory)) { @Override public void onMessageReceived(DebuggerEventDto result) { - if (isConnected()) { - onEventListReceived(result); + if (!isConnected()) { + return; } + onEventListReceived(result); } @Override public void onErrorReceived(Throwable exception) { - if (isConnected()) { - try { - messageBus.unsubscribe(eventChannel, this); - } catch (WebSocketException e) { - Log.error(AbstractDebugger.class, e); - } + if (!isConnected()) { + return; + } + try { + messageBus.unsubscribe(eventChannel, this); + } catch (WebSocketException e) { + Log.error(AbstractDebugger.class, e); + } - if (exception instanceof ServerException) { - ServerException serverException = (ServerException)exception; - if (HTTPStatus.INTERNAL_ERROR == serverException.getHTTPStatus() - && serverException.getMessage() != null - && serverException.getMessage().contains("not found")) { + if (exception instanceof ServerException) { + ServerException serverException = (ServerException)exception; + if (HTTPStatus.INTERNAL_ERROR == serverException.getHTTPStatus() + && serverException.getMessage() != null + && serverException.getMessage().contains("not found")) { - disconnect(); - } + disconnect(); } } } @@ -357,53 +360,55 @@ public void apply(PromiseError arg) throws OperationException { @Override public void deleteBreakpoint(final VirtualFile file, final int lineNumber) { - if (isConnected()) { - LocationDto locationDto = dtoFactory.createDto(LocationDto.class); - locationDto.setLineNumber(lineNumber + 1); + if (!isConnected()) { + return; + } + LocationDto locationDto = dtoFactory.createDto(LocationDto.class); + locationDto.setLineNumber(lineNumber + 1); - String fqn = pathToFqn(file); - if (fqn == null) { - return; - } - locationDto.setTarget(fqn); + String fqn = pathToFqn(file); + if (fqn == null) { + return; + } + locationDto.setTarget(fqn); - Promise promise = service.deleteBreakpoint(debugSessionDto.getId(), locationDto); - promise.then(new Operation() { - @Override - public void apply(Void arg) throws OperationException { - for (DebuggerObserver observer : observers) { - Breakpoint breakpoint = new Breakpoint(Breakpoint.Type.BREAKPOINT, lineNumber, file.getPath(), file, false); - observer.onBreakpointDeleted(breakpoint); - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - Log.error(AbstractDebugger.class, arg.getMessage()); + Promise promise = service.deleteBreakpoint(debugSessionDto.getId(), locationDto); + promise.then(new Operation() { + @Override + public void apply(Void arg) throws OperationException { + for (DebuggerObserver observer : observers) { + Breakpoint breakpoint = new Breakpoint(Breakpoint.Type.BREAKPOINT, lineNumber, file.getPath(), file, false); + observer.onBreakpointDeleted(breakpoint); } - }); - } + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError arg) throws OperationException { + Log.error(AbstractDebugger.class, arg.getMessage()); + } + }); } @Override public void deleteAllBreakpoints() { - if (isConnected()) { - Promise promise = service.deleteAllBreakpoints(debugSessionDto.getId()); + if (!isConnected()) { + return; + } + Promise promise = service.deleteAllBreakpoints(debugSessionDto.getId()); - promise.then(new Operation() { - @Override - public void apply(Void arg) throws OperationException { - for (DebuggerObserver observer : observers) { - observer.onAllBreakpointsDeleted(); - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - Log.error(AbstractDebugger.class, arg.getMessage()); + promise.then(new Operation() { + @Override + public void apply(Void arg) throws OperationException { + for (DebuggerObserver observer : observers) { + observer.onAllBreakpointsDeleted(); } - }); - } + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError arg) throws OperationException { + Log.error(AbstractDebugger.class, arg.getMessage()); + } + }); } @Override From 44b6e463615f979a7618eb58d5b6b892cd826b02 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 18 Nov 2016 16:53:54 +0200 Subject: [PATCH 04/74] CODENVY-1127; Avoid of concurrent snapshots on same node. (#3125) --- .../org/eclipse/che/plugin/docker/machine/DockerInstance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstance.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstance.java index 1a058bb1fa8..f09fdcb7e59 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstance.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstance.java @@ -247,7 +247,7 @@ public MachineSource saveToSnapshot() throws MachineException { } @VisibleForTesting - void commitContainer(String repository, String tag) throws IOException { + protected void commitContainer(String repository, String tag) throws IOException { String comment = format("Suspended at %1$ta %1$tb %1$td %1$tT %1$tZ %1$tY", System.currentTimeMillis()); // !! We SHOULD NOT pause container before commit because all execs will fail From 13000b066f56d27792e9b625cb0c8742d04e6444 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Fri, 18 Nov 2016 17:11:04 +0100 Subject: [PATCH 05/74] Issue 3029 - Add a 'warning' state for the notifications (#3113) Using the `#F0AD4E` code for the darkish orange background, so the font can remain white and be consistent with other types of notifications Signed-off-by: Xavier Coulon --- .../api/notification/StatusNotification.java | 1 + .../org/eclipse/che/ide/api/theme/Theme.java | 5 +++- .../NotificationContainerItem.java | 4 ++++ .../ide/notification/NotificationPopup.java | 10 +++++++- .../notification/NotificationResources.java | 5 ++++ .../org/eclipse/che/ide/theme/DarkTheme.java | 10 ++++++++ .../org/eclipse/che/ide/theme/LightTheme.java | 12 +++++++++- .../che/ide/notification/notification.css | 10 ++++++++ .../eclipse/che/ide/notification/warning.svg | 24 +++++++++++++++++++ 9 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/warning.svg diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/notification/StatusNotification.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/notification/StatusNotification.java index a8764988b1f..3f00257e623 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/notification/StatusNotification.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/notification/StatusNotification.java @@ -23,6 +23,7 @@ public class StatusNotification extends Notification { public enum Status { PROGRESS, SUCCESS, + WARNING, FAIL } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java index 63c05a047f9..cc1b00b541d 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java @@ -1493,7 +1493,6 @@ public interface Theme { */ String loaderProgressStatusColor(); - /** * The placeholder color for input fields. * @@ -1529,6 +1528,8 @@ public interface Theme { String notificationPopupProgressBackground(); + String notificationPopupWarningBackground(); + String notificationPopupPanelShadow(); String notificationPopupIconSuccessFill(); @@ -1537,6 +1538,8 @@ public interface Theme { String notificationPopupIconProgressFill(); + String notificationPopupIconWarningFill(); + String notificationPopupIconSvgFill(); String notificationPopupTextColor(); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationContainerItem.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationContainerItem.java index ebd3a413241..dfff6422e33 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationContainerItem.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationContainerItem.java @@ -228,6 +228,10 @@ private SVGImage getIconBaseOnStatus() { icon = resources.fail(); status = "fail"; break; + case WARNING: + icon = resources.warning(); + status = "warning"; + break; default: throw new IllegalArgumentException("Can't determine notification icon"); } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationPopup.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationPopup.java index 3e7d9d9d627..bac07cdf8cd 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationPopup.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationPopup.java @@ -199,6 +199,10 @@ private SVGImage getIconBaseOnStatus() { icon = resources.fail(); status = "fail"; break; + case WARNING: + icon = resources.warning(); + status = "warning"; + break; default: throw new IllegalArgumentException("Can't determine notification icon"); } @@ -301,6 +305,7 @@ private void update() { removeStyleName(resources.notificationCss().notificationStatusProgress()); removeStyleName(resources.notificationCss().notificationStatusSuccess()); removeStyleName(resources.notificationCss().notificationStatusFail()); + removeStyleName(resources.notificationCss().notificationStatusWarning()); DisplayMode displayMode = notification.getDisplayMode(); Status status = notification.getStatus(); @@ -312,8 +317,11 @@ private void update() { setStyleName(resources.notificationCss().notificationStatusSuccess(), true); break; case FAIL: - setStyleName(resources.notificationCss().notificationStatusFail(), true); + setStyleName(resources.notificationCss().notificationStatusFail(), true); break; + case WARNING: + setStyleName(resources.notificationCss().notificationStatusWarning(), true); + break; } if (FLOAT_MODE == displayMode && PROGRESS == status) { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationResources.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationResources.java index 45488f77543..cf1253346f8 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationResources.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationResources.java @@ -46,6 +46,8 @@ interface NotificationCss extends CssResource { String notificationStatusFail(); + String notificationStatusWarning(); + String notificationPopup(); String notificationPopupContentWrapper(); @@ -78,4 +80,7 @@ interface NotificationCss extends CssResource { @Source("progress.svg") SVGResource progress(); + + @Source("warning.svg") + SVGResource warning(); } \ No newline at end of file diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java index 39cf2cc299b..df928046b05 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java @@ -1361,6 +1361,11 @@ public String notificationPopupProgressBackground() { return "#9b9b9b"; } + @Override + public String notificationPopupWarningBackground() { + return "#F0AD4E"; + } + @Override public String notificationPopupPanelShadow() { return "0 0 10px rgba(0,0,0,0.6)"; @@ -1381,6 +1386,11 @@ public String notificationPopupIconProgressFill() { return "#9b9b9b"; } + @Override + public String notificationPopupIconWarningFill() { + return "#F0AD4E"; + } + @Override public String notificationPopupIconSvgFill() { return "#FFFFFF"; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java index a1d0c001793..131ac1cc205 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java @@ -1337,6 +1337,11 @@ public String notificationPopupProgressBackground() { return "#9b9b9b"; } + @Override + public String notificationPopupWarningBackground() { + return "#F0AD4E"; + } + @Override public String notificationPopupPanelShadow() { return "0 0 7px rgba(0,0,0,0.2)"; @@ -1356,7 +1361,12 @@ public String notificationPopupIconFailFill() { public String notificationPopupIconProgressFill() { return "#9b9b9b"; } - + + @Override + public String notificationPopupIconWarningFill() { + return "#F0AD4E"; + } + @Override public String notificationPopupIconSvgFill() { return "#FFFFFF"; diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/notification.css b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/notification.css index 566553633a5..8700ce2df16 100644 --- a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/notification.css +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/notification.css @@ -11,10 +11,12 @@ @eval notificationPopupSuccessBackground org.eclipse.che.ide.api.theme.Style.theme.notificationPopupSuccessBackground(); @eval notificationPopupFailBackground org.eclipse.che.ide.api.theme.Style.theme.notificationPopupFailBackground(); @eval notificationPopupProgressBackground org.eclipse.che.ide.api.theme.Style.theme.notificationPopupProgressBackground(); +@eval notificationPopupWarningBackground org.eclipse.che.ide.api.theme.Style.theme.notificationPopupWarningBackground(); @eval notificationPopupPanelShadow org.eclipse.che.ide.api.theme.Style.theme.notificationPopupPanelShadow(); @eval notificationPopupIconSuccessFill org.eclipse.che.ide.api.theme.Style.theme.notificationPopupIconSuccessFill(); @eval notificationPopupIconFailFill org.eclipse.che.ide.api.theme.Style.theme.notificationPopupIconFailFill(); @eval notificationPopupIconProgressFill org.eclipse.che.ide.api.theme.Style.theme.notificationPopupIconProgressFill(); +@eval notificationPopupIconWarningFill org.eclipse.che.ide.api.theme.Style.theme.notificationPopupIconWarningFill(); @eval notificationPopupIconSvgFill org.eclipse.che.ide.api.theme.Style.theme.notificationPopupIconSvgFill(); @eval notificationPopupTextColor org.eclipse.che.ide.api.theme.Style.theme.notificationPopupTextColor(); @eval closeNotificationButtonColor org.eclipse.che.ide.api.theme.Style.theme.closeNotificationButtonColor(); @@ -60,6 +62,10 @@ fill: notificationPopupIconProgressFill; } +.notificationIconWrapper svg[name="warning"] { + fill: notificationPopupIconWarningFill; +} + .notificationContentWrapper{ display: inline-block; width: literal("calc(100% - 75px)"); @@ -129,6 +135,10 @@ background-color: notificationPopupProgressBackground; } +.notificationStatusWarning { + background-color: notificationPopupWarningBackground; +} + .notificationStatusSuccess { background-color: notificationPopupSuccessBackground; } diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/warning.svg b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/warning.svg new file mode 100644 index 00000000000..2c2feebd115 --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/notification/warning.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + From 6b111349761c9190facebf6162e778f47043f7c7 Mon Sep 17 00:00:00 2001 From: Alexander Garagatyi Date: Mon, 21 Nov 2016 17:39:54 +0200 Subject: [PATCH 06/74] CODENVY-593: fix workspace stopping (#3133) Signed-off-by: Alexander Garagatyi --- .../server/CheEnvironmentEngine.java | 7 +- .../WorkspaceRuntimeIntegrationTest.java | 204 ++++++++++++++++++ .../server/WorkspaceRuntimesTest.java | 4 +- 3 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimeIntegrationTest.java diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java index 9b56fd8c48f..9694ee85de9 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java @@ -279,14 +279,13 @@ public void stop(String workspaceId) throws EnvironmentNotRunningException, ServerException { List machinesCopy = null; EnvironmentHolder environmentHolder; - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { environmentHolder = environments.get(workspaceId); if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) { throw new EnvironmentNotRunningException( format("Stop of not running environment of workspace with ID '%s' is not allowed.", workspaceId)); } - environments.remove(workspaceId); List machines = environmentHolder.machines; if (machines != null && !machines.isEmpty()) { machinesCopy = new ArrayList<>(machines); @@ -297,6 +296,10 @@ public void stop(String workspaceId) throws EnvironmentNotRunningException, if (machinesCopy != null) { destroyEnvironment(environmentHolder.networkId, machinesCopy); } + + try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + environments.remove(workspaceId); + } } /** diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimeIntegrationTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimeIntegrationTest.java new file mode 100644 index 00000000000..17f0352ab20 --- /dev/null +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimeIntegrationTest.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.workspace.server; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import org.eclipse.che.api.agent.server.AgentRegistry; +import org.eclipse.che.api.agent.server.impl.AgentSorter; +import org.eclipse.che.api.agent.server.launcher.AgentLauncherFactory; +import org.eclipse.che.api.core.ApiException; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.model.workspace.Environment; +import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.core.util.LineConsumer; +import org.eclipse.che.api.environment.server.CheEnvironmentEngine; +import org.eclipse.che.api.environment.server.ContainerNameGenerator; +import org.eclipse.che.api.environment.server.DefaultServicesStartStrategy; +import org.eclipse.che.api.environment.server.EnvironmentParser; +import org.eclipse.che.api.environment.server.InfrastructureProvisioner; +import org.eclipse.che.api.environment.server.MachineInstanceProvider; +import org.eclipse.che.api.environment.server.model.CheServiceImpl; +import org.eclipse.che.api.environment.server.model.CheServicesEnvironmentImpl; +import org.eclipse.che.api.machine.server.MachineInstanceProviders; +import org.eclipse.che.api.machine.server.model.impl.MachineConfigImpl; +import org.eclipse.che.api.machine.server.spi.Instance; +import org.eclipse.che.api.machine.server.spi.SnapshotDao; +import org.eclipse.che.api.machine.server.util.RecipeDownloader; +import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto; +import org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto; +import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; +import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.SubjectImpl; +import org.eclipse.che.commons.test.mockito.answer.WaitingAnswer; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.slf4j.Logger; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.eclipse.che.dto.server.DtoFactory.newDto; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * @author Alexander Garagatyi + */ +@Listeners(MockitoTestNGListener.class) +public class WorkspaceRuntimeIntegrationTest { + private static final Logger LOG = getLogger(WorkspaceRuntimeIntegrationTest.class); + private static final String WORKSPACE_ID = "workspace123"; + private static final String ENV_NAME = "default-env"; + + @Mock + private EventService eventService; + @Mock + private SnapshotDao snapshotDao; + @Mock + private MachineInstanceProviders machineInstanceProviders; + @Mock + private EnvironmentParser environmentParser; + @Mock + private MachineInstanceProvider instanceProvider; + @Mock + private InfrastructureProvisioner infrastructureProvisioner; + @Mock + private RecipeDownloader recipeDownloader; + @Mock + private ContainerNameGenerator containerNameGenerator; + @Mock + private AgentRegistry agentRegistry; + @Mock + private AgentSorter agentSorter; + @Mock + private AgentLauncherFactory launcherFactory; + + private ExecutorService executor; + private WorkspaceRuntimes runtimes; + + @BeforeMethod + public void setUp() throws Exception { + CheEnvironmentEngine environmentEngine = new CheEnvironmentEngine(snapshotDao, + machineInstanceProviders, + "/tmp", + 2000, + eventService, + environmentParser, + new DefaultServicesStartStrategy(), + instanceProvider, + infrastructureProvisioner, + "http://localhost:8080/api", + recipeDownloader, + containerNameGenerator, + agentRegistry); + + runtimes = new WorkspaceRuntimes(eventService, + environmentEngine, + agentSorter, + launcherFactory, + agentRegistry); + + executor = Executors.newFixedThreadPool( + 1, new ThreadFactoryBuilder().setNameFormat(this.getClass().toString() + "-%d").build()); + + EnvironmentContext.getCurrent().setSubject(new SubjectImpl("name", "id", "token", false)); + } + + @AfterMethod + public void tearDown() throws Exception { + executor.shutdownNow(); + + EnvironmentContext.reset(); + } + + // Check for https://github.com/codenvy/codenvy/issues/593 + @Test(expectedExceptions = NotFoundException.class, + expectedExceptionsMessageRegExp = "Workspace with id '" + WORKSPACE_ID + "' is not running.") + public void environmentEngineShouldDestroyAllMachinesBeforeRemovalOfEnvironmentRecord() throws Exception { + // given + EnvironmentDto environment = newDto(EnvironmentDto.class); + environment.withMachines(singletonMap("service1", newDto(ExtendedMachineDto.class) + .withAgents(singletonList("org.eclipse.che.ws-agent")))); + WorkspaceConfigDto config = newDto(WorkspaceConfigDto.class) + .withDefaultEnv(ENV_NAME) + .withName("ws1") + .withEnvironments(singletonMap(ENV_NAME, environment)); + WorkspaceDto workspace = newDto(WorkspaceDto.class).withId(WORKSPACE_ID) + .withNamespace("namespace") + .withConfig(config); + Instance instance = mock(Instance.class); + MachineConfigImpl machineConfig = new MachineConfigImpl(); + machineConfig.setDev(true); + machineConfig.setName("service1"); + when(instance.getWorkspaceId()).thenReturn(WORKSPACE_ID); + when(instance.getId()).thenReturn("machineId"); + when(instance.getConfig()).thenReturn(machineConfig); + + CheServicesEnvironmentImpl internalEnv = new CheServicesEnvironmentImpl(); + internalEnv.getServices().put("service1", new CheServiceImpl().withId("machineId")); + + when(environmentParser.parse(any(Environment.class))).thenReturn(internalEnv); + when(instanceProvider.startService(anyString(), + anyString(), + anyString(), + anyString(), + anyBoolean(), + anyString(), + any(CheServiceImpl.class), + any(LineConsumer.class))) + .thenReturn(instance); + + runtimes.start(workspace, ENV_NAME, false); + + WaitingAnswer waitingAnswer = new WaitingAnswer<>(); + doAnswer(waitingAnswer).when(instance).destroy(); + + // when + executor.execute(() -> { + try { + runtimes.stop(WORKSPACE_ID); + } catch (ApiException e) { + LOG.error(e.getLocalizedMessage(), e); + } + }); + + waitingAnswer.waitAnswerCall(1, TimeUnit.SECONDS); + + // then + // no exception - environment and workspace are still running + runtimes.get(WORKSPACE_ID); + // let instance removal proceed + waitingAnswer.completeAnswer(); + // verify destroying was called + verify(instance, timeout(1000)).destroy(); + verify(instanceProvider, timeout(1000)).destroyNetwork(anyString()); + // wait to ensure that removal of runtime is finished + Thread.sleep(500); + // runtime is removed - now getting of it should throw an exception + runtimes.get(WORKSPACE_ID); + } +} diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java index ebd1c825066..eda27ec77c7 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java @@ -85,11 +85,9 @@ public class WorkspaceRuntimesTest { private static final String ENV_NAME = "default-env"; @Mock - private EventService eventService; - + private EventService eventService; @Mock private CheEnvironmentEngine environmentEngine; - @Mock private AgentSorter agentSorter; @Mock From 4bad844864fb2b87286be2b043a6a3c827ed6d43 Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Tue, 22 Nov 2016 15:47:11 +0200 Subject: [PATCH 07/74] CHE-2157: preparation for merge https://github.com/eclipse/che/pull/2157 (#3095) * added java test runner plugin to the che project Signed-off-by: Mirage Abeysekara --- assembly/assembly-ide-war/pom.xml | 20 ++ .../resources/org/eclipse/che/ide/IDE.gwt.xml | 2 + assembly/assembly-wsagent-war/pom.xml | 24 ++ .../pom.xml | 45 +++ .../server/MavenTestClasspathProvider.java | 106 ++++++ .../inject/TestMavenClasspathGuiceModule.java | 29 ++ .../che-java-testing-classpath/pom.xml | 28 ++ .../che-java-testing-core-ide/pom.xml | 126 ++++++++ .../java/testing/core/client/TestAction.java | 35 ++ .../testing/core/client/TestExtension.java | 70 ++++ .../testing/core/client/TestGinModule.java | 32 ++ .../core/client/TestLocalizationConstant.java | 53 +++ .../testing/core/client/TestResources.java | 32 ++ .../core/client/TestServiceClient.java | 66 ++++ .../core/client/view/TestResultPresenter.java | 89 ++++++ .../core/client/view/TestResultView.java | 43 +++ .../core/client/view/TestResultViewImpl.java | 231 ++++++++++++++ .../view/navigation/TestClassNavigation.java | 20 ++ .../factory/TestResultNodeFactory.java | 34 ++ .../navigation/nodes/TestResultClassNode.java | 80 +++++ .../navigation/nodes/TestResultGroupNode.java | 84 +++++ .../nodes/TestResultMethodNode.java | 107 +++++++ .../java/testing/core/TestExtension.gwt.xml | 22 ++ .../TestLocalizationConstant.properties | 30 ++ .../ext/java/testing/core/client/svg/test.svg | 18 ++ .../java/testing/core/client/svg/test_all.svg | 74 +++++ .../testing/core/client/svg/test_results.svg | 52 +++ .../core/client/svg/test_results_fail.svg | 52 +++ .../core/client/svg/test_results_pass.svg | 52 +++ .../client/view/TestResultViewImpl.ui.xml | 50 +++ .../client/view/TestResultPresenterTest.java | 103 ++++++ .../che-java-testing-core-server/pom.xml | 94 ++++++ .../testing/core/server/TestingService.java | 119 +++++++ .../classpath/TestClasspathProvider.java | 37 +++ .../classpath/TestClasspathRegistry.java | 51 +++ .../framework/TestFrameworkRegistry.java | 51 +++ .../core/server/framework/TestRunner.java | 44 +++ .../core/server/inject/TestGuiceModule.java | 34 ++ .../core/server/TestingServiceTest.java | 146 +++++++++ .../che-java-testing-core-shared/pom.xml | 153 +++++++++ .../ext/java/testing/core/shared/Failure.java | 67 ++++ .../java/testing/core/shared/TestResult.java | 56 ++++ .../che-java-testing-core/pom.xml | 31 ++ .../che-java-testing-junit-ide/pom.xml | 84 +++++ .../testing/junit/client/JUnitGinModule.java | 29 ++ .../testing/junit/client/JUnitTestAction.java | 65 ++++ .../client/JUnitTestLocalizationConstant.java | 40 +++ .../junit/client/JUnitTestResources.java | 27 ++ .../junit/client/action/RunAllTestAction.java | 101 ++++++ .../action/RunClassContextTestAction.java | 152 +++++++++ .../client/action/RunClassTestAction.java | 116 +++++++ .../JUnitTestLocalizationConstant.properties | 23 ++ .../java/testing/junit/client/svg/test.svg | 18 ++ .../testing/junit/client/svg/test_all.svg | 74 +++++ .../che-java-testing-junit-server/pom.xml | 53 +++ .../testing/junit/server/JUnitTestRunner.java | 302 ++++++++++++++++++ .../junit/server/inject/JunitGuiceModule.java | 29 ++ .../che-java-testing-junit-shared/pom.xml | 157 +++++++++ .../junit4x/shared/JUnitTestResult.java | 36 +++ .../che-java-testing-junit/pom.xml | 30 ++ .../che-java-testing-testng-ide/pom.xml | 84 +++++ .../testng/client/TestNGGinModule.java | 27 ++ .../client/TestNGLocalizationConstant.java | 46 +++ .../testng/client/TestNGResources.java | 27 ++ .../testng/client/TestNGTestAction.java | 74 +++++ .../client/action/RunAllTestAction.java | 102 ++++++ .../action/RunClassContextTestAction.java | 152 +++++++++ .../client/action/RunClassTestAction.java | 121 +++++++ .../client/action/RunTestXMLAction.java | 105 ++++++ .../TestNGLocalizationConstant.properties | 26 ++ .../java/testing/testng/client/svg/test.svg | 18 ++ .../testing/testng/client/svg/test_all.svg | 74 +++++ .../che-java-testing-testng-server/pom.xml | 53 +++ .../testing/testng/server/TestNGRunner.java | 265 +++++++++++++++ .../server/inject/TestNGGuiceModule.java | 29 ++ .../che-java-testing-testng/pom.xml | 29 ++ plugins/plugin-java-test-runner/pom.xml | 30 ++ plugins/pom.xml | 1 + pom.xml | 50 +++ 79 files changed, 5341 insertions(+) create mode 100644 plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/MavenTestClasspathProvider.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/inject/TestMavenClasspathGuiceModule.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestExtension.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestGinModule.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestResources.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestServiceClient.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultView.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/TestClassNavigation.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/factory/TestResultNodeFactory.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultClassNode.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultGroupNode.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultMethodNode.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/TestExtension.gwt.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.properties create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_all.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_fail.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_pass.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.ui.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingService.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathProvider.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathRegistry.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestFrameworkRegistry.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestRunner.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/inject/TestGuiceModule.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/test/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingServiceTest.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/Failure.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/TestResult.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-core/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitGinModule.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestResources.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunAllTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassContextTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.properties create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test_all.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/JUnitTestRunner.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/inject/JunitGuiceModule.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/junit4x/shared/JUnitTestResult.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGGinModule.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGResources.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunAllTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassContextTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassTestAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunTestXMLAction.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.properties create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test_all.svg create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/TestNGRunner.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/inject/TestNGGuiceModule.java create mode 100644 plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml create mode 100644 plugins/plugin-java-test-runner/pom.xml diff --git a/assembly/assembly-ide-war/pom.xml b/assembly/assembly-ide-war/pom.xml index 33a4cdca6df..397dc7a2ff3 100644 --- a/assembly/assembly-ide-war/pom.xml +++ b/assembly/assembly-ide-war/pom.xml @@ -80,6 +80,26 @@ org.eclipse.che.lib che-swagger-module + + org.eclipse.che.plugin + che-java-testing-core-ide + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + che-java-testing-junit-ide + + + org.eclipse.che.plugin + che-java-testing-junit-shared + + + org.eclipse.che.plugin + che-java-testing-testng-ide + org.eclipse.che.plugin che-plugin-cpp-lang-ide diff --git a/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml b/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml index b2421f5206d..9cd5ab567ae 100644 --- a/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml +++ b/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml @@ -84,6 +84,7 @@ + @@ -93,4 +94,5 @@ + diff --git a/assembly/assembly-wsagent-war/pom.xml b/assembly/assembly-wsagent-war/pom.xml index 1020de35803..03440bb329c 100644 --- a/assembly/assembly-wsagent-war/pom.xml +++ b/assembly/assembly-wsagent-war/pom.xml @@ -102,6 +102,30 @@ org.eclipse.che.lib che-swagger-module + + org.eclipse.che.plugin + che-java-testing-classpath-maven-server + + + org.eclipse.che.plugin + che-java-testing-core-server + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + che-java-testing-junit-server + + + org.eclipse.che.plugin + che-java-testing-junit-shared + + + org.eclipse.che.plugin + che-java-testing-testng-server + org.eclipse.che.plugin che-plugin-cpp-lang-server diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml new file mode 100644 index 00000000000..7e9d6a34ef9 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml @@ -0,0 +1,45 @@ + + + + 4.0.0 + + che-java-testing-classpath + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-classpath-maven-server + Che Plugin :: Java Testing :: Maven Classpath + + + com.google.inject + guice + + + com.google.inject.extensions + guice-multibindings + + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-commons-inject + + + org.eclipse.che.plugin + che-java-testing-core-server + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/MavenTestClasspathProvider.java b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/MavenTestClasspathProvider.java new file mode 100644 index 00000000000..4e02d456985 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/MavenTestClasspathProvider.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.classpath.maven.server; + + +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.ide.ext.java.testing.core.server.classpath.TestClasspathProvider; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +/** + * Maven implementation for the test classpath provider. + * + * @author Mirage Abeysekara + */ +public class MavenTestClasspathProvider implements TestClasspathProvider { + + private boolean buildClasspath(String projectPath) throws IOException, InterruptedException { + + final CommandLine commandLineClassPath = new CommandLine("mvn", "clean", "dependency:build-classpath", + "-Dmdep.outputFile=target/test.classpath.maven"); + Process processBuildClassPath = new ProcessBuilder() + .redirectErrorStream(true) + .directory(new File(projectPath)) + .command(commandLineClassPath.toShellCommand()) + .start(); + ProcessUtil.process(processBuildClassPath, LineConsumer.DEV_NULL, LineConsumer.DEV_NULL); + processBuildClassPath.waitFor(); + + final CommandLine commandLineTestCompile = new CommandLine("mvn", "test-compile"); + Process processTestCompile = new ProcessBuilder() + .redirectErrorStream(true) + .directory(new File(projectPath)) + .command(commandLineTestCompile.toShellCommand()) + .start(); + ProcessUtil.process(processTestCompile, LineConsumer.DEV_NULL, LineConsumer.DEV_NULL); + return processTestCompile.waitFor() == 0; + + } + + private List getProjectClasspath(String projectPath) throws IOException { + + List classUrls = new ArrayList<>(); + File cpFile = Paths.get(projectPath, "target", "test.classpath.maven").toFile(); + + FileReader fileReader = new FileReader(cpFile); + BufferedReader bufferedReader = new BufferedReader(fileReader); + + String line = bufferedReader.readLine(); + String[] paths = line.split(":"); + + for (String path : paths) { + classUrls.add(new File(path).toURI().toURL()); + } + bufferedReader.close(); + fileReader.close(); + + classUrls.add(Paths.get(projectPath, "target", "classes").toUri().toURL()); + classUrls.add(Paths.get(projectPath, "target", "test-classes").toUri().toURL()); + + return classUrls; + } + + /** + * {@inheritDoc} + */ + @Override + public ClassLoader getClassLoader(String projectPath, boolean updateClasspath) throws Exception { + List classUrls; + try { + if (updateClasspath) { + buildClasspath(projectPath); + } + classUrls = getProjectClasspath(projectPath); + } catch (IOException | InterruptedException e) { + throw new Exception("Failed to build Maven classpath.", e); + } + return new URLClassLoader(classUrls.toArray(new URL[classUrls.size()]), null); + } + + /** + * {@inheritDoc} + */ + @Override + public String getProjectType() { + return "maven"; + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/inject/TestMavenClasspathGuiceModule.java b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/inject/TestMavenClasspathGuiceModule.java new file mode 100644 index 00000000000..5c6451007cf --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/src/main/java/org/eclipse/che/ide/ext/java/testing/classpath/maven/server/inject/TestMavenClasspathGuiceModule.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.classpath.maven.server.inject; + +import com.google.inject.AbstractModule; +import org.eclipse.che.ide.ext.java.testing.classpath.maven.server.MavenTestClasspathProvider; +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathProvider; +import org.eclipse.che.inject.DynaModule; + +import static com.google.inject.multibindings.Multibinder.newSetBinder; + +/** + * @author Mirage Abeysekara + */ +@DynaModule +public class TestMavenClasspathGuiceModule extends AbstractModule { + @Override + protected void configure() { + newSetBinder(binder(), TestClasspathProvider.class).addBinding().to(MavenTestClasspathProvider.class); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml new file mode 100644 index 00000000000..36630e9bdc9 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml @@ -0,0 +1,28 @@ + + + + 4.0.0 + + che-plugin-java-test-runner-parent + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-classpath + pom + Che Plugin :: Java Testing :: Classpath Patent + + che-java-testing-classpath-maven-server + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml new file mode 100644 index 00000000000..bea18bead89 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml @@ -0,0 +1,126 @@ + + + + 4.0.0 + + che-java-testing-core + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-core-ide + Che Plugin :: Java Testing :: Core IDE + + + com.google.guava + guava + + + com.google.gwt + gwt-user + + + com.google.gwt.inject + gin + + + com.google.inject + guice + + + com.google.inject.extensions + guice-assistedinject + + + javax.validation + validation-api + + + org.eclipse.che.core + che-core-commons-gwt + + + org.eclipse.che.core + che-core-ide-api + + + org.eclipse.che.core + che-core-ide-ui + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + che-plugin-java-ext-lang-client + + + org.eclipse.che.plugin + che-plugin-maven-shared + + + org.vectomatic + lib-gwt-svg + + + com.google.gwt + gwt-dev + provided + + + com.google.gwt.gwtmockito + gwtmockito + test + + + junit + junit + test + + + org.mockito + mockito-core + test + + + + + + src/main/java + + **/*.java + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + + org.eclipse.che.plugin:che-plugin-maven-shared + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestAction.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestAction.java new file mode 100644 index 00000000000..d0daf19e6ed --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestAction.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client; + +import org.eclipse.che.ide.api.action.DefaultActionGroup; +/** + * Interface for defining test framework IDE actions for the test runner. All test framework implementations should + * implement this interface in order to appear testing actions in menus + * + * @author Mirage Abeysekara + */ +public interface TestAction { + + /** + * This method get called when the extension is loading and adding the menu items for the main menu. + * @param testMainMenu Main menu item for test actions + */ + void addMainMenuItems(DefaultActionGroup testMainMenu); + + /** + * This method get called when the extension is loading and adding the menu items for the project explorer + * context menu. + * @param testContextMenu Context menu item for test actions + */ + void addContextMenuItems(DefaultActionGroup testContextMenu); + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestExtension.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestExtension.java new file mode 100644 index 00000000000..13eb98b7d2f --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestExtension.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.ide.api.extension.Extension; +import org.eclipse.che.ide.util.loging.Log; + +import java.util.Set; + +import static org.eclipse.che.ide.api.action.IdeActions.GROUP_MAIN_CONTEXT_MENU; +import static org.eclipse.che.ide.api.action.IdeActions.GROUP_RUN; + +/** + * Java test extension. + * + * @author Mirage Abeysekara + */ +@Singleton +@Extension(title = "Test Extension", version = "1.0.0") +public class TestExtension { + + @Inject + public TestExtension(ActionManager actionManager, TestLocalizationConstant localization, + Set testActions) { + + Log.info(TestExtension.class, "Java TestRunner Plugin"); + + DefaultActionGroup runMenu = (DefaultActionGroup) actionManager.getAction(GROUP_RUN); + + DefaultActionGroup testMainMenu = + new DefaultActionGroup(localization.actionGroupMenuName(), true, actionManager); + actionManager.registerAction("TestMainGroup", testMainMenu); + + for (TestAction testAction : testActions) { + testAction.addMainMenuItems(testMainMenu); + testMainMenu.addSeparator(); + } + + runMenu.addSeparator(); + runMenu.add(testMainMenu); + + + DefaultActionGroup explorerMenu = (DefaultActionGroup) actionManager.getAction(GROUP_MAIN_CONTEXT_MENU); + DefaultActionGroup testContextMenu = + new DefaultActionGroup(localization.actionGroupMenuName(), true, actionManager); + actionManager.registerAction("TestContextGroup", testContextMenu); + + for (TestAction testAction : testActions) { + testAction.addContextMenuItems(testContextMenu); + testContextMenu.addSeparator(); + } + + explorerMenu.addSeparator(); + explorerMenu.add(testContextMenu); + explorerMenu.addSeparator(); + + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestGinModule.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestGinModule.java new file mode 100644 index 00000000000..5fc530e0917 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestGinModule.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client; + +import com.google.gwt.inject.client.AbstractGinModule; +import com.google.gwt.inject.client.assistedinject.GinFactoryModuleBuilder; + +import org.eclipse.che.ide.api.extension.ExtensionGinModule; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultView; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultViewImpl; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.factory.TestResultNodeFactory; +/** + * Gin Module for test runner extension. + * + * @author Mirage Abeysekara + */ +@ExtensionGinModule +public class TestGinModule extends AbstractGinModule{ + @Override + protected void configure() { + install(new GinFactoryModuleBuilder().build(TestResultNodeFactory.class)); + bind(TestResultView.class).to(TestResultViewImpl.class); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.java new file mode 100644 index 00000000000..cd6c4006866 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client; + +import com.google.gwt.i18n.client.Messages; + +/** + * Localization constants. Interface to represent the constants defined in resource bundle: + * 'TestLocalizationConstant.properties'. + * + * @author Mirage Abeysekara + */ +public interface TestLocalizationConstant extends Messages { + + /* Actions */ + + @Key("actionGroup.menu.name") + String actionGroupMenuName(); + + @Key("action.runClass.title") + String actionRunClassTitle(); + + @Key("action.runClass.description") + String actionRunClassDescription(); + + @Key("action.runClassContext.title") + String actionRunClassContextTitle(); + + @Key("action.runClassContext.description") + String actionRunClassContextDescription(); + + @Key("action.runAll.title") + String actionRunAllTitle(); + + @Key("action.runAll.description") + String actionRunAllDescription(); + + /* Titles */ + + @Key("title.testResultPresenter") + String titleTestResultPresenter(); + + @Key("title.testResultPresenter.toolTip") + String titleTestResultPresenterToolTip(); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestResources.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestResources.java new file mode 100644 index 00000000000..cdb9a76713a --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestResources.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client; + +import com.google.gwt.resources.client.ClientBundle; +import org.vectomatic.dom.svg.ui.SVGResource; + +/** + * Resources for test extension. + * + * @author Mirage Abeysekara + */ +public interface TestResources extends ClientBundle { + + @Source("org/eclipse/che/ide/ext/java/testing/core/client/svg/test.svg") + SVGResource testIcon(); + + + @Source("org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_pass.svg") + SVGResource testResultsPass(); + + @Source("org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_fail.svg") + SVGResource testResultsFail(); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestServiceClient.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestServiceClient.java new file mode 100644 index 00000000000..8e774edd751 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/TestServiceClient.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client; + +import com.google.gwt.http.client.URL; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.MimeType; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.rest.AsyncRequestFactory; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; +import org.eclipse.che.ide.rest.HTTPHeader; +import org.eclipse.che.ide.util.loging.Log; + +import java.util.Map; + +/** + * Client for calling test services + * + * @author Mirage Abeysekara + */ +@Singleton +public class TestServiceClient { + + private final AppContext appContext; + private final AsyncRequestFactory asyncRequestFactory; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + + @Inject + public TestServiceClient(AppContext appContext, AsyncRequestFactory asyncRequestFactory, + DtoUnmarshallerFactory dtoUnmarshallerFactory) { + + this.appContext = appContext; + this.asyncRequestFactory = asyncRequestFactory; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + + } + + public Promise getTestResult(String projectPath, String testFramework, Map parameters) { + StringBuilder sb = new StringBuilder(); + if (parameters != null) { + for (Map.Entry e : parameters.entrySet()) { + if (sb.length() > 0) { + sb.append('&'); + } + sb.append(URL.encode(e.getKey())).append('=').append(URL.encode(e.getValue())); + } + } + String url = appContext.getDevMachine().getWsAgentBaseUrl() + "/java/testing/run/?projectPath=" + projectPath + "&testFramework=" + testFramework + "&" + + sb.toString(); + return asyncRequestFactory.createGetRequest(url) + .header(HTTPHeader.ACCEPT, MimeType.APPLICATION_JSON) + .send(dtoUnmarshallerFactory.newUnmarshaller(TestResult.class)); + } + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java new file mode 100644 index 00000000000..90d2bfd1045 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.gwt.user.client.ui.IsWidget; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.eclipse.che.ide.api.parts.PartStackType; +import org.eclipse.che.ide.api.parts.WorkspaceAgent; +import org.eclipse.che.ide.api.parts.base.BasePresenter; +import org.eclipse.che.ide.ext.java.testing.core.client.TestLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.core.client.TestResources; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.vectomatic.dom.svg.ui.SVGResource; + +/** + * Presenter for the displaying the test results on the workspace. + * + * @author Mirage Abeysekara + */ +@Singleton +public class TestResultPresenter extends BasePresenter implements TestResultView.ActionDelegate { + private final WorkspaceAgent workspaceAgent; + private final TestLocalizationConstant localizationConstant; + private final TestResources resources; + private final TestResultView view; + + @Inject + public TestResultPresenter(WorkspaceAgent workspaceAgent, + TestLocalizationConstant localizationConstant, + TestResources resources, + TestResultView view) { + this.workspaceAgent = workspaceAgent; + this.localizationConstant = localizationConstant; + this.resources = resources; + this.view = view; + view.setDelegate(this); + } + + @Override + public String getTitle() { + return localizationConstant.titleTestResultPresenter(); + } + + @Override + public void setVisible(boolean visible) { + view.setVisible(visible); + } + + @Override + public IsWidget getView() { + return view; + } + + @Override + public String getTitleToolTip() { + return localizationConstant.titleTestResultPresenterToolTip(); + } + + @Override + public SVGResource getTitleImage() { + return resources.testIcon(); + } + + @Override + public void go(AcceptsOneWidget container) { + container.setWidget(view); + } + + /** + * Activate Test results part and showing the test results. + * + * @param response result of the test runner + */ + public void handleResponse(TestResult response) { + workspaceAgent.openPart(this, PartStackType.INFORMATION); + workspaceAgent.setActivePart(this); + view.showResults(response); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultView.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultView.java new file mode 100644 index 00000000000..4df4c8e060a --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultView.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view; + +import org.eclipse.che.ide.api.mvp.View; +import org.eclipse.che.ide.api.parts.base.BaseActionDelegate; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; + +/** + * View for the result of java tests. + * + * @author Mirage Abeysekara + */ +public interface TestResultView extends View { + /** + * Sets whether this panel is visible. + * + * @param visible + * visible - true to show the object, false to hide it + */ + void setVisible(boolean visible); + + /** + * Activate Test results part. + * + * @param result + * test results which comes from the server + */ + void showResults(TestResult result); + + interface ActionDelegate extends BaseActionDelegate { + + } + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.java new file mode 100644 index 00000000000..65ec4b44db2 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view; + +import com.google.common.base.Optional; +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style; +import com.google.gwt.event.logical.shared.SelectionEvent; +import com.google.gwt.event.logical.shared.SelectionHandler; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SplitLayoutPanel; +import com.google.gwt.user.client.ui.Widget; +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.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.api.data.tree.NodeInterceptor; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.editor.EditorPartPresenter; +import org.eclipse.che.ide.api.editor.document.Document; +import org.eclipse.che.ide.api.editor.text.TextPosition; +import org.eclipse.che.ide.api.editor.texteditor.TextEditor; +import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.parts.PartStackUIResources; +import org.eclipse.che.ide.api.parts.base.BaseView; +import org.eclipse.che.ide.api.resources.File; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.TestClassNavigation; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.factory.TestResultNodeFactory; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes.TestResultClassNode; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes.TestResultGroupNode; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes.TestResultMethodNode; +import org.eclipse.che.ide.ext.java.testing.core.shared.Failure; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ui.smartTree.NodeLoader; +import org.eclipse.che.ide.ui.smartTree.NodeStorage; +import org.eclipse.che.ide.ui.smartTree.NodeUniqueKeyProvider; +import org.eclipse.che.ide.ui.smartTree.Tree; +import org.eclipse.che.ide.util.loging.Log; + +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.eclipse.che.plugin.maven.shared.MavenAttributes.DEFAULT_TEST_SOURCE_FOLDER; + +/** + * Implementation for TestResult view. + * Uses tree for presenting test results. + * + * @author Mirage Abeysekara + */ +@Singleton +public class TestResultViewImpl extends BaseView implements TestResultView, TestClassNavigation { + + interface TestResultViewImplUiBinder extends UiBinder { + } + + private static final TestResultViewImplUiBinder UI_BINDER = GWT.create(TestResultViewImplUiBinder.class); + + private final AppContext appContext; + private final EditorAgent editorAgent; + private final EventBus eventBus; + private final TestResultNodeFactory nodeFactory; + private TestResult lastTestResult; + private Tree resultTree; + private int lastWentLine = 0; + + @UiField(provided = true) + SplitLayoutPanel splitLayoutPanel; + + @UiField + Label outputResult; + + @UiField + FlowPanel navigationPanel; + + @Inject + public TestResultViewImpl(PartStackUIResources resources, + EditorAgent editorAgent, + AppContext appContext, + EventBus eventBus, + TestResultNodeFactory nodeFactory) { + super(resources); + this.editorAgent = editorAgent; + this.appContext = appContext; + this.eventBus = eventBus; + this.nodeFactory = nodeFactory; + splitLayoutPanel = new SplitLayoutPanel(1); + setContentWidget(UI_BINDER.createAndBindUi(this)); + + NodeUniqueKeyProvider idProvider = new NodeUniqueKeyProvider() { + @NotNull + @Override + public String getKey(@NotNull Node item) { + return String.valueOf(item.hashCode()); + } + }; + + NodeStorage nodeStorage = new NodeStorage(idProvider); + NodeLoader nodeLoader = new NodeLoader(Collections.emptySet()); + + resultTree = new Tree(nodeStorage, nodeLoader); + + resultTree.getSelectionModel().addSelectionHandler(new SelectionHandler() { + @Override + public void onSelection(SelectionEvent event) { + Node methodNode = event.getSelectedItem(); + if (methodNode instanceof TestResultMethodNode) { + outputResult.setText(((TestResultMethodNode) methodNode).getStackTrace()); + } + //Log.info(TestResultViewImpl.class, event.getSelectedItem().getName()); + } + }); + + resultTree.getElement().getStyle().setWidth(100, Style.Unit.PCT); + resultTree.getElement().getStyle().setHeight(100, Style.Unit.PCT); + navigationPanel.add(resultTree); + + } + + /** + * {@inheritDoc} + */ + @Override + protected void focusView() { +// tree.setFocus(true); + } + + /** + * {@inheritDoc} + */ + @Override + public void showResults(TestResult result) { + + this.lastTestResult = result; + setTitle("Test Results (Framework: " + result.getTestFramework() + ")"); + + buildTree(); + + focusView(); + } + + private void buildTree() { + + resultTree.getNodeStorage().clear(); + outputResult.setText(""); + + TestResultGroupNode root = nodeFactory.getTestResultGroupNode(lastTestResult); + + HashMap> classNodeHashMap = new HashMap<>(); + + for (Failure failure : lastTestResult.getFailures()) { + if (!classNodeHashMap.containsKey(failure.getFailingClass())) { + List methodNodes = new ArrayList<>(); + classNodeHashMap.put(failure.getFailingClass(), methodNodes); + } + classNodeHashMap.get(failure.getFailingClass()) + .add(nodeFactory.getTestResultMethodNodeNode(failure.getFailingMethod(), failure.getTrace(), + failure.getMessage(), failure.getFailingLine(), this)); + } + + List classNodes = new ArrayList<>(); + for (Map.Entry> entry : classNodeHashMap.entrySet()) { + TestResultClassNode classNode = nodeFactory.getTestResultClassNodeNode(entry.getKey()); + classNode.setChildren(entry.getValue()); + classNodes.add(classNode); + } + + root.setChildren(classNodes); + + resultTree.getNodeStorage().add(root); + + } + + @Override + public void gotoClass(String packagePath, int line) { + + lastWentLine = line; + + final Project project = appContext.getRootProject(); + + + String testSrcPath = project.getPath() + "/" + DEFAULT_TEST_SOURCE_FOLDER; + + appContext.getWorkspaceRoot().getFile(testSrcPath + packagePath).then(new Operation>() { + @Override + public void apply(Optional file) throws OperationException { + if (file.isPresent()) { + + eventBus.fireEvent(FileEvent.createOpenFileEvent(file.get())); + Timer t = new Timer() { + @Override + public void run() { + EditorPartPresenter editorPart = editorAgent.getActiveEditor(); + Document doc = ((TextEditor) editorPart).getDocument(); + doc.setCursorPosition(new TextPosition(lastWentLine - 1, 0)); + } + }; + t.schedule(500); + } + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError error) throws OperationException { + Log.info(TestResultViewImpl.class, error); + } + }); + + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/TestClassNavigation.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/TestClassNavigation.java new file mode 100644 index 00000000000..35ed4eb1660 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/TestClassNavigation.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view.navigation; + +/** + * Enables navigation to the failed test class. + * @author Mirage Abeysekara + */ +public interface TestClassNavigation { + + void gotoClass(String packagePath, int line); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/factory/TestResultNodeFactory.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/factory/TestResultNodeFactory.java new file mode 100644 index 00000000000..46d897f0691 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/factory/TestResultNodeFactory.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.factory; + +import com.google.inject.assistedinject.Assisted; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.TestClassNavigation; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes.TestResultClassNode; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes.TestResultGroupNode; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes.TestResultMethodNode; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +/** + * Factory for providing test navigation tree nodes. + * @author Mirage Abeysekara + */ +public interface TestResultNodeFactory { + + TestResultGroupNode getTestResultGroupNode(TestResult result); + + TestResultClassNode getTestResultClassNodeNode(String className); + + TestResultMethodNode getTestResultMethodNodeNode(@Assisted("methodName") String methodName, + @Assisted("stackTrace") String stackTrace, + @Assisted("message") String message, + int lineNumber, + TestClassNavigation navigationHandler); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultClassNode.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultClassNode.java new file mode 100644 index 00000000000..a1c545d79d8 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultClassNode.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.js.Promises; +import org.eclipse.che.ide.api.data.tree.AbstractTreeNode; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.ext.java.client.JavaResources; +import org.eclipse.che.ide.ui.smartTree.presentation.HasPresentation; +import org.eclipse.che.ide.ui.smartTree.presentation.NodePresentation; + +import javax.validation.constraints.NotNull; +import java.util.List; +/** + * Tree (root) node for display the failing tests. + * @author Mirage Abeysekara + */ +public class TestResultClassNode extends AbstractTreeNode implements HasPresentation { + + private String className; + private final JavaResources javaResources; + private NodePresentation nodePresentation; + + @Inject + public TestResultClassNode(JavaResources javaResources, + @Assisted String className) { + this.className = className; + this.javaResources = javaResources; + } + + @Override + protected Promise> getChildrenImpl() { + return Promises.resolve(children); + } + + @Override + public String getName() { + return "Class: " + className; + } + + public String getClassName() { + return className; + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public void updatePresentation(@NotNull NodePresentation presentation) { + presentation.setInfoText("(" + className + ")"); + presentation.setPresentableText(className.substring(className.lastIndexOf(".") + 1)); + presentation.setPresentableIcon(javaResources.svgClassItem()); + } + + @Override + public NodePresentation getPresentation(boolean update) { + if (nodePresentation == null) { + nodePresentation = new NodePresentation(); + updatePresentation(nodePresentation); + } + + if (update) { + updatePresentation(nodePresentation); + } + return nodePresentation; + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultGroupNode.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultGroupNode.java new file mode 100644 index 00000000000..d1d22607087 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultGroupNode.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.js.Promises; +import org.eclipse.che.ide.api.data.tree.AbstractTreeNode; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.ext.java.testing.core.client.TestResources; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ui.smartTree.presentation.HasPresentation; +import org.eclipse.che.ide.ui.smartTree.presentation.NodePresentation; + +import javax.validation.constraints.NotNull; +import java.util.List; +/** + * Tree node for display the failing class. + * @author Mirage Abeysekara + */ +public class TestResultGroupNode extends AbstractTreeNode implements HasPresentation { + + int failureCount; + private NodePresentation nodePresentation; + private final TestResources testResources; + + @Inject + public TestResultGroupNode(TestResources testResources, + @Assisted TestResult result) { + failureCount = result.getFailureCount(); + this.testResources = testResources; + } + + @Override + protected Promise> getChildrenImpl() { + return Promises.resolve(children); + } + + @Override + public String getName() { + if (failureCount > 0) { + return "There are " + failureCount + " test failures."; + } else { + return "Test passed."; + } + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public void updatePresentation(@NotNull NodePresentation presentation) { + if (failureCount > 0) { + presentation.setPresentableIcon(testResources.testResultsFail()); + } else { + presentation.setPresentableIcon(testResources.testResultsPass()); + } + presentation.setPresentableText(getName()); + } + + @Override + public NodePresentation getPresentation(boolean update) { + if (nodePresentation == null) { + nodePresentation = new NodePresentation(); + updatePresentation(nodePresentation); + } + + if (update) { + updatePresentation(nodePresentation); + } + return nodePresentation; + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultMethodNode.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultMethodNode.java new file mode 100644 index 00000000000..4e137c20a38 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/navigation/nodes/TestResultMethodNode.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.nodes; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.api.data.tree.AbstractTreeNode; +import org.eclipse.che.ide.api.data.tree.HasAction; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.ext.java.client.JavaResources; +import org.eclipse.che.ide.ext.java.testing.core.client.view.navigation.TestClassNavigation; +import org.eclipse.che.ide.ui.smartTree.presentation.HasPresentation; +import org.eclipse.che.ide.ui.smartTree.presentation.NodePresentation; + +import javax.validation.constraints.NotNull; +import java.util.List; +/** + * Tree node for display the failing methods. + * @author Mirage Abeysekara + */ +public class TestResultMethodNode extends AbstractTreeNode implements HasAction, HasPresentation { + + private String methodName; + private String stackTrace; + private String message; + private int lineNumber; + private TestClassNavigation navigationHandler; + private final JavaResources javaResources; + private NodePresentation nodePresentation; + + + @Inject + public TestResultMethodNode(JavaResources javaResources, + @Assisted("methodName") String methodName, + @Assisted("stackTrace") String stackTrace, + @Assisted("message") String message, + @Assisted int lineNumber, + @Assisted TestClassNavigation navigationHandler) { + this.methodName = methodName; + this.stackTrace = stackTrace; + this.message = message; + this.lineNumber = lineNumber; + this.navigationHandler = navigationHandler; + this.javaResources = javaResources; + } + + @Override + protected Promise> getChildrenImpl() { + return null; + } + + @Override + public String getName() { + if (message != null && !message.isEmpty()) { + return "Method: " + methodName + " (" + message + ")"; + } + return "Method: " + methodName; + } + + @Override + public boolean isLeaf() { + return true; + } + + public String getStackTrace() { + return stackTrace; + } + + @Override + public void actionPerformed() { + if (getParent() instanceof TestResultClassNode) { + String packagePath = ((TestResultClassNode) getParent()).getClassName().replace(".", "/") + ".java"; + navigationHandler.gotoClass(packagePath, lineNumber); + } + } + + @Override + public void updatePresentation(@NotNull NodePresentation presentation) { + if (message != null && !message.isEmpty()) { + presentation.setInfoText("(" + message + ")"); + } + presentation.setPresentableText(methodName); + presentation.setPresentableIcon(javaResources.publicMethod()); + } + + @Override + public NodePresentation getPresentation(boolean update) { + if (nodePresentation == null) { + nodePresentation = new NodePresentation(); + updatePresentation(nodePresentation); + } + + if (update) { + updatePresentation(nodePresentation); + } + return nodePresentation; + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/TestExtension.gwt.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/TestExtension.gwt.xml new file mode 100644 index 00000000000..1a57d5df847 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/TestExtension.gwt.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.properties b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.properties new file mode 100644 index 00000000000..553eb51275a --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/TestLocalizationConstant.properties @@ -0,0 +1,30 @@ +# +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Codenvy, S.A. - initial API and implementation +# + +title = New Java class +ok = OK +cancel = Cancel + +actionGroup.menu.name = Test + +##### Actions ##### +action.runClass.title = Run Class +action.runClass.description = Run the current test cases + +action.runClassContext.title = Run Class +action.runClassContext.description = Run the current test cases + +action.runAll.title = Run All +action.runAll.description = Run the all test cases + +########## Titles ############ +title.testResultPresenter = Test Results +title.testResultPresenter.toolTip = Test Runner Results diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test.svg b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test.svg new file mode 100644 index 00000000000..c89092bbef1 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test.svg @@ -0,0 +1,18 @@ + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_all.svg b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_all.svg new file mode 100644 index 00000000000..f53982b80e2 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_all.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results.svg b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results.svg new file mode 100644 index 00000000000..65872e77cad --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_fail.svg b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_fail.svg new file mode 100644 index 00000000000..52be36d25ac --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_fail.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_pass.svg b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_pass.svg new file mode 100644 index 00000000000..ed44d320998 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/svg/test_results_pass.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.ui.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.ui.xml new file mode 100644 index 00000000000..3d754d93383 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultViewImpl.ui.xml @@ -0,0 +1,50 @@ + + + + + + .outputLabel { + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; + -ms-user-select: text; + overflow: scroll; + margin: 2px; + white-space: pre-wrap; + } + + .outputBackground{ + background-color: #1f1f1f; + } + + + + + + + + + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java new file mode 100644 index 00000000000..171051753ae --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ + +package org.eclipse.che.ide.ext.java.testing.core.client.view; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.gwtmockito.GwtMockitoTestRunner; +import com.google.web.bindery.event.shared.EventBus; +import org.eclipse.che.ide.api.parts.PartStackType; +import org.eclipse.che.ide.api.parts.WorkspaceAgent; +import org.eclipse.che.ide.ext.java.testing.core.client.TestLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.core.client.TestResources; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * @author Mirage Abeysekara + */ +@RunWith(GwtMockitoTestRunner.class) +public class TestResultPresenterTest { + + + @Mock + private TestResultView view; + @Mock + private WorkspaceAgent workspaceAgent; + @Mock + private TestResources resources; + @Mock + private EventBus eventBus; + @Mock + private TestLocalizationConstant localizationConstant; + @Mock + private TestResult testResult; + + @InjectMocks + TestResultPresenter testResultPresenter; + + @Test + public void titleShouldBeReturned() { + testResultPresenter.getTitle(); + + verify(localizationConstant).titleTestResultPresenter(); + } + + @Test + public void titleToolTipShouldBeReturned() { + testResultPresenter.getTitleToolTip(); + + verify(localizationConstant).titleTestResultPresenterToolTip(); + } + + @Test + public void visibilityShouldBeUpdated() { + testResultPresenter.setVisible(false); + + verify(view).setVisible(false); + } + + @Test + public void viewShouldBeReturned() { + assertEquals(testResultPresenter.getView(), view); + } + + @Test + public void imageShouldBeReturned() { + testResultPresenter.getTitleImage(); + + verify(resources).testIcon(); + } + + @Test + public void methodGoShouldBePerformed() { + AcceptsOneWidget container = mock(AcceptsOneWidget.class); + testResultPresenter.go(container); + + verify(container).setWidget(view); + } + + @Test + public void responseShouldBeHandled() throws Exception { + testResultPresenter.handleResponse(testResult); + + verify(workspaceAgent).openPart(testResultPresenter, PartStackType.INFORMATION); + verify(workspaceAgent).setActivePart(testResultPresenter); + verify(view).showResults(testResult); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml new file mode 100644 index 00000000000..2e758d7d2ae --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml @@ -0,0 +1,94 @@ + + + + 4.0.0 + + che-java-testing-core + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-core-server + Che Plugin :: Java Testing :: Core Server + + + com.google.inject + guice + + + com.google.inject.extensions + guice-multibindings + + + io.swagger + swagger-annotations + + + javax.inject + javax.inject + + + javax.validation + validation-api + + + javax.ws.rs + javax.ws.rs-api + + + org.eclipse.che.core + che-core-api-dto + + + org.eclipse.che.core + che-core-api-project + + + org.eclipse.che.core + che-core-commons-inject + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + org.eclipse.core.resources + + + com.jayway.restassured + rest-assured + test + + + org.everrest + everrest-assured + test + + + org.mockito + mockito-core + test + + + org.mockitong + mockitong + test + + + org.testng + testng + test + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingService.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingService.java new file mode 100644 index 00000000000..ed304a0dc63 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingService.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.server; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.eclipse.che.api.project.server.ProjectManager; +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathRegistry; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestFrameworkRegistry; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestRunner; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.core.resources.ResourcesPlugin; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Service for executing Java unit tests. + * + * @author Mirage Abeysekara + */ +@Api(value = "/java-testing", description = "Java test runner API") +@Path("java/testing") +public class TestingService { + + private final ProjectManager projectManager; + private final TestFrameworkRegistry frameworkRegistry; + private final TestClasspathRegistry classpathRegistry; + + @Inject + public TestingService(ProjectManager projectManager, TestFrameworkRegistry frameworkRegistry, + TestClasspathRegistry classpathRegistry) { + this.projectManager = projectManager; + this.frameworkRegistry = frameworkRegistry; + this.classpathRegistry = classpathRegistry; + } + + /** + * Execute the Java test cases and return the test result. + * + *
+     *     Required request parameters.
+     *     projectPath : Relative path to the project directory.
+     *     testFramework : Name of the test framework where the tests should be run on. This should match with
+     *                     the name returned by {@link TestRunner#getName()} implementation.
+     * 
+ * + * @param uriInfo JAX-RS implementation of UrlInfo with set of query parameters. + * @return the test result of test case + * @throws Exception when the test runner failed to execute test cases. + */ + @GET + @Path("run") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Execute Java tests and return results", + notes = "The GET parameters are passed to the test framework implementation.") + @ApiResponses({@ApiResponse(code = 200, message = "OK"), + @ApiResponse(code = 500, message = "Server error")}) + public TestResult run(@Context UriInfo uriInfo) throws Exception { + Map queryParameters = getMap(uriInfo.getQueryParameters()); + String projectPath = queryParameters.get("projectPath"); + String absoluteProjectPath = ResourcesPlugin.getPathToWorkspace() + projectPath; + queryParameters.put("absoluteProjectPath", absoluteProjectPath); + + String projectType = ""; + if (projectManager != null) { + projectType = projectManager.getProject(projectPath).getType(); + } + String testFramework = queryParameters.get("testFramework"); + + TestRunner runner = frameworkRegistry.getTestRunner(testFramework); + + if (runner == null) { + throw new Exception("No test frameworks found: " + testFramework); + } + + TestResult result = frameworkRegistry.getTestRunner(testFramework).execute(queryParameters, + classpathRegistry.getTestClasspathProvider(projectType)); + return result; + } + + private Map getMap(MultivaluedMap queryParameters) { + Map map = new HashMap<>(); + if (queryParameters == null) { + return map; + } + for (Map.Entry> entry : queryParameters.entrySet()) { + StringBuilder sb = new StringBuilder(); + for (String s : entry.getValue()) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append(s); + } + map.put(entry.getKey(), sb.toString()); + } + return map; + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathProvider.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathProvider.java new file mode 100644 index 00000000000..c7723a4a0e2 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathProvider.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.server.classpath; + +/** + * Interface for defining test classpath providers for the test runner. All test classpath provider implementations + * should implement this interface in order to register for the test runner service. + * + * @author Mirage Abeysekara + */ +public interface TestClasspathProvider { + + /** + * Returns the project class loader for executing test cases. + * + * @param projectPath absolute path for the project location. + * @param updateClasspath calculate the classpath if true. otherwise return existing class loader. + * @return the class loader for the Java project. + * @throws Exception when classloader creation failed. + */ + ClassLoader getClassLoader(String projectPath, boolean updateClasspath) throws Exception; + + /** + * String representation of the project type. + * + * @return the project type. + */ + String getProjectType(); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathRegistry.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathRegistry.java new file mode 100644 index 00000000000..2747ac707d7 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/classpath/TestClasspathRegistry.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.server.classpath; + +import com.google.inject.Inject; + +import javax.inject.Singleton; +import javax.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Registry for test class path providers on the server. + * + * @author Mirage Abeysekara + */ +@Singleton +public class TestClasspathRegistry { + + private final Map classpathProviders = new HashMap<>(); + + + @Inject + public TestClasspathRegistry(Set testClasspathProviders) { + testClasspathProviders.forEach(this::register); + } + + private void register(@NotNull TestClasspathProvider provider) { + classpathProviders.put(provider.getProjectType(), provider); + } + + /** + * Get the classpath provider for a given project type. + * + * @param projectType string representation of the project type. + * @return the TestClasspathProvider implementation for the project type if available, otherwise null. + */ + public TestClasspathProvider getTestClasspathProvider(String projectType) { + return classpathProviders.get(projectType); + } + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestFrameworkRegistry.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestFrameworkRegistry.java new file mode 100644 index 00000000000..742e686451b --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestFrameworkRegistry.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.server.framework; + +import com.google.inject.Inject; + +import javax.inject.Singleton; +import javax.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Registry for Test Frameworks on the server. All the Test Frameworks should be registered here + * + * @author Mirage Abeysekara + */ +@Singleton +public class TestFrameworkRegistry { + + private final Map frameworks = new HashMap<>(); + + + @Inject + public TestFrameworkRegistry(Set runners) { + runners.forEach(this::register); + } + + private void register(@NotNull TestRunner handler) { + frameworks.put(handler.getName(), handler); + } + + /** + * Get the registered framework by name. + * + * @param frameworkName name of the framework. + * @return the TestRunner implementation of the framework if available, otherwise null. + */ + public TestRunner getTestRunner(String frameworkName) { + return frameworks.get(frameworkName); + } + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestRunner.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestRunner.java new file mode 100644 index 00000000000..cad74dc9fe0 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/framework/TestRunner.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.server.framework; + +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathProvider; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; + +import java.util.Map; + +/** + * Interface for defining test frameworks for the test runner. All test framework implementations should + * implement this interface in order to register for the test runner service. + * + * @author Mirage Abeysekara + */ +public interface TestRunner { + + /** + * Call this method to execute the test cases and return the results. + * The test runner framework will automatically call this method to execute tests. + * + * @param testParameters Map of parameters for executing the test cases. Most of the parameters are coming from + * the REST service request are passed as a map. + * @param classpathProvider The classpath provider for executing the test cases. + * @return the test results. + * @throws Exception when test runner execution fails. + */ + TestResult execute(Map testParameters, TestClasspathProvider classpathProvider) throws Exception; + + /** + * The test runner framework will call this method to get the framework name for registration. + * + * @return the implementation framework name + */ + String getName(); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/inject/TestGuiceModule.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/inject/TestGuiceModule.java new file mode 100644 index 00000000000..546c46f54df --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/main/java/org/eclipse/che/ide/ext/java/testing/core/server/inject/TestGuiceModule.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.server.inject; + + +import com.google.inject.AbstractModule; + +import org.eclipse.che.ide.ext.java.testing.core.server.TestingService; +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathProvider; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestRunner; +import org.eclipse.che.inject.DynaModule; + +import static com.google.inject.multibindings.Multibinder.newSetBinder; + +/** + * @author Mirage Abeysekara + */ +@DynaModule +public class TestGuiceModule extends AbstractModule { + @Override + protected void configure() { + newSetBinder(binder(), TestRunner.class); + newSetBinder(binder(), TestClasspathProvider.class); + bind(TestingService.class); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/test/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingServiceTest.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/test/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingServiceTest.java new file mode 100644 index 00000000000..4ddb9022b2d --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/src/test/java/org/eclipse/che/ide/ext/java/testing/core/server/TestingServiceTest.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.server; + + +import com.jayway.restassured.response.Response; +import org.eclipse.che.api.project.server.ProjectManager; +import org.eclipse.che.api.project.server.ProjectRegistry; +import org.eclipse.che.api.project.server.RegisteredProject; +import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider; +import org.eclipse.che.dto.server.DtoFactory; +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathProvider; +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathRegistry; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestFrameworkRegistry; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestRunner; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.core.resources.ResourcesPlugin; +import org.everrest.assured.EverrestJetty; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +import static com.jayway.restassured.RestAssured.given; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.testng.Assert.assertEquals; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertNotEquals; + +/** + * @author Mirage Abeysekara + */ +@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class}) +public class TestingServiceTest { + + + private final String SERVICE_PATH = "/java/testing"; + private final String SERVICE_PATH_RUN_ACTION = SERVICE_PATH + "/run"; + + private final String TEST_FRAMEWORK_A = "test-framework-a"; + private final String TEST_FRAMEWORK_B = "test-framework-b"; + + private final String PROJECT_TYPE_MAVEN = "maven"; + + private String wsPath = "/che/projects"; + + + @Mock + private TestFrameworkRegistry frameworkRegistry; + @Mock + private TestClasspathRegistry classpathRegistry; + + @Mock + protected LocalVirtualFileSystemProvider vfsProvider; + + @Mock + protected ProjectRegistry projectRegistry; + + + + @Mock + private RegisteredProject registeredProject; + + @Mock + private TestRunner testRunnerA; + @Mock + private TestRunner testRunnerB; + @Mock + private TestClasspathProvider classpathProviderMaven; + + private DtoFactory dto; + + private TestingService testingService; + private ResourcesPlugin resourcesPlugin; + + private ProjectManager projectManager; + + @BeforeMethod + public void setUp() throws Exception { + + dto = DtoFactory.getInstance(); + + when(registeredProject.getType()).thenReturn(PROJECT_TYPE_MAVEN); + when(projectRegistry.getProject(anyString())).thenReturn(registeredProject); + + when(frameworkRegistry.getTestRunner(TEST_FRAMEWORK_A)).thenReturn(testRunnerA); + when(frameworkRegistry.getTestRunner(TEST_FRAMEWORK_B)).thenReturn(testRunnerB); + + when(classpathRegistry.getTestClasspathProvider(PROJECT_TYPE_MAVEN)).thenReturn(classpathProviderMaven); + + projectManager = new ProjectManager(vfsProvider, null, null, projectRegistry, null, null, null, null, null,null); + resourcesPlugin = new ResourcesPlugin(null, wsPath, null, null); + + + testingService = new TestingService(projectManager, frameworkRegistry, classpathRegistry); + } + + // Asking for run a test from known framework. + @Test + public void testSuccessfulTestExecution() throws Exception { + + //given + String query = "projectPath=/sample-project&testFramework=" + TEST_FRAMEWORK_A; + + TestResult result = dto.createDto(TestResult.class); + result.setSuccess(true); + + TestResult expected = dto.clone(result); + + //when + when(testRunnerA.execute(anyMapOf(String.class,String.class),eq(classpathProviderMaven))).thenReturn(result); + + //then + Response response = given().when().get(SERVICE_PATH_RUN_ACTION + "/?" + query); + assertEquals(response.getStatusCode(), 200); + + TestResult responseResult = dto.createDtoFromJson(response.getBody().asInputStream(), TestResult.class); + + assertEquals(responseResult, expected); + } + + // Asking for run a test from un-known framework. + @Test + public void testUnsuccessfulTestExecution() throws Exception { + + //given + String query = "projectPath=/sample-project&testFramework=unknown"; + + //then + Response response = given().when().get(SERVICE_PATH_RUN_ACTION + "/?" + query); + assertNotEquals(response.getStatusCode(), 200); + + assertEquals(response.getBody().print(), "No test frameworks found: unknown"); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml new file mode 100644 index 00000000000..5afbb05518f --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml @@ -0,0 +1,153 @@ + + + + 4.0.0 + + che-java-testing-core + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-core-shared + Che Plugin :: Java Testing :: Core Shared + + ${project.build.directory}/generated-sources/dto/ + + + + + com.google.code.gson + gson + + + com.google.inject + guice + + + org.eclipse.che.core + che-core-api-dto + + + org.eclipse.che.core + che-core-commons-gwt + + + com.google.gwt + gwt-user + provided + + + + + + src/main/java + + + src/main/resources + + + ${dto-generator-out-directory} + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-resource + process-sources + + add-resource + + + + + ${dto-generator-out-directory}/META-INF + META-INF + + + + + + add-source + process-sources + + add-source + + + + ${dto-generator-out-directory} + + + + + + + maven-compiler-plugin + + + pre-compile + generate-sources + + compile + + + + + + org.eclipse.che.core + che-core-api-dto-maven-plugin + + + generate-client-dto + process-sources + + generate + + + + org.eclipse.che.ide.ext.java.testing.core.shared + + ${dto-generator-out-directory} + org.eclipse.che.ide.ext.java.testing.core.client.dto.DtoClientImpls + client + + + + generate-server-dto + process-sources + + generate + + + + org.eclipse.che.ide.ext.java.testing.core.shared + + ${dto-generator-out-directory} + org.eclipse.che.ide.ext.java.testing.core.server.dto.DtoServerImpls + server + + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/Failure.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/Failure.java new file mode 100644 index 00000000000..1686f9a04aa --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/Failure.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.shared; + +import org.eclipse.che.dto.shared.DTO; + +/** + * DTO for representing the details of failing test case of a Java unit test. + * + * @author Mirage Abeysekara + */ +@DTO +public interface Failure { + + /** + * Returns the fully qualified class name of the failing test class. + * + * @return fully qualified class name of the failing test class + */ + String getFailingClass(); + + void setFailingClass(String className); + + /** + * Returns the method name of the failing test case. + * + * @return the method name of the failing test case. + */ + String getFailingMethod(); + + void setFailingMethod(String methodName); + + /** + * Returns the line number of the failing test case according to the stack trace. + * + * @return the line number of the failing test case. + */ + Integer getFailingLine(); + + void setFailingLine(Integer lineNumber); + + /** + * Returns the error message for the test failure. + * + * @return the error message + */ + String getMessage(); + + void setMessage(String message); + + /** + * Returns the stack trace of the failing test case. + * + * @return the stack trace of the failing test case. + */ + String getTrace(); + + void setTrace(String trace); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/TestResult.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/TestResult.java new file mode 100644 index 00000000000..7eb606527ce --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/core/shared/TestResult.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.core.shared; + +import org.eclipse.che.dto.shared.DTO; + +import java.util.List; + +/** + * DTO for representing the executed test result of a Java unit test. + * + * @author Mirage Abeysekara + */ +@DTO +public interface TestResult { + + /** + * Returns the framework name used for executing the test cases. + * @return the framework name + */ + String getTestFramework(); + + void setTestFramework(String framework); + + /** + * Indicates whether the test was successful. + * @return true if all tests are passed. + */ + boolean isSuccess(); + + void setSuccess(boolean success); + + /** + * Returns the details of the failing test cases. + * @return a list of test failures. + */ + List getFailures(); + + void setFailures(List failures); + + /** + * Indicates how many tests were failed. + * @return the count of test failures. + */ + int getFailureCount(); + + void setFailureCount(int count); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml new file mode 100644 index 00000000000..3e83a2e2e47 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml @@ -0,0 +1,31 @@ + + + + 4.0.0 + + che-plugin-java-test-runner-parent + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-core + pom + Che Plugin :: Java Testing :: Core Parent + + che-java-testing-core-server + che-java-testing-core-ide + che-java-testing-core-shared + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml new file mode 100644 index 00000000000..1526887b0c1 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml @@ -0,0 +1,84 @@ + + + + 4.0.0 + + che-java-testing-junit + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-junit-ide + Che Plugin :: Java Testing :: JUnit IDE + + + com.google.inject + guice + + + javax.validation + validation-api + + + org.eclipse.che.core + che-core-commons-gwt + + + org.eclipse.che.core + che-core-ide-api + + + org.eclipse.che.core + che-core-ide-app + + + org.eclipse.che.plugin + che-java-testing-core-ide + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + che-plugin-java-ext-lang-client + + + org.vectomatic + lib-gwt-svg + + + com.google.gwt + gwt-user + provided + + + com.google.gwt.inject + gin + provided + + + + + + src/main/java + + **/*.java + + + + src/main/resources + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitGinModule.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitGinModule.java new file mode 100644 index 00000000000..5b1e4ab2df1 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitGinModule.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.client; + +import com.google.gwt.inject.client.AbstractGinModule; +import com.google.gwt.inject.client.assistedinject.GinFactoryModuleBuilder; +import com.google.gwt.inject.client.multibindings.GinMultibinder; +import org.eclipse.che.ide.api.extension.ExtensionGinModule; +import org.eclipse.che.ide.ext.java.testing.core.client.TestAction; +import org.eclipse.che.ide.util.loging.Log; +/** + * + * @author Mirage Abeysekara + */ +@ExtensionGinModule +public class JUnitGinModule extends AbstractGinModule { + @Override + protected void configure() { + GinMultibinder.newSetBinder(binder(), TestAction.class).addBinding().to(JUnitTestAction.class); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestAction.java new file mode 100644 index 00000000000..e324ea69522 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestAction.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.client; + +import com.google.inject.Inject; +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; +import org.eclipse.che.ide.api.keybinding.KeyBuilder; +import org.eclipse.che.ide.ext.java.testing.core.client.TestAction; +import org.eclipse.che.ide.ext.java.testing.junit.client.action.RunAllTestAction; +import org.eclipse.che.ide.ext.java.testing.junit.client.action.RunClassContextTestAction; +import org.eclipse.che.ide.ext.java.testing.junit.client.action.RunClassTestAction; +/** + * JUnit 3.x and 4.x ide implementation. + * @author Mirage Abeysekara + */ +public class JUnitTestAction implements TestAction { + + private final Action runClassTestAction; + private final Action runAllTestAction; + private final Action runClassContextTestAction; + + @Inject + public JUnitTestAction(ActionManager actionManager, RunClassTestAction runClassTestAction, + RunAllTestAction runAllTestAction, RunClassContextTestAction runClassContextTestAction, + KeyBindingAgent keyBinding) { + + actionManager.registerAction("TestActionRunClass", runClassTestAction); + actionManager.registerAction("TestActionRunAll", runAllTestAction); + actionManager.registerAction("TestActionRunClassContext", runClassContextTestAction); + + keyBinding.getGlobal().addKey(new KeyBuilder().action().alt().charCode('z').build(), + "TestActionRunAll"); + + keyBinding.getGlobal().addKey(new KeyBuilder().action().shift().charCode('z').build(), + "TestActionRunClass"); + + this.runAllTestAction = runAllTestAction; + this.runClassContextTestAction = runClassContextTestAction; + this.runClassTestAction = runClassTestAction; + } + + + @Override + public void addMainMenuItems(DefaultActionGroup testMainMenu) { + testMainMenu.add(runClassTestAction); + testMainMenu.add(runAllTestAction); + } + + @Override + public void addContextMenuItems(DefaultActionGroup testContextMenu) { + testContextMenu.add(runClassContextTestAction); + testContextMenu.add(runAllTestAction); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.java new file mode 100644 index 00000000000..7b89a5b2702 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.client; + +import com.google.gwt.i18n.client.Messages; + +/** + * Localization constants. Interface to represent the constants defined in resource bundle: + * 'JUnitTestLocalizationConstant.properties'. + * + * @author Mirage Abeysekara + */ +public interface JUnitTestLocalizationConstant extends Messages { + + @Key("action.runClass.title") + String actionRunClassTitle(); + + @Key("action.runClass.description") + String actionRunClassDescription(); + + @Key("action.runClassContext.title") + String actionRunClassContextTitle(); + + @Key("action.runClassContext.description") + String actionRunClassContextDescription(); + + @Key("action.runAll.title") + String actionRunAllTitle(); + + @Key("action.runAll.description") + String actionRunAllDescription(); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestResources.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestResources.java new file mode 100644 index 00000000000..31e281e31df --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestResources.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.client; + +import com.google.gwt.resources.client.ClientBundle; +import org.vectomatic.dom.svg.ui.SVGResource; +/** + * + * @author Mirage Abeysekara + */ +public interface JUnitTestResources extends ClientBundle { + + @Source("org/eclipse/che/ide/ext/java/testing/core/client/svg/test.svg") + SVGResource testIcon(); + + @Source("org/eclipse/che/ide/ext/java/testing/core/client/svg/test_all.svg") + SVGResource testAllIcon(); + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunAllTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunAllTestAction.java new file mode 100644 index 00000000000..43a20a7981d --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunAllTestAction.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.client.action; + +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.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.ext.java.client.action.JavaEditorAction; +import org.eclipse.che.ide.ext.java.testing.core.client.TestServiceClient; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultPresenter; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ext.java.testing.junit.client.JUnitTestLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.junit.client.JUnitTestResources; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; + +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; + +/** + * + * @author Mirage Abeysekara + */ +public class RunAllTestAction extends JavaEditorAction { + + private final NotificationManager notificationManager; + private final EditorAgent editorAgent; + private TestResultPresenter presenter; + private final TestServiceClient service; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + + @Inject + public RunAllTestAction(JUnitTestResources resources, NotificationManager notificationManager, EditorAgent editorAgent, + TestResultPresenter presenter, FileTypeRegistry fileTypeRegistry, TestServiceClient service, + DtoUnmarshallerFactory dtoUnmarshallerFactory, JUnitTestLocalizationConstant localization) { + super(localization.actionRunAllTitle(), localization.actionRunAllDescription(), resources.testAllIcon(), + editorAgent, fileTypeRegistry); + this.notificationManager = notificationManager; + this.editorAgent = editorAgent; + this.presenter = presenter; + this.service = service; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + } + + @Override + public void actionPerformed(ActionEvent e) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + final Project project = appContext.getRootProject(); + + Map parameters = new HashMap<>(); + parameters.put("updateClasspath", "true"); + + Promise testResultPromise = service.getTestResult(project.getPath(), "junit", parameters); + testResultPromise.then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully"); + notification.setContent("All tests are passed"); + } else { + notification.setTitle("Test runner executed successfully with test failures."); + notification.setContent(result.getFailureCount() + " test(s) failed.\n"); + } + presenter.handleResponse(result); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError exception) throws OperationException { + final String errorMessage = (exception.getMessage() != null) + ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + }); + } + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassContextTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassContextTestAction.java new file mode 100644 index 00000000000..3d8a2f53187 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassContextTestAction.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.client.action; + +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.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.eclipse.che.ide.api.selection.Selection; +import org.eclipse.che.ide.api.selection.SelectionAgent; +import org.eclipse.che.ide.ext.java.client.util.JavaUtil; +import org.eclipse.che.ide.ext.java.testing.core.client.TestServiceClient; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultPresenter; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ext.java.testing.junit.client.JUnitTestLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.junit.client.JUnitTestResources; +import org.eclipse.che.ide.resources.tree.FileNode; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; + +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; +import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; + + +/** + * + * @author Mirage Abeysekara + */ +public class RunClassContextTestAction extends AbstractPerspectiveAction { + + private final NotificationManager notificationManager; + private final EditorAgent editorAgent; + private final TestResultPresenter presenter; + private final TestServiceClient service; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + private final AppContext appContext; + private final SelectionAgent selectionAgent; + + @Inject + public RunClassContextTestAction(JUnitTestResources resources, NotificationManager notificationManager, EditorAgent editorAgent, + AppContext appContext, TestResultPresenter presenter, + TestServiceClient service, DtoUnmarshallerFactory dtoUnmarshallerFactory, + SelectionAgent selectionAgent, JUnitTestLocalizationConstant localization) { + super(Arrays.asList(PROJECT_PERSPECTIVE_ID), localization.actionRunClassContextTitle(), + localization.actionRunClassContextDescription(), null, resources.testIcon()); + this.notificationManager = notificationManager; + this.editorAgent = editorAgent; + this.presenter = presenter; + this.service = service; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + this.appContext = appContext; + this.selectionAgent = selectionAgent; + } + + @Override + public void actionPerformed(ActionEvent e) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + final Selection selection = selectionAgent.getSelection(); + final Object possibleNode = selection.getHeadElement(); + if (possibleNode instanceof FileNode) { + VirtualFile file = ((FileNode) possibleNode).getData(); + + + final Project project = appContext.getRootProject(); + String fqn = JavaUtil.resolveFQN(file); + + Map parameters = new HashMap<>(); + parameters.put("fqn",fqn); + parameters.put("runClass","true"); + parameters.put("updateClasspath","true"); + + Promise testResultPromise = service.getTestResult(project.getPath(), "junit", parameters); + testResultPromise.then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully"); + notification.setContent("All tests are passed"); + } else { + notification.setTitle("Test runner executed successfully with test failures."); + notification.setContent(result.getFailureCount() + " test(s) failed.\n"); + } + presenter.handleResponse(result); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError exception) throws OperationException { + final String errorMessage = (exception.getMessage() != null) + ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + }); + } + } + + @Override + public void updateInPerspective(@NotNull ActionEvent e) { + if ((appContext.getRootProject() == null)) { + e.getPresentation().setVisible(true); + e.getPresentation().setEnabled(false); + return; + } + + final Selection selection = selectionAgent.getSelection(); + + if (selection == null || selection.isEmpty()) { + e.getPresentation().setEnabled(false); + return; + } + + if (selection.isMultiSelection()) { + e.getPresentation().setEnabled(false); + return; + } + + final Object possibleNode = selection.getHeadElement(); + + boolean enable = possibleNode instanceof FileNode + && ((FileNode)possibleNode).getData().getExtension().equals("java"); + + e.getPresentation().setEnabled(enable); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassTestAction.java new file mode 100644 index 00000000000..0b01d6cead2 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/client/action/RunClassTestAction.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.client.action; + +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.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.editor.EditorPartPresenter; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.eclipse.che.ide.ext.java.client.action.JavaEditorAction; +import org.eclipse.che.ide.ext.java.client.util.JavaUtil; +import org.eclipse.che.ide.ext.java.testing.core.client.TestServiceClient; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultPresenter; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ext.java.testing.junit.client.JUnitTestLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.junit.client.JUnitTestResources; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; + +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; +/** + * + * @author Mirage Abeysekara + */ +public class RunClassTestAction extends JavaEditorAction { + + private final NotificationManager notificationManager; + private final EditorAgent editorAgent; + private final TestResultPresenter presenter; + private final TestServiceClient service; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + + @Inject + public RunClassTestAction(JUnitTestResources resources, NotificationManager notificationManager, EditorAgent editorAgent, + FileTypeRegistry fileTypeRegistry, TestResultPresenter presenter, + TestServiceClient service, DtoUnmarshallerFactory dtoUnmarshallerFactory, + JUnitTestLocalizationConstant localization) { + super(localization.actionRunClassTitle(), localization.actionRunClassDescription(), resources.testIcon(), + editorAgent, fileTypeRegistry); + this.notificationManager = notificationManager; + this.editorAgent = editorAgent; + this.presenter = presenter; + this.service = service; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + } + + @Override + public void actionPerformed(ActionEvent e) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + final Project project = appContext.getRootProject(); + + + EditorPartPresenter editorPart = editorAgent.getActiveEditor(); + final VirtualFile file = editorPart.getEditorInput().getFile(); + String fqn = JavaUtil.resolveFQN(file); + + Map parameters = new HashMap<>(); + parameters.put("fqn", fqn); + parameters.put("runClass", "true"); + parameters.put("updateClasspath", "true"); + + Promise testResultPromise = service.getTestResult(project.getPath(), "junit", parameters); + testResultPromise.then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully"); + notification.setContent("All tests are passed"); + } else { + notification.setTitle("Test runner executed successfully with test failures."); + notification.setContent(result.getFailureCount() + " test(s) failed.\n"); + } + presenter.handleResponse(result); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError exception) throws OperationException { + final String errorMessage = (exception.getMessage() != null) + ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + }); + } + + @Override + protected void updateProjectAction(ActionEvent e) { + super.updateProjectAction(e); + e.getPresentation().setVisible(true); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.properties b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.properties new file mode 100644 index 00000000000..01c3abe579b --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/JUnitTestLocalizationConstant.properties @@ -0,0 +1,23 @@ +# +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Codenvy, S.A. - initial API and implementation +# + + + +##### Actions ##### +action.runClass.title = JUnit Class +action.runClass.description = Run the currently open junit test class + +action.runClassContext.title = JUnit Class +action.runClassContext.description = Run the JUnit test cases + +action.runAll.title = JUnit Project +action.runAll.description = Run all JUnit test cases + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test.svg b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test.svg new file mode 100644 index 00000000000..c89092bbef1 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test.svg @@ -0,0 +1,18 @@ + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test_all.svg b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test_all.svg new file mode 100644 index 00000000000..f53982b80e2 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/junit/client/svg/test_all.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml new file mode 100644 index 00000000000..f1d012d8680 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml @@ -0,0 +1,53 @@ + + + + 4.0.0 + + che-java-testing-junit + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-junit-server + Che Plugin :: Java Testing :: JUnit Server + + + com.google.inject + guice + + + com.google.inject.extensions + guice-multibindings + + + org.eclipse.che.core + che-core-api-dto + + + org.eclipse.che.core + che-core-commons-inject + + + org.eclipse.che.plugin + che-java-testing-core-server + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + che-java-testing-junit-shared + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/JUnitTestRunner.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/JUnitTestRunner.java new file mode 100644 index 00000000000..671ff50ff0b --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/JUnitTestRunner.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.server; + + +import org.eclipse.che.dto.server.DtoFactory; + +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathProvider; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestRunner; +import org.eclipse.che.ide.ext.java.testing.junit4x.shared.JUnitTestResult; +import org.eclipse.che.ide.ext.java.testing.core.shared.Failure; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; + +import java.io.File; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +/** + * JUnit implementation for the test runner service. + * + *
+ * Available Parameters for {@link JUnitTestRunner#execute(Map, TestClasspathProvider)}
+ *
+ * absoluteProjectPath : Absolute path to the project directory
+ * updateClasspath : A boolean indicating whether rebuilding of class path is required.
+ * runClass : A boolean indicating whether the test runner should execute all the test cases or a test class
+ *            indicated by fqn parameter.
+ * fqn : Fully qualified class name of the test class if the runClass is true.
+ * 
+ * + * @author Mirage Abeysekara + */ +public class JUnitTestRunner implements TestRunner { + + private static final String JUNIT4X_RUNNER_CLASS = "org.junit.runner.JUnitCore"; + private static final String JUNIT3X_RUNNER_CLASS = "junit.textui.TestRunner"; + private String projectPath; + private ClassLoader projectClassLoader; + + + private TestResult run4x(String testClass) throws Exception { + ClassLoader classLoader = projectClassLoader; + Class clsTest = Class.forName(testClass, true, classLoader); + return run4xTestClasses(clsTest); + + } + + private TestResult runAll4x() throws Exception { + + List testClassNames = new ArrayList<>(); + Files.walk(Paths.get(projectPath, "target", "test-classes")).forEach(filePath -> { + if (Files.isRegularFile(filePath) && filePath.toString().toLowerCase().endsWith(".class")) { + String path = Paths.get(projectPath, "target", "test-classes").relativize(filePath).toString(); + String className = path.replace(File.separatorChar, '.'); + className = className.substring(0, className.length() - 6); + testClassNames.add(className); + } + }); + + List testableClasses = new ArrayList<>(); + for (String className : testClassNames) { + Class clazz = Class.forName(className, false, projectClassLoader); + if (isTestable4x(clazz)) { + testableClasses.add(clazz); + } + } + return run4xTestClasses(testableClasses.toArray(new Class[testableClasses.size()])); + } + + + private boolean isTestable4x(Class clazz) throws ClassNotFoundException { + for (Method method : clazz.getDeclaredMethods()) { + for (Annotation annotation : method.getAnnotations()) { + if (annotation.annotationType().getName().equals("org.junit.Test")) { + return true; + } + } + } + return false; + } + + + private TestResult run4xTestClasses(Class... classes) throws Exception { + + ClassLoader classLoader = projectClassLoader; + Class clsJUnitCore = Class.forName("org.junit.runner.JUnitCore", true, classLoader); + Class clsResult = Class.forName("org.junit.runner.Result", true, classLoader); + Class clsFailure = Class.forName("org.junit.runner.notification.Failure", true, classLoader); + Class clsDescription = Class.forName("org.junit.runner.Description", true, classLoader); + Class clsThrowable = Class.forName("java.lang.Throwable", true, classLoader); + Class clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader); + Object result = clsJUnitCore.getMethod("runClasses", Class[].class).invoke(null, new Object[]{classes}); + JUnitTestResult dtoResult = DtoFactory.getInstance().createDto(JUnitTestResult.class); + boolean isSuccess = (Boolean) clsResult.getMethod("wasSuccessful").invoke(result); + List failures = (List) clsResult.getMethod("getFailures").invoke(result); + List jUnitFailures = new ArrayList<>(); + + for (Object failure : failures) { + Failure dtoFailure = DtoFactory.getInstance().createDto(Failure.class); + + String message = (String) clsFailure.getMethod("getMessage").invoke(failure); + Object description = clsFailure.getMethod("getDescription").invoke(failure); + String failClassName = (String) clsDescription.getMethod("getClassName").invoke(description); + Object exception = clsFailure.getMethod("getException").invoke(failure); + Object stackTrace = clsThrowable.getMethod("getStackTrace").invoke(exception); + String failMethod = ""; + Integer failLine = null; + + if (stackTrace.getClass().isArray()) { + int length = Array.getLength(stackTrace); + for (int i = 0; i < length; i++) { + Object stackElement = Array.get(stackTrace, i); + String failClass = (String) clsStackTraceElement.getMethod("getClassName").invoke(stackElement); + if (failClass.equals(failClassName)) { + failMethod = (String) clsStackTraceElement.getMethod("getMethodName").invoke(stackElement); + failLine = (Integer) clsStackTraceElement.getMethod("getLineNumber").invoke(stackElement); + break; + } + } + } + String trace = (String) clsFailure.getMethod("getTrace").invoke(failure); + dtoFailure.setFailingClass(failClassName); + dtoFailure.setFailingMethod(failMethod); + dtoFailure.setFailingLine(failLine); + dtoFailure.setMessage(message); + dtoFailure.setTrace(trace); + jUnitFailures.add(dtoFailure); + } + dtoResult.setTestFramework("JUnit4x"); + dtoResult.setSuccess(isSuccess); + dtoResult.setFailureCount(jUnitFailures.size()); + dtoResult.setFailures(jUnitFailures); + dtoResult.setFrameworkVersion("4.x"); + return dtoResult; + } + + + + + + private TestResult run3x(String testClass) throws Exception { + ClassLoader classLoader = projectClassLoader; + Class clsTest = Class.forName(testClass, true, classLoader); + return run3xTestClasses(clsTest); + + } + + private TestResult runAll3x() throws Exception { + List testClassNames = new ArrayList<>(); + Files.walk(Paths.get(projectPath, "target", "test-classes")).forEach(filePath -> { + if (Files.isRegularFile(filePath) && filePath.toString().toLowerCase().endsWith(".class")) { + String path = Paths.get(projectPath, "target", "test-classes").relativize(filePath).toString(); + String className = path.replace(File.separatorChar, '.'); + className = className.substring(0, className.length() - 6); + testClassNames.add(className); + } + }); + + List testableClasses = new ArrayList<>(); + for (String className : testClassNames) { + Class clazz = Class.forName(className, false, projectClassLoader); + if (isTestable3x(clazz)) { + testableClasses.add(clazz); + } + } + + return run3xTestClasses(testableClasses.toArray(new Class[testableClasses.size()])); + + } + + + private boolean isTestable3x(Class clazz) throws ClassNotFoundException { + Class superClass = Class.forName("junit.framework.TestCase", true, projectClassLoader); + return superClass.isAssignableFrom(clazz); + } + + + private TestResult run3xTestClasses(Class... classes) throws Exception { + + + ClassLoader classLoader = projectClassLoader; + Class clsTestSuite = Class.forName("junit.framework.TestSuite", true, classLoader); + Class clsTestResult = Class.forName("junit.framework.TestResult", true, classLoader); + Class clsThrowable = Class.forName("java.lang.Throwable", true, classLoader); + Class clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader); + Class clsFailure = Class.forName("junit.framework.TestFailure", true, classLoader); + Object testSuite = clsTestSuite.newInstance(); + Object testResult = clsTestResult.newInstance(); + + for(Class testClass : classes){ + clsTestSuite.getMethod("addTestSuite", Class.class).invoke(testSuite, testClass); + } + + clsTestSuite.getMethod("run", clsTestResult).invoke(testSuite, testResult); + + JUnitTestResult dtoResult = DtoFactory.getInstance().createDto(JUnitTestResult.class); + boolean isSuccess = (Boolean) clsTestResult.getMethod("wasSuccessful").invoke(testResult); + Enumeration failures = (Enumeration) clsTestResult.getMethod("failures").invoke(testResult); + List jUnitFailures = new ArrayList<>(); + + while(failures.hasMoreElements()){ + Failure dtoFailure = DtoFactory.getInstance().createDto(Failure.class); + Object failure = failures.nextElement(); + String message = (String) clsFailure.getMethod("exceptionMessage").invoke(failure); + String trace = (String) clsFailure.getMethod("trace").invoke(failure); + Object failClassObject = clsFailure.getMethod("failedTest").invoke(failure); + String failClassName = failClassObject.getClass().getName(); + Object exception = clsFailure.getMethod("thrownException").invoke(failure); + Object stackTrace = clsThrowable.getMethod("getStackTrace").invoke(exception); + String failMethod = ""; + Integer failLine = null; + + if (stackTrace.getClass().isArray()) { + int length = Array.getLength(stackTrace); + for (int i = 0; i < length; i ++) { + Object arrayElement = Array.get(stackTrace, i); + String failClass = (String) clsStackTraceElement.getMethod("getClassName").invoke(arrayElement); + if(failClass.equals(failClassName)) { + failMethod = (String) clsStackTraceElement.getMethod("getMethodName").invoke(arrayElement); + failLine = (Integer) clsStackTraceElement.getMethod("getLineNumber").invoke(arrayElement); + break; + } + } + } + dtoFailure.setFailingClass(failClassName); + dtoFailure.setFailingMethod(failMethod); + dtoFailure.setFailingLine(failLine); + dtoFailure.setMessage(message); + dtoFailure.setTrace(trace); + jUnitFailures.add(dtoFailure); + } + + dtoResult.setTestFramework("JUnit3x"); + dtoResult.setSuccess(isSuccess); + dtoResult.setFailureCount(jUnitFailures.size()); + dtoResult.setFailures(jUnitFailures); + dtoResult.setFrameworkVersion("3.x"); + return dtoResult; + } + + /** + * {@inheritDoc} + */ + @Override + public TestResult execute(Map testParameters, + TestClasspathProvider classpathProvider) throws Exception { + + projectPath = testParameters.get("absoluteProjectPath"); + boolean updateClasspath = Boolean.valueOf(testParameters.get("updateClasspath")); + boolean runClass = Boolean.valueOf(testParameters.get("runClass")); + projectClassLoader = classpathProvider.getClassLoader(projectPath, updateClasspath); + TestResult testResult; + + try { + Class.forName(JUNIT4X_RUNNER_CLASS, true, projectClassLoader); + if (runClass) { + String fqn = testParameters.get("fqn"); + testResult = run4x(fqn); + } else { + testResult = runAll4x(); + } + return testResult; + } catch (Exception ignored) { + } + + try { + Class.forName(JUNIT3X_RUNNER_CLASS, true, projectClassLoader); + if (runClass) { + String fqn = testParameters.get("fqn"); + testResult = run3x(fqn); + } else { + testResult = runAll3x(); + } + return testResult; + } catch (Exception ignored) { + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return "junit"; + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/inject/JunitGuiceModule.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/inject/JunitGuiceModule.java new file mode 100644 index 00000000000..9389872ed15 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/src/main/java/org/eclipse/che/ide/ext/java/testing/junit/server/inject/JunitGuiceModule.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit.server.inject; + +import com.google.inject.AbstractModule; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestRunner; +import org.eclipse.che.ide.ext.java.testing.junit.server.JUnitTestRunner; +import org.eclipse.che.inject.DynaModule; + +import static com.google.inject.multibindings.Multibinder.newSetBinder; + +/** + * @author Mirage Abeysekara + */ +@DynaModule +public class JunitGuiceModule extends AbstractModule { + @Override + protected void configure() { + newSetBinder(binder(), TestRunner.class).addBinding().to(JUnitTestRunner.class); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml new file mode 100644 index 00000000000..48f1fb07bac --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml @@ -0,0 +1,157 @@ + + + + 4.0.0 + + che-java-testing-junit + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-junit-shared + Che Plugin :: Java Testing :: JUnit Shared + + ${project.build.directory}/generated-sources/dto/ + + + + + com.google.code.gson + gson + + + com.google.inject + guice + + + org.eclipse.che.core + che-core-api-dto + + + org.eclipse.che.core + che-core-commons-gwt + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + com.google.gwt + gwt-user + provided + + + + + + src/main/java + + + src/main/resources + + + ${dto-generator-out-directory} + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-resource + process-sources + + add-resource + + + + + ${dto-generator-out-directory}/META-INF + META-INF + + + + + + add-source + process-sources + + add-source + + + + ${dto-generator-out-directory} + + + + + + + maven-compiler-plugin + + + pre-compile + generate-sources + + compile + + + + + + org.eclipse.che.core + che-core-api-dto-maven-plugin + + + generate-client-dto + process-sources + + generate + + + + org.eclipse.che.ide.ext.java.testing.junit4x.shared + + ${dto-generator-out-directory} + org.eclipse.che.ide.ext.java.testing.junit.client.dto.DtoClientImpls + client + + + + generate-server-dto + process-sources + + generate + + + + org.eclipse.che.ide.ext.java.testing.junit4x.shared + + ${dto-generator-out-directory} + org.eclipse.che.ide.ext.java.testing.junit.server.dto.DtoServerImpls + server + + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/junit4x/shared/JUnitTestResult.java b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/junit4x/shared/JUnitTestResult.java new file mode 100644 index 00000000000..37010052e93 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/src/main/java/org/eclipse/che/ide/ext/java/testing/junit4x/shared/JUnitTestResult.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.junit4x.shared; + +import org.eclipse.che.dto.shared.DTO; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; + + +import java.util.List; +/** + * TestResult dto for JUnit + * @author Mirage Abeysekara + */ +@DTO +public interface JUnitTestResult extends TestResult { + /** + * Get the running JUnit framework version. + * @return JUnit framework version. + */ + String getFrameworkVersion(); + + /** + * Sets the JUnit framework version. + * @param framework framework version string + */ + void setFrameworkVersion(String framework); + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml new file mode 100644 index 00000000000..9bf590a8097 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml @@ -0,0 +1,30 @@ + + + + 4.0.0 + + che-plugin-java-test-runner-parent + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-junit + pom + Che Plugin :: Java Testing :: JUnit Parent + + che-java-testing-junit-server + che-java-testing-junit-shared + che-java-testing-junit-ide + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml new file mode 100644 index 00000000000..769506f1fc0 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml @@ -0,0 +1,84 @@ + + + + 4.0.0 + + che-java-testing-testng + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-testng-ide + Che Plugin :: Java Testing :: TestNG IDE + + + com.google.inject + guice + + + javax.validation + validation-api + + + org.eclipse.che.core + che-core-commons-gwt + + + org.eclipse.che.core + che-core-ide-api + + + org.eclipse.che.core + che-core-ide-app + + + org.eclipse.che.plugin + che-java-testing-core-ide + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + che-plugin-java-ext-lang-client + + + org.vectomatic + lib-gwt-svg + + + com.google.gwt + gwt-user + provided + + + com.google.gwt.inject + gin + provided + + + + + + src/main/java + + **/*.java + + + + src/main/resources + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGGinModule.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGGinModule.java new file mode 100644 index 00000000000..ab504693a86 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGGinModule.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client; + +import com.google.gwt.inject.client.AbstractGinModule; +import com.google.gwt.inject.client.multibindings.GinMultibinder; +import org.eclipse.che.ide.api.extension.ExtensionGinModule; +import org.eclipse.che.ide.ext.java.testing.core.client.TestAction; +/** + * + * @author Mirage Abeysekara + */ +@ExtensionGinModule +public class TestNGGinModule extends AbstractGinModule { + @Override + protected void configure() { + GinMultibinder.newSetBinder(binder(), TestAction.class).addBinding().to(TestNGTestAction.class); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.java new file mode 100644 index 00000000000..3d2b05f5305 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client; + +import com.google.gwt.i18n.client.Messages; + +/** + * Localization constants. Interface to represent the constants defined in resource bundle: + * 'TestNGLocalizationConstant.properties'. + * + * @author Mirage Abeysekara + */ +public interface TestNGLocalizationConstant extends Messages { + + @Key("action.runClass.title") + String actionRunClassTitle(); + + @Key("action.runClass.description") + String actionRunClassDescription(); + + @Key("action.runClassContext.title") + String actionRunClassContextTitle(); + + @Key("action.runClassContext.description") + String actionRunClassContextDescription(); + + @Key("action.runAll.title") + String actionRunAllTitle(); + + @Key("action.runAll.description") + String actionRunAllDescription(); + + @Key("action.runXML.title") + String actionRunXMLTitle(); + + @Key("action.runXML.description") + String actionRunXMLDescription(); +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGResources.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGResources.java new file mode 100644 index 00000000000..e321e97ea04 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGResources.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client; + +import com.google.gwt.resources.client.ClientBundle; +import org.vectomatic.dom.svg.ui.SVGResource; +/** + * + * @author Mirage Abeysekara + */ +public interface TestNGResources extends ClientBundle { + + @Source("org/eclipse/che/ide/ext/java/testing/core/client/svg/test.svg") + SVGResource testIcon(); + + @Source("org/eclipse/che/ide/ext/java/testing/core/client/svg/test_all.svg") + SVGResource testAllIcon(); + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGTestAction.java new file mode 100644 index 00000000000..a4451100798 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGTestAction.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client; + +import com.google.inject.Inject; +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; +import org.eclipse.che.ide.api.keybinding.KeyBuilder; +import org.eclipse.che.ide.ext.java.testing.core.client.TestAction; +import org.eclipse.che.ide.ext.java.testing.testng.client.action.RunAllTestAction; +import org.eclipse.che.ide.ext.java.testing.testng.client.action.RunClassContextTestAction; +import org.eclipse.che.ide.ext.java.testing.testng.client.action.RunClassTestAction; +import org.eclipse.che.ide.ext.java.testing.testng.client.action.RunTestXMLAction; +/** + * TestNG ide implementation. + * @author Mirage Abeysekara + */ +public class TestNGTestAction implements TestAction { + + private final Action runClassTestAction; + private final Action runAllTestAction; + private final Action runClassContextTestAction; + private final Action runTestXMLAction; + + @Inject + public TestNGTestAction(ActionManager actionManager, + RunClassTestAction runClassTestAction, + RunAllTestAction runAllTestAction, + RunClassContextTestAction runClassContextTestAction, + RunTestXMLAction runTestXMLAction, + KeyBindingAgent keyBinding) { + + actionManager.registerAction("TestNGActionRunClass", runClassTestAction); + actionManager.registerAction("TestNGActionRunAll", runAllTestAction); + actionManager.registerAction("TestNGActionRunXML", runTestXMLAction); + actionManager.registerAction("TestNGActionRunClassContext", runClassContextTestAction); + + keyBinding.getGlobal().addKey(new KeyBuilder().action().alt().charCode('n').build(), + "TestNGActionRunAll"); + + keyBinding.getGlobal().addKey(new KeyBuilder().action().shift().charCode('n').build(), + "TestNGActionRunClass"); + + this.runAllTestAction = runAllTestAction; + this.runClassContextTestAction = runClassContextTestAction; + this.runClassTestAction = runClassTestAction; + this.runTestXMLAction = runTestXMLAction; + } + + + @Override + public void addMainMenuItems(DefaultActionGroup testMainMenu) { + testMainMenu.add(runClassTestAction); + testMainMenu.add(runAllTestAction); + testMainMenu.add(runTestXMLAction); + } + + @Override + public void addContextMenuItems(DefaultActionGroup testContextMenu) { + testContextMenu.add(runClassContextTestAction); + testContextMenu.add(runAllTestAction); + testContextMenu.add(runTestXMLAction); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunAllTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunAllTestAction.java new file mode 100644 index 00000000000..134bb7d2d02 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunAllTestAction.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client.action; + +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.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.ext.java.client.action.JavaEditorAction; +import org.eclipse.che.ide.ext.java.testing.core.client.TestServiceClient; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultPresenter; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGResources; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; + +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; + +/** + * + * @author Mirage Abeysekara + */ +public class RunAllTestAction extends JavaEditorAction { + + private final NotificationManager notificationManager; + private final EditorAgent editorAgent; + private TestResultPresenter presenter; + private final TestServiceClient service; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + + @Inject + public RunAllTestAction(TestNGResources resources, NotificationManager notificationManager, EditorAgent editorAgent, + TestResultPresenter presenter, FileTypeRegistry fileTypeRegistry, TestServiceClient service, + DtoUnmarshallerFactory dtoUnmarshallerFactory, TestNGLocalizationConstant localization) { + super(localization.actionRunAllTitle(), localization.actionRunAllDescription(), resources.testAllIcon(), + editorAgent, fileTypeRegistry); + this.notificationManager = notificationManager; + this.editorAgent = editorAgent; + this.presenter = presenter; + this.service = service; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + } + + @Override + public void actionPerformed(ActionEvent e) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + final Project project = appContext.getRootProject(); + + Map parameters = new HashMap<>(); + parameters.put("updateClasspath", "true"); + + Promise testResultPromise = service.getTestResult(project.getPath(), "testng", parameters); + testResultPromise.then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully"); + notification.setContent("All tests are passed"); + } else { + notification.setTitle("Test runner executed successfully with test failures."); + notification.setContent(result.getFailureCount() + " test(s) failed.\n"); + } + presenter.handleResponse(result); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError exception) throws OperationException { + final String errorMessage = (exception.getMessage() != null) + ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + }); + + } + +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassContextTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassContextTestAction.java new file mode 100644 index 00000000000..aa0d41d7ff7 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassContextTestAction.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client.action; + +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.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.eclipse.che.ide.api.selection.Selection; +import org.eclipse.che.ide.api.selection.SelectionAgent; +import org.eclipse.che.ide.ext.java.client.util.JavaUtil; +import org.eclipse.che.ide.ext.java.testing.core.client.TestServiceClient; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultPresenter; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGResources; +import org.eclipse.che.ide.resources.tree.FileNode; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; + +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; +import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; + +/** + * + * @author Mirage Abeysekara + */ +public class RunClassContextTestAction extends AbstractPerspectiveAction { + + private final NotificationManager notificationManager; + private final EditorAgent editorAgent; + private final TestResultPresenter presenter; + private final TestServiceClient service; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + private final AppContext appContext; + private final SelectionAgent selectionAgent; + + @Inject + public RunClassContextTestAction(TestNGResources resources, NotificationManager notificationManager, EditorAgent editorAgent, + AppContext appContext, TestResultPresenter presenter, + TestServiceClient service, DtoUnmarshallerFactory dtoUnmarshallerFactory, + SelectionAgent selectionAgent, TestNGLocalizationConstant localization) { + super(Arrays.asList(PROJECT_PERSPECTIVE_ID), localization.actionRunClassContextTitle(), + localization.actionRunClassContextDescription(), null, resources.testIcon()); + this.notificationManager = notificationManager; + this.editorAgent = editorAgent; + this.presenter = presenter; + this.service = service; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + this.appContext = appContext; + this.selectionAgent = selectionAgent; + } + + @Override + public void actionPerformed(ActionEvent e) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + final Selection selection = selectionAgent.getSelection(); + final Object possibleNode = selection.getHeadElement(); + if (possibleNode instanceof FileNode) { + VirtualFile file = ((FileNode) possibleNode).getData(); + + + final Project project = appContext.getRootProject(); + + String fqn = JavaUtil.resolveFQN(file); + + Map parameters = new HashMap<>(); + parameters.put("fqn",fqn); + parameters.put("runClass","true"); + parameters.put("updateClasspath","true"); + + Promise testResultPromise = service.getTestResult(project.getPath(), "testng", parameters); + testResultPromise.then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully"); + notification.setContent("All tests are passed"); + } else { + notification.setTitle("Test runner executed successfully with test failures."); + notification.setContent(result.getFailureCount() + " test(s) failed.\n"); + } + presenter.handleResponse(result); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError exception) throws OperationException { + final String errorMessage = (exception.getMessage() != null) + ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + }); + } + } + + @Override + public void updateInPerspective(@NotNull ActionEvent e) { + if ((appContext.getRootProject() == null)) { + e.getPresentation().setVisible(true); + e.getPresentation().setEnabled(false); + return; + } + + final Selection selection = selectionAgent.getSelection(); + + if (selection == null || selection.isEmpty()) { + e.getPresentation().setEnabled(false); + return; + } + + if (selection.isMultiSelection()) { + e.getPresentation().setEnabled(false); + return; + } + + final Object possibleNode = selection.getHeadElement(); + + boolean enable = possibleNode instanceof FileNode + && ((FileNode)possibleNode).getData().getExtension().equals("java"); + + e.getPresentation().setEnabled(enable); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassTestAction.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassTestAction.java new file mode 100644 index 00000000000..836bb96a71a --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunClassTestAction.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client.action; + +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.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.editor.EditorPartPresenter; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.eclipse.che.ide.ext.java.client.action.JavaEditorAction; +import org.eclipse.che.ide.ext.java.client.util.JavaUtil; +import org.eclipse.che.ide.ext.java.testing.core.client.TestServiceClient; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultPresenter; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGResources; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; + +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; + +/** + * + * @author Mirage Abeysekara + */ +public class RunClassTestAction extends JavaEditorAction { + + private final NotificationManager notificationManager; + private final EditorAgent editorAgent; + private final TestResultPresenter presenter; + private final TestServiceClient service; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + + @Inject + public RunClassTestAction(TestNGResources resources, + NotificationManager notificationManager, + EditorAgent editorAgent, + FileTypeRegistry fileTypeRegistry, + TestResultPresenter presenter, + TestServiceClient service, + DtoUnmarshallerFactory dtoUnmarshallerFactory, + TestNGLocalizationConstant localization) { + super(localization.actionRunClassTitle(), localization.actionRunClassDescription(), resources.testIcon(), + editorAgent, fileTypeRegistry); + this.notificationManager = notificationManager; + this.editorAgent = editorAgent; + this.presenter = presenter; + this.service = service; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + } + + @Override + public void actionPerformed(ActionEvent e) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + final Project project = appContext.getRootProject(); + + + EditorPartPresenter editorPart = editorAgent.getActiveEditor(); + final VirtualFile file = editorPart.getEditorInput().getFile(); + String fqn = JavaUtil.resolveFQN(file); + + Map parameters = new HashMap<>(); + parameters.put("fqn", fqn); + parameters.put("runClass", "true"); + parameters.put("updateClasspath", "true"); + + Promise testResultPromise = service.getTestResult(project.getPath(), "testng", parameters); + testResultPromise.then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully"); + notification.setContent("All tests are passed"); + } else { + notification.setTitle("Test runner executed successfully with test failures."); + notification.setContent(result.getFailureCount() + " test(s) failed.\n"); + } + presenter.handleResponse(result); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError exception) throws OperationException { + final String errorMessage = (exception.getMessage() != null) + ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + }); + } + + @Override + protected void updateProjectAction(ActionEvent e) { + super.updateProjectAction(e); + e.getPresentation().setVisible(true); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunTestXMLAction.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunTestXMLAction.java new file mode 100644 index 00000000000..ee003564517 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/client/action/RunTestXMLAction.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.client.action; + +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.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.ext.java.client.action.JavaEditorAction; +import org.eclipse.che.ide.ext.java.testing.core.client.TestServiceClient; +import org.eclipse.che.ide.ext.java.testing.core.client.view.TestResultPresenter; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGLocalizationConstant; +import org.eclipse.che.ide.ext.java.testing.testng.client.TestNGResources; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; +import org.eclipse.che.plugin.maven.shared.MavenAttributes; + +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; + +/** + * + * @author Mirage Abeysekara + */ +public class RunTestXMLAction extends JavaEditorAction { + + private final NotificationManager notificationManager; + private final EditorAgent editorAgent; + private TestResultPresenter presenter; + private final TestServiceClient service; + private final DtoUnmarshallerFactory dtoUnmarshallerFactory; + + @Inject + public RunTestXMLAction(TestNGResources resources, NotificationManager notificationManager, EditorAgent editorAgent, + TestResultPresenter presenter, FileTypeRegistry fileTypeRegistry, TestServiceClient service, + DtoUnmarshallerFactory dtoUnmarshallerFactory, TestNGLocalizationConstant localization) { + + super(localization.actionRunXMLTitle(), localization.actionRunXMLDescription(), resources.testAllIcon(), + editorAgent, fileTypeRegistry); + + this.notificationManager = notificationManager; + this.editorAgent = editorAgent; + this.presenter = presenter; + this.service = service; + this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; + } + + @Override + public void actionPerformed(ActionEvent e) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + final Project project = appContext.getRootProject(); + + Map parameters = new HashMap<>(); + parameters.put("updateClasspath", "true"); + parameters.put("testngXML", project.getPath() + "/" + + MavenAttributes.DEFAULT_TEST_RESOURCES_FOLDER + "/testng.xml"); + + Promise testResultPromise = service.getTestResult(project.getPath(), "testng", parameters); + testResultPromise.then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully"); + notification.setContent("All tests are passed"); + } else { + notification.setTitle("Test runner executed successfully with test failures."); + notification.setContent(result.getFailureCount() + " test(s) failed.\n"); + } + presenter.handleResponse(result); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError exception) throws OperationException { + final String errorMessage = (exception.getMessage() != null) + ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + }); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.properties b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.properties new file mode 100644 index 00000000000..8f3141760f7 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/TestNGLocalizationConstant.properties @@ -0,0 +1,26 @@ +# +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Codenvy, S.A. - initial API and implementation +# + + + +##### Actions ##### +action.runClass.title = TestNG Class +action.runClass.description = Run the currently open TestNG test class + +action.runClassContext.title = TestNG Class +action.runClassContext.description = Run the TestNG test cases + +action.runAll.title = TestNG Project +action.runAll.description = Run all TestNG test cases + +action.runXML.title = TestNG XML Suite +action.runXML.description = Run TestNG XML Suite in testng.xml file + diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test.svg b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test.svg new file mode 100644 index 00000000000..c89092bbef1 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test.svg @@ -0,0 +1,18 @@ + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test_all.svg b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test_all.svg new file mode 100644 index 00000000000..f53982b80e2 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/src/main/resources/org/eclipse/che/ide/ext/java/testing/testng/client/svg/test_all.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml new file mode 100644 index 00000000000..ceb00f8223a --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml @@ -0,0 +1,53 @@ + + + + 4.0.0 + + che-java-testing-testng + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-testng-server + Che Plugin :: Java Testing :: TestNG Server + + + com.google.inject + guice + + + com.google.inject.extensions + guice-multibindings + + + org.eclipse.che.core + che-core-api-dto + + + org.eclipse.che.core + che-core-commons-inject + + + org.eclipse.che.plugin + che-java-testing-core-server + + + org.eclipse.che.plugin + che-java-testing-core-shared + + + org.eclipse.che.plugin + org.eclipse.core.resources + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/TestNGRunner.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/TestNGRunner.java new file mode 100644 index 00000000000..f166a65c192 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/TestNGRunner.java @@ -0,0 +1,265 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.server; + + +import org.eclipse.che.dto.server.DtoFactory; + +import org.eclipse.che.ide.ext.java.testing.core.server.classpath.TestClasspathProvider; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestRunner; +import org.eclipse.che.ide.ext.java.testing.core.shared.Failure; +import org.eclipse.che.ide.ext.java.testing.core.shared.TestResult; +import org.eclipse.core.resources.ResourcesPlugin; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * TestNG implementation for the test runner service. + * + *
+ * Available Parameters for {@link TestNGRunner#execute(Map, TestClasspathProvider)}
+ *
+ * absoluteProjectPath : Absolute path to the project directory
+ * updateClasspath : A boolean indicating whether rebuilding of class path is required.
+ * runClass : A boolean indicating whether the test runner should execute all, TestNG XML suite test cases or
+ *            a test class indicated by fqn parameter.
+ * fqn : Fully qualified class name of the test class if the runClass is true.
+ * testngXML : Relative path to the testng.xml file. If this parameter is set, the TestNG test runner will
+ *             execute given testng.xml test suite, otherwise all the test classes are get executed.
+ *             (Note: If the runClass parameter is true then testngXML parameter gets ignored.)
+ *
+ * 
+ * @author Mirage Abeysekara + */ +public class TestNGRunner implements TestRunner { + + String projectPath; + ClassLoader projectClassLoader; + + + private TestResult run(String testClass) throws Exception { + ClassLoader classLoader = projectClassLoader; + Class clsTest = Class.forName(testClass, true, classLoader); + return runTestClasses(clsTest); + + } + + private TestResult runAll() throws Exception { + List testClassNames = new ArrayList<>(); + Files.walk(Paths.get(projectPath, "target", "test-classes")).forEach(filePath -> { + if (Files.isRegularFile(filePath) && filePath.toString().toLowerCase().endsWith(".class")) { + String path = Paths.get(projectPath, "target", "test-classes").relativize(filePath).toString(); + String className = path.replace(File.separatorChar, '.'); + className = className.substring(0, className.length() - 6); + testClassNames.add(className); + } + }); + + List testableClasses = new ArrayList<>(); + for (String className : testClassNames) { + Class clazz = Class.forName(className, false, projectClassLoader); + if (isTestable(clazz)) { + testableClasses.add(clazz); + } + } + + return runTestClasses(testableClasses.toArray(new Class[testableClasses.size()])); + + } + + + private boolean isTestable(Class clazz) throws ClassNotFoundException { + for (Method method : clazz.getDeclaredMethods()) { + for (Annotation annotation : method.getAnnotations()) { + if (annotation.annotationType().getName().equals("org.testng.annotations.Test")) { + return true; + } + } + } + return false; + } + + + private TestResult runTestClasses(Class... classes) throws Exception { + + ClassLoader classLoader = projectClassLoader; + Class clsTestNG = Class.forName("org.testng.TestNG", true, classLoader); + Class clsTestListner = Class.forName("org.testng.TestListenerAdapter", true, classLoader); + Class clsITestListner = Class.forName("org.testng.ITestListener", true, classLoader); + Class clsResult = Class.forName("org.testng.ITestResult", true, classLoader); + Class clsIClass = Class.forName("org.testng.IClass", true, classLoader); + Class clsThrowable = Class.forName("java.lang.Throwable", true, classLoader); + Class clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader); + Object testNG = clsTestNG.newInstance(); + Object testListner = clsTestListner.newInstance(); + clsTestNG.getMethod("addListener", clsITestListner).invoke(testNG, testListner); + clsTestNG.getMethod("setTestClasses", Class[].class).invoke(testNG, new Object[]{classes}); + clsTestNG.getMethod("setOutputDirectory", String.class).invoke(testNG, Paths.get(projectPath,"target","testng-out").toString()); + clsTestNG.getMethod("run").invoke(testNG); + + List failures = (List) clsTestListner.getMethod("getFailedTests").invoke(testListner); + TestResult dtoResult = DtoFactory.getInstance().createDto(TestResult.class); + boolean isSuccess = (failures.size() == 0); + List testNGFailures = new ArrayList<>(); + + for (Object failure : failures) { + Failure dtoFailure = DtoFactory.getInstance().createDto(Failure.class); + Object throwable = clsResult.getMethod("getThrowable").invoke(failure); + String message = (String) clsThrowable.getMethod("getMessage").invoke(throwable); + Object failingClass = clsResult.getMethod("getTestClass").invoke(failure); + String failClassName = (String) clsIClass.getMethod("getName").invoke(failingClass); + Object stackTrace = clsThrowable.getMethod("getStackTrace").invoke(throwable); + String failMethod = ""; + Integer failLine = null; + + if (stackTrace.getClass().isArray()) { + int length = Array.getLength(stackTrace); + for (int i = 0; i < length; i++) { + Object arrayElement = Array.get(stackTrace, i); + String failClass = (String) clsStackTraceElement.getMethod("getClassName").invoke(arrayElement); + if (failClass.equals(failClassName)) { + failMethod = (String) clsStackTraceElement.getMethod("getMethodName").invoke(arrayElement); + failLine = (Integer) clsStackTraceElement.getMethod("getLineNumber").invoke(arrayElement); + break; + } + } + } + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + clsThrowable.getMethod("printStackTrace", PrintWriter.class).invoke(throwable, pw); + String trace = sw.toString(); + dtoFailure.setFailingClass(failClassName); + dtoFailure.setFailingMethod(failMethod); + dtoFailure.setFailingLine(failLine); + dtoFailure.setMessage(message); + dtoFailure.setTrace(trace); + testNGFailures.add(dtoFailure); + } + + dtoResult.setTestFramework("TestNG"); + dtoResult.setSuccess(isSuccess); + dtoResult.setFailureCount(testNGFailures.size()); + dtoResult.setFailures(testNGFailures); + return dtoResult; + } + + + private TestResult runTestXML(String xmlPath) throws Exception { + + + ClassLoader classLoader = projectClassLoader; + Class clsTestNG = Class.forName("org.testng.TestNG", true, classLoader); + Class clsTestListner = Class.forName("org.testng.TestListenerAdapter", true, classLoader); + Class clsITestListner = Class.forName("org.testng.ITestListener", true, classLoader); + Class clsResult = Class.forName("org.testng.ITestResult", true, classLoader); + Class clsIClass = Class.forName("org.testng.IClass", true, classLoader); + Class clsThrowable = Class.forName("java.lang.Throwable", true, classLoader); + Class clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader); + Object testNG = clsTestNG.newInstance(); + Object testListner = clsTestListner.newInstance(); + clsTestNG.getMethod("addListener", clsITestListner).invoke(testNG, testListner); + List testSuites = new ArrayList<>(); + testSuites.add(xmlPath); + clsTestNG.getMethod("setTestSuites", List.class).invoke(testNG, testSuites); + clsTestNG.getMethod("setOutputDirectory", String.class).invoke(testNG, Paths.get(projectPath,"target","testng-out").toString()); + clsTestNG.getMethod("run").invoke(testNG); + List failures = (List) clsTestListner.getMethod("getFailedTests").invoke(testListner); + TestResult dtoResult = DtoFactory.getInstance().createDto(TestResult.class); + boolean isSuccess = (failures.size() == 0); + List testNGFailures = new ArrayList<>(); + + for (Object failure : failures) { + + Failure dtoFailure = DtoFactory.getInstance().createDto(Failure.class); + Object throwable = clsResult.getMethod("getThrowable").invoke(failure); + String message = (String) clsThrowable.getMethod("getMessage").invoke(throwable); + Object failingClass = clsResult.getMethod("getTestClass").invoke(failure); + String failClassName = (String) clsIClass.getMethod("getName").invoke(failingClass); + Object stackTrace = clsThrowable.getMethod("getStackTrace").invoke(throwable); + String failMethod = ""; + Integer failLine = null; + + if (stackTrace.getClass().isArray()) { + int length = Array.getLength(stackTrace); + for (int i = 0; i < length; i++) { + Object arrayElement = Array.get(stackTrace, i); + String failClass = (String) clsStackTraceElement.getMethod("getClassName").invoke(arrayElement); + if (failClass.equals(failClassName)) { + failMethod = (String) clsStackTraceElement.getMethod("getMethodName").invoke(arrayElement); + failLine = (Integer) clsStackTraceElement.getMethod("getLineNumber").invoke(arrayElement); + break; + } + } + } + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + clsThrowable.getMethod("printStackTrace", PrintWriter.class).invoke(throwable, pw); + String trace = sw.toString(); + dtoFailure.setFailingClass(failClassName); + dtoFailure.setFailingMethod(failMethod); + dtoFailure.setFailingLine(failLine); + dtoFailure.setMessage(message); + dtoFailure.setTrace(trace); + testNGFailures.add(dtoFailure); + } + + dtoResult.setTestFramework("TestNG"); + dtoResult.setSuccess(isSuccess); + dtoResult.setFailureCount(testNGFailures.size()); + dtoResult.setFailures(testNGFailures); + return dtoResult; + } + + /** + * {@inheritDoc} + */ + @Override + public TestResult execute(Map testParameters, + TestClasspathProvider classpathProvider) throws Exception { + + projectPath = testParameters.get("absoluteProjectPath"); + String xmlPath = testParameters.get("testngXML"); + boolean updateClasspath = Boolean.valueOf(testParameters.get("updateClasspath")); + boolean runClass = Boolean.valueOf(testParameters.get("runClass")); + projectClassLoader = classpathProvider.getClassLoader(projectPath, updateClasspath); + TestResult testResult; + + if (runClass) { + String fqn = testParameters.get("fqn"); + testResult = run(fqn); + } else { + if (xmlPath == null) { + testResult = runAll(); + } else { + testResult = runTestXML(ResourcesPlugin.getPathToWorkspace() + xmlPath); + } + } + return testResult; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return "testng"; + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/inject/TestNGGuiceModule.java b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/inject/TestNGGuiceModule.java new file mode 100644 index 00000000000..78c5fa5e0e4 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/src/main/java/org/eclipse/che/ide/ext/java/testing/testng/server/inject/TestNGGuiceModule.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.ext.java.testing.testng.server.inject; + +import com.google.inject.AbstractModule; +import org.eclipse.che.ide.ext.java.testing.core.server.framework.TestRunner; +import org.eclipse.che.ide.ext.java.testing.testng.server.TestNGRunner; +import org.eclipse.che.inject.DynaModule; + +import static com.google.inject.multibindings.Multibinder.newSetBinder; + +/** + * @author Mirage Abeysekara + */ +@DynaModule +public class TestNGGuiceModule extends AbstractModule { + @Override + protected void configure() { + newSetBinder(binder(), TestRunner.class).addBinding().to(TestNGRunner.class); + } +} diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml new file mode 100644 index 00000000000..e165b4b0614 --- /dev/null +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml @@ -0,0 +1,29 @@ + + + + 4.0.0 + + che-plugin-java-test-runner-parent + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-java-testing-testng + pom + Che Plugin :: Java Testing :: TestNG Parent + + che-java-testing-testng-server + che-java-testing-testng-ide + + + diff --git a/plugins/plugin-java-test-runner/pom.xml b/plugins/plugin-java-test-runner/pom.xml new file mode 100644 index 00000000000..6fbd6d5464b --- /dev/null +++ b/plugins/plugin-java-test-runner/pom.xml @@ -0,0 +1,30 @@ + + + + 4.0.0 + + che-plugin-parent + org.eclipse.che.plugin + 5.0.0-M8-SNAPSHOT + + che-plugin-java-test-runner-parent + pom + Che Plugin :: Java Testing :: Parent + + che-java-testing-core + che-java-testing-junit + che-java-testing-testng + che-java-testing-classpath + + diff --git a/plugins/pom.xml b/plugins/pom.xml index 4710aaa10ff..1bc9eaba9d7 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -33,6 +33,7 @@ plugin-debugger plugin-java plugin-java-debugger + plugin-java-test-runner plugin-maven plugin-gdb plugin-sdk diff --git a/pom.xml b/pom.xml index 9df509d3395..85f49568fee 100644 --- a/pom.xml +++ b/pom.xml @@ -406,6 +406,56 @@ org-eclipse-jdt-core-repack ${che.lib.version}
+ + org.eclipse.che.plugin + che-java-testing-classpath-maven-server + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-core-ide + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-core-server + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-core-shared + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-junit-ide + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-junit-server + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-junit-shared + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-testng-ide + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-testng-server + ${che.version} + + + org.eclipse.che.plugin + che-java-testing-testng-shared + ${che.version} + org.eclipse.che.plugin che-plugin-cpp-lang-ide From c91257f46bb096af13b0fb49180850048e8ef92e Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Tue, 22 Nov 2016 22:55:25 +0200 Subject: [PATCH 08/74] CODENVY-657: Do not log SourceNotFoundException (#3084) --- .../che/plugin/docker/client/DockerConnector.java | 12 +++++++++++- .../che/api/workspace/server/WorkspaceManager.java | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java index e691e915cdb..6ac395f279f 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java @@ -798,6 +798,12 @@ private String buildImage(final DockerConnection dockerConnection, Future imageIdFuture = executor.submit(() -> { ProgressStatus progressStatus; while ((progressStatus = progressReader.next()) != null) { + if (progressStatus.getError() != null) { + String errorMessage = progressStatus.getError(); + if (errorMessage.matches("Error: image .+ not found")) { + throw new ImageNotFoundException(errorMessage); + } + } final String buildImageId = getBuildImageId(progressStatus); if (buildImageId != null) { return buildImageId; @@ -811,7 +817,11 @@ private String buildImage(final DockerConnection dockerConnection, return imageIdFuture.get(); } catch (ExecutionException e) { // unwrap exception thrown by task with .getCause() - throw new DockerException(e.getCause().getLocalizedMessage(), 500); + if (e.getCause() instanceof ImageNotFoundException) { + throw new ImageNotFoundException(e.getCause().getLocalizedMessage()); + } else { + throw new DockerException(e.getCause().getLocalizedMessage(), 500); + } } catch (InterruptedException e) { throw new DockerException("Docker image build was interrupted", 500); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index cc8f6aad1ff..3c7cccdd00b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -28,6 +28,7 @@ import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.environment.server.exception.EnvironmentException; import org.eclipse.che.api.machine.server.exception.SnapshotException; +import org.eclipse.che.api.machine.server.exception.SourceNotFoundException; import org.eclipse.che.api.machine.server.model.impl.MachineImpl; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.spi.Instance; @@ -61,6 +62,7 @@ import java.util.concurrent.Future; import static com.google.common.base.MoreObjects.firstNonNull; +import static com.google.common.base.Throwables.getCausalChain; import static java.lang.Boolean.parseBoolean; import static java.lang.String.format; import static java.lang.System.currentTimeMillis; @@ -647,6 +649,11 @@ void performAsyncStart(WorkspaceImpl workspace, rmEx.getLocalizedMessage()); } } + for (Throwable cause : getCausalChain(ex)) { + if (cause instanceof SourceNotFoundException) { + return; + } + } LOG.error(ex.getLocalizedMessage(), ex); } })); From 7258273064369ca480a59065d0a5b2a620436c4c Mon Sep 17 00:00:00 2001 From: Evgen Vidolob Date: Wed, 23 Nov 2016 09:14:58 +0200 Subject: [PATCH 09/74] #2972 fix all comments to feature --- .../che/ide/api/action/IdeActions.java | 2 - .../core/StandardComponentInitializer.java | 14 +--- .../ide/part/editor/EmptyEditorsPanel.java | 80 +++++++++++-------- .../ide/part/editor/EmptyEditorsPanel.ui.xml | 26 ++++-- .../EditorMultiPartStackViewImpl.java | 4 + .../part/explorer/project/EmptyTreePanel.java | 13 ++- 6 files changed, 82 insertions(+), 57 deletions(-) diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java index af2db3908db..d59e0e2fc64 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java @@ -47,6 +47,4 @@ public interface IdeActions { String GROUP_LEFT_STATUS_PANEL = "leftStatusPanelGroup"; String GROUP_RIGHT_STATUS_PANEL = "rightStatusPanelGroup"; - String GROUP_EMPTY_EDITOR_PANEL = "emptyEditorPanelGroup"; - String GROUP_EMPTY_PROJECT_PANEL = "emptyProjectPanelGroup"; } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java index 8f5bd1452f0..4341ef3a1cb 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java @@ -668,16 +668,6 @@ public void initialize() { editorContextMenuGroup.add(closeActiveEditorAction); - DefaultActionGroup emptyEditorsPanel = new DefaultActionGroup(actionManager); - actionManager.registerAction(IdeActions.GROUP_EMPTY_EDITOR_PANEL, emptyEditorsPanel); - emptyEditorsPanel.add(newFileAction); - emptyEditorsPanel.add(createProjectAction); - - DefaultActionGroup emptyProjectPanel = new DefaultActionGroup(actionManager); - actionManager.registerAction(IdeActions.GROUP_EMPTY_PROJECT_PANEL, emptyProjectPanel); - emptyProjectPanel.add(importProjectAction); - emptyProjectPanel.add(createProjectAction); - // Define hot-keys keyBinding.getGlobal().addKey(new KeyBuilder().action().alt().charCode('n').build(), "navigateToFile"); keyBinding.getGlobal().addKey(new KeyBuilder().action().charCode('F').build(), "fullTextSearch"); @@ -692,6 +682,10 @@ public void initialize() { keyBinding.getGlobal().addKey(new KeyBuilder().action().charCode('s').build(), "noOpAction"); keyBinding.getGlobal().addKey(new KeyBuilder().charCode(KeyCodeMap.DELETE).build(), "deleteItem"); + keyBinding.getGlobal().addKey(new KeyBuilder().alt().charCode('N').build(), "newFile"); + keyBinding.getGlobal().addKey(new KeyBuilder().alt().charCode('x').build(), "createProject"); + keyBinding.getGlobal().addKey(new KeyBuilder().alt().charCode('A').build(), "importProject"); + if (UserAgent.isMac()) { keyBinding.getGlobal().addKey(new KeyBuilder().control().charCode('w').build(), "closeActiveEditor"); keyBinding.getGlobal().addKey(new KeyBuilder().control().charCode('p').build(), "signatureHelp"); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.java index 232a5dedf43..ab4a409f28b 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.java @@ -30,11 +30,11 @@ import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.Resources; +import org.eclipse.che.ide.actions.CreateProjectAction; +import org.eclipse.che.ide.actions.ImportProjectAction; import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.action.ActionManager; -import org.eclipse.che.ide.api.action.DefaultActionGroup; -import org.eclipse.che.ide.api.action.IdeActions; import org.eclipse.che.ide.api.action.Presentation; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; @@ -43,15 +43,15 @@ import org.eclipse.che.ide.api.resources.ResourceChangedEvent; import org.eclipse.che.ide.api.resources.ResourceDelta; import org.eclipse.che.ide.api.theme.Style; +import org.eclipse.che.ide.newresource.NewFileAction; import org.eclipse.che.ide.ui.toolbar.PresentationFactory; -import org.eclipse.che.ide.ui.toolbar.Utils; import org.eclipse.che.ide.util.dom.Elements; import org.eclipse.che.ide.util.input.KeyMapUtil; import org.vectomatic.dom.svg.ui.SVGImage; import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import static org.eclipse.che.ide.api.resources.Resource.PROJECT; @@ -66,17 +66,20 @@ public class EmptyEditorsPanel extends Composite implements ResourceChangedEvent private final Provider perspectiveManagerProvider; private final KeyBindingAgent keyBindingAgent; private final PresentationFactory presentationFactory; - private final CoreLocalizationConstant localizationConstant; + private final CoreLocalizationConstant localizationConstant; + + private final Map noFiles = new HashMap<>(); + private final Map noProjects = new HashMap<>(); @UiField - protected DivElement title; + protected DivElement title; @UiField - protected DivElement root; + protected DivElement root; @UiField - protected DivElement container; + protected DivElement container; @UiField - protected DivElement logo; + protected DivElement logo; @UiField - Css style; + Css style; @Inject public EmptyEditorsPanel(ActionManager actionManager, @@ -85,8 +88,12 @@ public EmptyEditorsPanel(ActionManager actionManager, AppContext appContext, EventBus eventBus, Resources resources, - CoreLocalizationConstant localizationConstant) { - this(actionManager, perspectiveManagerProvider, keyBindingAgent, appContext, localizationConstant); + CoreLocalizationConstant localizationConstant, + NewFileAction newFileAction, + CreateProjectAction createProjectAction, + ImportProjectAction importProjectAction) { + this(actionManager, perspectiveManagerProvider, keyBindingAgent, appContext, localizationConstant, newFileAction, + createProjectAction, importProjectAction); eventBus.addHandler(ResourceChangedEvent.getType(), this); @@ -103,12 +110,22 @@ public EmptyEditorsPanel(ActionManager actionManager, Provider perspectiveManagerProvider, KeyBindingAgent keyBindingAgent, AppContext appContext, - CoreLocalizationConstant localizationConstant) { + CoreLocalizationConstant localizationConstant, + NewFileAction newFileAction, + CreateProjectAction createProjectAction, + ImportProjectAction importProjectAction) { this.actionManager = actionManager; this.perspectiveManagerProvider = perspectiveManagerProvider; this.keyBindingAgent = keyBindingAgent; this.appContext = appContext; this.localizationConstant = localizationConstant; + + noFiles.put("Create File...", newFileAction); + noFiles.put("Create Project...", createProjectAction); + + noProjects.put("Import Project...", importProjectAction); + noProjects.put("Create Project...", createProjectAction); + presentationFactory = new PresentationFactory(); Widget rootElement = ourUiBinder.createAndBindUi(this); @@ -142,40 +159,29 @@ private void updateOnProjectsChange() { } protected void renderNoProjects() { - DefaultActionGroup - actionGroup = (DefaultActionGroup)actionManager.getAction(IdeActions.GROUP_EMPTY_PROJECT_PANEL); - render(localizationConstant.emptyStateNoProjects(), actionGroup); + render(localizationConstant.emptyStateNoProjects(), noProjects); } protected void renderNoFiles() { - DefaultActionGroup - actionGroup = (DefaultActionGroup)actionManager.getAction(IdeActions.GROUP_EMPTY_EDITOR_PANEL); - render(localizationConstant.emptyStateNoFiles(), actionGroup); + render(localizationConstant.emptyStateNoFiles(), noFiles); } - private void render(String title, DefaultActionGroup actionGroup) { + private void render(String title, Map actions) { this.title.setInnerText(title); container.removeAllChildren(); Element listElement = Elements.createElement("ul", new String[] {style.list()}); - List visibleActionGroups = - Utils.renderActionGroup(actionGroup, presentationFactory, actionManager, perspectiveManagerProvider.get()); - List list = new ArrayList<>(); - for (Utils.VisibleActionGroup groupActions : visibleActionGroups) { - list.addAll(groupActions.getActionList()); - } - - for (Action action : list) { + for (Map.Entry pair : actions.entrySet()) { LIElement liElement = Elements.createLiElement(); - liElement.appendChild(renderAction(action)); + liElement.appendChild(renderAction(pair.getKey(), pair.getValue())); listElement.appendChild(liElement); } container.appendChild((com.google.gwt.dom.client.Node)listElement); } - private Node renderAction(final Action action) { + private Node renderAction(String title, final Action action) { final Presentation presentation = presentationFactory.getPresentation(action); Element divElement = Elements.createDivElement(style.listElement()); divElement.addEventListener("click", new EventListener() { @@ -187,8 +193,8 @@ public void handleEvent(Event evt) { }, true); divElement.getStyle().setCursor("pointer"); divElement.getStyle().setColor(Style.getOutputLinkColor()); - SpanElement label = Elements.createSpanElement(); - label.setInnerText(presentation.getText()); + Element label = Elements.createDivElement(style.actionLabel()); + label.setInnerText(title); divElement.appendChild(label); String hotKey = KeyMapUtil.getShortcutText(keyBindingAgent.getKeyBinding(actionManager.getId(action))); @@ -198,7 +204,7 @@ public void handleEvent(Event evt) { hotKey = " " + hotKey + " "; } - SpanElement hotKeyElement = Elements.createSpanElement(); + SpanElement hotKeyElement = Elements.createSpanElement(style.hotKey()); hotKeyElement.setInnerHTML(hotKey); divElement.appendChild(hotKeyElement); return divElement; @@ -214,6 +220,12 @@ interface Css extends CssResource { String child(); String listElement(); + + String title(); + + String hotKey(); + + String actionLabel(); } interface EmptyEditorsPanelUiBinder extends UiBinder {} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.ui.xml index 479c428da64..314d36a7007 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.ui.xml +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EmptyEditorsPanel.ui.xml @@ -15,6 +15,7 @@ @eval lineColor org.eclipse.che.ide.api.theme.Style.theme.iconColor(); + @eval fontColor org.eclipse.che.ide.api.theme.Style.getMainFontColor(); .center{ display: flex; justify-content: center; @@ -32,25 +33,35 @@ top: 50%; left: 50%; transform: translate(-50%, -50%); + width: 215px; } .list { padding-left: 26px; margin: 0; + margin-top: 5px; } .listElement{ - font-size: 11px; - margin-bottom: 2px; + font-size: 10px; + margin-bottom: 3px; } - .line{ - margin-top: 5px; - margin-bottom: 5px; + .title{ + padding-left: 8px; border-bottom: 1px solid lineColor; + font-size: 13px; + width: 138px; } - .title{ - margin-left: 8px; + .hotKey{ + border: 1px solid fontColor; + color: fontColor; + border-radius: 2px; + margin-left: 50px; + } + .actionLabel { + display: inline-block; + width: 77px; } @@ -58,7 +69,6 @@
-
diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java index ca9a1d29fbb..7bcc3876c62 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java @@ -64,6 +64,7 @@ public void setWidget(IsWidget widget) { if (relativePartStack == null) { rootView = splitEditorPartViewFactory.create(widget); splitEditorParts.put(partStack, rootView); + contentPanel.remove(emptyEditorsPanel); contentPanel.add(rootView); return; } @@ -89,6 +90,9 @@ public void removePartStack(@NotNull EditorPartStack partStack) { if (splitEditorPartView != null) { splitEditorPartView.removeFromParent(); } + if (splitEditorParts.size() == 0) { + contentPanel.add(emptyEditorsPanel); + } } @Override diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/EmptyTreePanel.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/EmptyTreePanel.java index e46479a362b..becd6c6a6f2 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/EmptyTreePanel.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/EmptyTreePanel.java @@ -16,11 +16,14 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; +import org.eclipse.che.ide.actions.CreateProjectAction; +import org.eclipse.che.ide.actions.ImportProjectAction; import org.eclipse.che.ide.api.action.ActionManager; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; import org.eclipse.che.ide.api.parts.PerspectiveManager; import org.eclipse.che.ide.api.resources.ResourceChangedEvent; +import org.eclipse.che.ide.newresource.NewFileAction; import org.eclipse.che.ide.part.editor.EmptyEditorsPanel; import javax.inject.Inject; @@ -36,8 +39,12 @@ public EmptyTreePanel(ActionManager actionManager, KeyBindingAgent keyBindingAgent, AppContext appContext, EventBus eventBus, - CoreLocalizationConstant localizationConstant) { - super(actionManager, perspectiveManagerProvider, keyBindingAgent, appContext, localizationConstant); + CoreLocalizationConstant localizationConstant, + NewFileAction newFileAction, + CreateProjectAction createProjectAction, + ImportProjectAction importProjectAction) { + super(actionManager, perspectiveManagerProvider, keyBindingAgent, appContext, localizationConstant, newFileAction, + createProjectAction, importProjectAction); eventBus.addHandler(ResourceChangedEvent.getType(), this); root.getStyle().setTop(46, Style.Unit.PX); Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @@ -53,7 +60,7 @@ public void onResourceChanged(ResourceChangedEvent event) { Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { - if(appContext.getProjects().length!= 0) { + if (appContext.getProjects().length != 0) { getElement().removeFromParent(); } } From 9b7909153f1edac41992122d2cd63e1fdb53a51a Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Wed, 23 Nov 2016 09:21:31 +0200 Subject: [PATCH 10/74] che#2550: replaced .codenvy folder to .che (#2919) Signed-off-by: Dmitry Kuleshov --- .../filetype/ExtensionFileTypeIdentifier.java | 2 +- .../eclipse/core/resources/ProjectScope.java | 2 +- .../jdt/internal/core/JavaProject.java | 3 +-- .../che/plugin/java/server/che/BaseTest.java | 2 +- .../jdt/testplugin/JavaProjectHelper.java | 2 +- .../multimoduleProject/.codenvy/project.json | 1 - .../subModule/.codenvy/classpath | 18 ------------------ .../subModule/.codenvy/project.json | 1 - .../test/.codenvy/classpath | 18 ------------------ .../test/.codenvy/project.json | 1 - .../projects/test/.codenvy/classpath | 19 ------------------- .../projects/test/.codenvy/classpath.maven | 1 - .../projects/test/.codenvy/project.json | 1 - .../plugin/java/plain/server/BaseTest.java | 2 +- .../projects/project/.codenvy/classpath | 4 ---- .../maven/server/core/MavenClasspathUtil.java | 2 +- .../server/rmi/MavenServerManagerTest.java | 2 +- .../che/api/git/GitConfigurationChecker.java | 6 +++--- .../api/git/GitConfigurationCheckerTest.java | 1 - .../che/api/project/shared/Constants.java | 2 +- .../api/project/server/ProjectApiModule.java | 1 - .../api/project/server/ProjectManager.java | 2 +- 22 files changed, 13 insertions(+), 80 deletions(-) delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/.codenvy/project.json delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/classpath delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/project.json delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/classpath delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/project.json delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath.maven delete mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/project.json delete mode 100644 plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/resources/projects/project/.codenvy/classpath diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/filetype/ExtensionFileTypeIdentifier.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/filetype/ExtensionFileTypeIdentifier.java index 5fce4f163c0..0681cbded14 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/filetype/ExtensionFileTypeIdentifier.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/filetype/ExtensionFileTypeIdentifier.java @@ -33,7 +33,7 @@ public List identifyType(final VirtualFile file) { final String filename = file.getName(); if (filename != null) { final int dotPos = filename.lastIndexOf('.'); - if (dotPos < 1) { // either -1 (not found) or 0 (first position, for example .project or .codenvy etc. + if (dotPos < 1) { // either -1 (not found) or 0 (first position, for example .project or .che etc. Log.debug(ExtensionFileTypeIdentifier.class, "File name has no suffix "); return null; } diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/src/main/java/org/eclipse/core/resources/ProjectScope.java b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/src/main/java/org/eclipse/core/resources/ProjectScope.java index c9ea2954cc5..94d8ea9bc0f 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/src/main/java/org/eclipse/core/resources/ProjectScope.java +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/src/main/java/org/eclipse/core/resources/ProjectScope.java @@ -74,7 +74,7 @@ public IEclipsePreferences getNode(String qualifier) { if(!cache.containsKey(context.getName())){ String pathToWorkspace = ResourcesPlugin.getPathToWorkspace(); IPath fullPath = context.getFullPath(); - cache.putIfAbsent(context.getName(), new ChePreferences(pathToWorkspace + fullPath + "/.codenvy/project.preferences")); + cache.putIfAbsent(context.getName(), new ChePreferences(pathToWorkspace + fullPath + "/.che/project.preferences")); } } } diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/src/main/java/org/eclipse/jdt/internal/core/JavaProject.java b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/src/main/java/org/eclipse/jdt/internal/core/JavaProject.java index 1538458750b..9cc024cd92f 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/src/main/java/org/eclipse/jdt/internal/core/JavaProject.java +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/src/main/java/org/eclipse/jdt/internal/core/JavaProject.java @@ -75,7 +75,6 @@ import java.io.OutputStreamWriter; import java.io.StringReader; import java.io.UnsupportedEncodingException; -import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -97,7 +96,7 @@ public class JavaProject extends Openable implements IJavaProject, SuffixConstan /** * Name of file containing project classpath */ - public static final String INNER_DIR = Constants.CODENVY_DIR; + public static final String INNER_DIR = Constants.CHE_DIR; public static final String CLASSPATH_FILENAME = INNER_DIR + "/classpath"; /** diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/che/BaseTest.java b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/che/BaseTest.java index 6b635a846ff..beb1b69fb72 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/che/BaseTest.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/che/BaseTest.java @@ -82,7 +82,7 @@ public void closeProject() throws Exception { if (project != null) { project.close(); } - File pref = new File(wsPath + "/test/.codenvy/project.preferences"); + File pref = new File(wsPath + "/test/.che/project.preferences"); if (pref.exists()) { pref.delete(); } diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/jdt/testplugin/JavaProjectHelper.java b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/jdt/testplugin/JavaProjectHelper.java index 6484b880a39..dfa24b8d041 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/jdt/testplugin/JavaProjectHelper.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/java/org/eclipse/che/plugin/java/server/jdt/testplugin/JavaProjectHelper.java @@ -139,7 +139,7 @@ public static IJavaProject createJavaProject(String projectName, String binFolde outputLocation = project.getFullPath(); } - IFolder codenvyFolder = project.getFolder(".codenvy"); + IFolder codenvyFolder = project.getFolder(".che"); if (!codenvyFolder.exists()) { CoreUtility.createFolder(codenvyFolder, false, true, null); } diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/.codenvy/project.json b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/.codenvy/project.json deleted file mode 100644 index 9b2d5f9c6ad..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/.codenvy/project.json +++ /dev/null @@ -1 +0,0 @@ -{"builders":{"default":"maven"},"runners":{"configs":{"recommend":{"variables":{},"ram":256,"options":{}}},"default":"system:/java/web/tomcat7"},"description":"A basic example using Spring servlets. The app returns values entered into a submit form.","type":"maven","attributes":{}} \ No newline at end of file diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/classpath b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/classpath deleted file mode 100644 index 0e576a91c4d..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/classpath +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/project.json b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/project.json deleted file mode 100644 index 9b2d5f9c6ad..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/subModule/.codenvy/project.json +++ /dev/null @@ -1 +0,0 @@ -{"builders":{"default":"maven"},"runners":{"configs":{"recommend":{"variables":{},"ram":256,"options":{}}},"default":"system:/java/web/tomcat7"},"description":"A basic example using Spring servlets. The app returns values entered into a submit form.","type":"maven","attributes":{}} \ No newline at end of file diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/classpath b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/classpath deleted file mode 100644 index 283b31b5bcb..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/classpath +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/project.json b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/project.json deleted file mode 100644 index 9b2d5f9c6ad..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/multimoduleProject/test/.codenvy/project.json +++ /dev/null @@ -1 +0,0 @@ -{"builders":{"default":"maven"},"runners":{"configs":{"recommend":{"variables":{},"ram":256,"options":{}}},"default":"system:/java/web/tomcat7"},"description":"A basic example using Spring servlets. The app returns values entered into a submit form.","type":"maven","attributes":{}} \ No newline at end of file diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath deleted file mode 100644 index 12b0495eb3b..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath.maven b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath.maven deleted file mode 100644 index 5552efd2f1f..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/classpath.maven +++ /dev/null @@ -1 +0,0 @@ -/home/evgen/java/dependency/junit/junit/4.10/junit-4.10.jar:/home/evgen/java/dependency/org/hamcrest/hamcrest-core/1.1/hamcrest-core-1.1.jar:/home/evgen/java/dependency/org/easytesting/fest-assert/1.4/fest-assert-1.4.jar:/home/evgen/java/dependency/org/easytesting/fest-util/1.1.6/fest-util-1.1.6.jar:/home/evgen/java/dependency/org/mockito/mockito-core/1.9.5/mockito-core-1.9.5.jar:/home/evgen/java/dependency/org/objenesis/objenesis/1.0/objenesis-1.0.jar \ No newline at end of file diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/project.json b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/project.json deleted file mode 100644 index 9b2d5f9c6ad..00000000000 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/test/resources/projects/test/.codenvy/project.json +++ /dev/null @@ -1 +0,0 @@ -{"builders":{"default":"maven"},"runners":{"configs":{"recommend":{"variables":{},"ram":256,"options":{}}},"default":"system:/java/web/tomcat7"},"description":"A basic example using Spring servlets. The app returns values entered into a submit form.","type":"maven","attributes":{}} \ No newline at end of file diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java index 9f243430797..d1f7279268c 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/java/org/eclipse/che/plugin/java/plain/server/BaseTest.java @@ -137,7 +137,7 @@ protected FolderEntry createTestProject() throws ServerException, NotFoundExcept FolderEntry parent = projectManager.getProjectsRoot().createFolder("project"); parent.createFolder("bin"); parent.createFolder("src"); - FolderEntry codenvyFolder = parent.createFolder(".codenvy"); + FolderEntry codenvyFolder = parent.createFolder(".che"); FolderEntry libFolder = parent.createFolder("lib"); libFolder.createFile("a.jar", "text".getBytes()); diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/resources/projects/project/.codenvy/classpath b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/resources/projects/project/.codenvy/classpath deleted file mode 100644 index c19ea02e13f..00000000000 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/test/resources/projects/project/.codenvy/classpath +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenClasspathUtil.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenClasspathUtil.java index f1d19631a82..03c23b9cc98 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenClasspathUtil.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenClasspathUtil.java @@ -31,7 +31,7 @@ public class MavenClasspathUtil { private static final Logger LOG = LoggerFactory.getLogger(MavenClasspathUtil.class); public static IClasspathContainer readMavenClasspath(IJavaProject javaProject) { - IFile file = javaProject.getProject().getFile(".codenvy/classpath.maven"); + IFile file = javaProject.getProject().getFile(".che/classpath.maven"); IClasspathEntry[] entries; if (file.exists()) { try { diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/rmi/MavenServerManagerTest.java b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/rmi/MavenServerManagerTest.java index 0e4210a9c7d..8f1e8dcfb86 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/rmi/MavenServerManagerTest.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/test/java/org/eclipse/che/plugin/maven/server/rmi/MavenServerManagerTest.java @@ -55,7 +55,7 @@ public class MavenServerManagerTest { @BeforeMethod public void setUp() throws Exception { workspaceCache = new MavenWorkspaceCache(); - workspaceCache.put(new MavenKey("com.codenvy.ide", "codenvy-ide-subModule", "1.0.0-TEST-SNAPSHOT"), + workspaceCache.put(new MavenKey("org.eclipse.che", "che-ide-subModule", "1.0.0-TEST-SNAPSHOT"), new File(MavenServerManagerTest.class.getResource("/multimoduleProject/subModule/pom.xml").getFile())); mavenServer = manager.createMavenServer(); mavenServer.customize(workspaceCache, new MyMavenTerminal(), new MyMavenServerProgressNotifier(), true, false); diff --git a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitConfigurationChecker.java b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitConfigurationChecker.java index d9723a997bc..f0ca1804589 100644 --- a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitConfigurationChecker.java +++ b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitConfigurationChecker.java @@ -33,7 +33,7 @@ * * Here we check that we have correct setting for git ignore. * Must be ignored files : - * .codenvy/misc.xml + * .che/misc.xml * .vfs/ * like system files for Codenvy * @@ -55,7 +55,7 @@ public GitConfigurationChecker() { GLOBAL_GITCONFIG_FILE_PATH = Paths.get(System.getProperty("user.home") + "/.gitconfig"); DEFAULT_GITIGNORE_FILE_PATH = Paths.get(System.getProperty("user.home") + "/.gitignore_codenvy"); - GITIGNORE_PATTERNS.add(Constants.CODENVY_DIR + "/"); + GITIGNORE_PATTERNS.add(Constants.CHE_DIR + "/"); GITIGNORE_PATTERNS.add(".che/"); GITIGNORE_PATTERNS.add(".vfs/"); } @@ -65,7 +65,7 @@ public GitConfigurationChecker() { GLOBAL_GITCONFIG_FILE_PATH = globalGitconfigFilePath; DEFAULT_GITIGNORE_FILE_PATH = gitIgnoreFilePath; - GITIGNORE_PATTERNS.add(Constants.CODENVY_DIR + "/"); + GITIGNORE_PATTERNS.add(Constants.CHE_DIR + "/"); GITIGNORE_PATTERNS.add(".che/"); GITIGNORE_PATTERNS.add(".vfs/"); } diff --git a/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitConfigurationCheckerTest.java b/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitConfigurationCheckerTest.java index f00d937365a..d0e526957a2 100644 --- a/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitConfigurationCheckerTest.java +++ b/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitConfigurationCheckerTest.java @@ -28,7 +28,6 @@ public class GitConfigurationCheckerTest { private static final String GITIGNORE_FILE_CONTENT = "\n" + "# Codenvy files\n" - + ".codenvy/\n" + ".che/\n" + ".vfs/\n"; private GitConfigurationChecker checker; diff --git a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java index b7ffbca2278..1a8b8f617fc 100644 --- a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java +++ b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java @@ -31,7 +31,7 @@ public class Constants { public static final String LINK_REL_PROJECT_TYPES = "project types"; - public static final String CODENVY_DIR = ".codenvy"; + public static final String CHE_DIR = ".che"; private Constants() { } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java index 0219c47e2e6..bdfdd72b350 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java @@ -92,7 +92,6 @@ protected void configure() { private void configureVfsFilters(Multibinder excludeMatcher) { addVfsFilter(excludeMatcher, ".che"); - addVfsFilter(excludeMatcher, ".codenvy"); addVfsFilter(excludeMatcher, ".#"); } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java index a63bd8ded42..3e6925e3056 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java @@ -112,7 +112,7 @@ public ProjectManager(VirtualFileSystemProvider vfsProvider, @PostConstruct void initWatcher() throws IOException { FileWatcherNotificationListener defaultListener = - new FileWatcherNotificationListener(file -> !(file.getPath().toString().contains(".codenvy") + new FileWatcherNotificationListener(file -> !(file.getPath().toString().contains(".che") || file.getPath().toString().contains(".#"))) { @Override public void onFileWatcherEvent(VirtualFile virtualFile, FileWatcherEventType eventType) { From fb8a6c8820d7cafadeb49b8a55bf1e82032366c1 Mon Sep 17 00:00:00 2001 From: Yevhenii Voevodin Date: Wed, 23 Nov 2016 11:03:22 +0200 Subject: [PATCH 11/74] Rework database schema (#3063) --- .gitignore | 1 - assembly/assembly-wsmaster-war/pom.xml | 41 +- .../che/api/deploy/WsMasterModule.java | 41 +- .../main/resources/META-INF/persistence.xml | 4 +- .../WEB-INF/classes/codenvy/che.properties | 10 + .../eclipselink/DescriptorEventAdapter.java | 83 ---- ...tyListenerInjectionManagerInitializer.java | 33 -- .../pom.xml | 10 +- .../che/core/db/h2/H2DataSourceProvider.java} | 22 +- .../jpa/eclipselink/H2ExceptionHandler.java | 6 +- .../pom.xml | 18 +- .../PostgreSqlExceptionHandler.java | 40 ++ core/che-core-db/pom.xml | 84 ++++ .../org/eclipse/che/core/db}/DBErrorCode.java | 2 +- .../eclipse/che/core/db/DBInitializer.java | 63 +++ .../che/core/db/JndiDataSourceProvider.java | 41 ++ .../core/db}/event/CascadeRemovalEvent.java | 2 +- .../event/CascadeRemovalEventSubscriber.java | 2 +- .../che/core/db}/event/RemovalContext.java | 2 +- .../core/db}/jpa/CascadeRemovalException.java | 2 +- .../db}/jpa/DetailedRollbackException.java | 4 +- .../core/db}/jpa/DuplicateKeyException.java | 4 +- ...IntegrityConstraintViolationException.java | 8 +- .../che/core/db/jpa/JpaInitializer.java | 27 ++ .../GuiceEntityListenerInjectionManager.java | 11 +- .../db/jpa/guice/GuiceJpaInitializer.java} | 25 +- .../schema/SchemaInitializationException.java | 27 ++ .../che/core/db/schema/SchemaInitializer.java | 27 ++ .../flyway/CustomSqlMigrationResolver.java | 204 +++++++++ .../impl/flyway/FlywaySchemaInitializer.java | 121 +++++ .../flyway/PlaceholderReplacerProvider.java | 37 ++ .../schema/impl/flyway/ResourcesFinder.java | 58 +++ .../core/db/schema/impl/flyway/SqlScript.java | 76 ++++ .../schema/impl/flyway/SqlScriptCreator.java | 57 +++ .../schema/impl/flyway/VersionResolver.java | 80 ++++ .../flyway/FlywaySchemaInitializerTest.java | 339 ++++++++++++++ .../impl/flyway/ResourcesFinderTest.java | 150 +++++++ .../impl/flyway/SqlScriptCreatorTest.java | 67 +++ .../impl/flyway/VersionResolverTest.java | 83 ++++ .../src/test/resources/logback-test.xml | 34 ++ .../src/test/resources/sql/1.0/1.init.sql | 17 + .../src/test/resources/sql/1.0/2.add_data.sql | 14 + .../resources/sql/2.0/1.modify_test_table.sql | 11 + .../2.0/postgresql/1.modify_test_table.sql | 11 + core/commons/che-core-commons-test/pom.xml | 4 + .../che/commons/test/db/H2JpaCleaner.java | 46 ++ .../che/commons/test/db/H2TestHelper.java | 56 +++ .../che/commons/test/tck/TckListener.java | 4 +- ...Listener.java => TestListenerAdapter.java} | 2 +- .../test/tck/repository/JpaTckRepository.java | 4 +- .../commons/test/tck/DBServerListener.java | 2 +- core/pom.xml | 5 +- pom.xml | 35 +- wsmaster/che-core-api-account/pom.xml | 36 +- .../event/BeforeAccountRemovedEvent.java | 2 +- .../eclipse/che/account/spi/AccountImpl.java | 10 +- .../spi/jpa/AccountEntityListener.java | 2 +- .../spi/tck/jpa/AccountJpaTckModule.java | 16 +- .../test/resources/META-INF/persistence.xml | 5 +- wsmaster/che-core-api-factory/pom.xml | 22 +- .../che/api/factory/server/FactoryImage.java | 8 +- .../api/factory/server/jpa/JpaFactoryDao.java | 6 +- .../factory/server/model/impl/ActionImpl.java | 12 +- .../factory/server/model/impl/AuthorImpl.java | 8 +- .../model/impl/ButtonAttributesImpl.java | 14 +- .../factory/server/model/impl/ButtonImpl.java | 5 + .../server/model/impl/FactoryImpl.java | 19 +- .../factory/server/model/impl/IdeImpl.java | 8 + .../server/model/impl/OnAppClosedImpl.java | 9 + .../server/model/impl/OnAppLoadedImpl.java | 9 + .../model/impl/OnProjectsLoadedImpl.java | 9 + .../server/model/impl/PoliciesImpl.java | 6 +- .../server/jpa/FactoryJpaTckRepository.java | 51 --- .../api/factory/server/jpa/JpaTckModule.java | 59 --- ...org.eclipse.che.commons.test.tck.TckModule | 1 - wsmaster/che-core-api-machine/pom.xml | 37 +- .../event/BeforeRecipeRemovedEvent.java | 2 +- .../api/machine/server/jpa/JpaRecipeDao.java | 4 +- .../machine/server/jpa/JpaSnapshotDao.java | 2 +- .../server/jpa/RecipeEntityListener.java | 2 +- .../server/model/impl/CommandImpl.java | 12 +- .../server/model/impl/MachineSourceImpl.java | 5 +- .../server/model/impl/SnapshotImpl.java | 19 +- .../api/machine/server/recipe/RecipeImpl.java | 18 +- .../api/machine/server/jpa/JpaTckModule.java | 34 +- .../server/jpa/TestWorkspaceEntity.java | 116 +++++ .../server/spi/tck/SnapshotDaoTest.java | 71 ++- .../test/resources/META-INF/persistence.xml | 8 +- wsmaster/che-core-api-ssh/pom.xml | 43 +- .../che/api/ssh/server/jpa/JpaSshDao.java | 4 +- .../ssh/server/model/impl/SshPairImpl.java | 9 +- .../che/api/ssh/server/jpa/SshTckModule.java | 20 +- .../test/resources/META-INF/persistence.xml | 7 +- wsmaster/che-core-api-user/pom.xml | 38 +- .../che/api/user/server/CheUserCreator.java | 8 +- .../server/event/BeforeUserRemovedEvent.java | 2 +- .../api/user/server/jpa/JpaPreferenceDao.java | 2 +- .../api/user/server/jpa/JpaProfileDao.java | 6 +- .../che/api/user/server/jpa/JpaUserDao.java | 4 +- .../api/user/server/jpa/PreferenceEntity.java | 13 +- .../user/server/jpa/UserEntityListener.java | 2 +- .../user/server/model/impl/ProfileImpl.java | 7 +- .../api/user/server/model/impl/UserImpl.java | 10 +- .../che/api/user/server/jpa/JpaTckModule.java | 22 +- .../test/resources/META-INF/persistence.xml | 5 +- wsmaster/che-core-api-workspace/pom.xml | 34 +- .../server/event/BeforeStackRemovedEvent.java | 2 +- .../event/BeforeWorkspaceRemovedEvent.java | 2 +- .../api/workspace/server/jpa/JpaStackDao.java | 2 +- .../workspace/server/jpa/JpaWorkspaceDao.java | 39 +- .../server/jpa/StackEntityListener.java | 2 +- .../server/jpa/WorkspaceEntityListener.java | 2 +- .../server/model/impl/EnvironmentImpl.java | 8 +- .../model/impl/EnvironmentRecipeImpl.java | 8 +- .../model/impl/ExtendedMachineImpl.java | 16 +- .../server/model/impl/ProjectConfigImpl.java | 26 +- .../server/model/impl/ServerConf2Impl.java | 16 +- .../server/model/impl/SourceStorageImpl.java | 14 +- .../model/impl/WorkspaceConfigImpl.java | 17 +- .../server/model/impl/WorkspaceImpl.java | 29 +- .../model/impl/stack/StackComponentImpl.java | 5 +- .../server/model/impl/stack/StackImpl.java | 18 +- .../model/impl/stack/StackSourceImpl.java | 5 +- .../workspace/server/stack/StackLoader.java | 4 +- .../server/stack/image/StackIcon.java | 4 +- .../server/jpa/JpaWorkspaceDaoTest.java | 8 +- .../server/jpa/WorkspaceTckModule.java | 15 +- .../test/resources/META-INF/persistence.xml | 6 +- wsmaster/che-core-sql-schema/pom.xml | 23 + .../resources/che-schema/5.0.0-M8/1__init.sql | 424 ++++++++++++++++++ .../integration-tests/cascade-removal/pom.xml | 152 +++++++ .../che/core/db/jpa/CascadeRemovalTest.java | 63 +-- .../che/core/db/jpa}/TestObjectsFactory.java | 18 +- .../test/resources/META-INF/persistence.xml | 29 +- wsmaster/integration-tests/pom.xml | 29 ++ .../integration-tests/postgresql-tck/pom.xml | 295 ++++++++++++ .../src/test/java/PostgreSqlTckModule.java | 232 ++++++++++ .../test/resources/META-INF/persistence.xml | 45 ++ ...org.eclipse.che.commons.test.tck.TckModule | 1 + .../src/test/resources/logback-test.xml | 25 ++ wsmaster/pom.xml | 2 + wsmaster/wsmaster-local/pom.xml | 57 +++ .../api/local/LocalToJpaDataMigratorTest.java | 137 ++++-- .../test/resources/META-INF/persistence.xml | 19 +- 144 files changed, 4116 insertions(+), 723 deletions(-) delete mode 100644 core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/DescriptorEventAdapter.java delete mode 100644 core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/EntityListenerInjectionManagerInitializer.java rename core/{che-core-api-jdbc-vendor-h2 => che-core-db-vendor-h2}/pom.xml (79%) rename core/{che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc/jpa/guice/CheJpaInitializer.java => che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2/H2DataSourceProvider.java} (65%) rename core/{che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc => che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2}/jpa/eclipselink/H2ExceptionHandler.java (88%) rename core/{che-core-api-jdbc => che-core-db-vendor-postgresql}/pom.xml (65%) create mode 100644 core/che-core-db-vendor-postgresql/src/main/java/org/eclipse/che/core/db/postgresql/jpa/eclipselink/PostgreSqlExceptionHandler.java create mode 100644 core/che-core-db/pom.xml rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc => che-core-db/src/main/java/org/eclipse/che/core/db}/DBErrorCode.java (97%) create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/DBInitializer.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/JndiDataSourceProvider.java rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa => che-core-db/src/main/java/org/eclipse/che/core/db}/event/CascadeRemovalEvent.java (94%) rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa => che-core-db/src/main/java/org/eclipse/che/core/db}/event/CascadeRemovalEventSubscriber.java (96%) rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa => che-core-db/src/main/java/org/eclipse/che/core/db}/event/RemovalContext.java (95%) rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc => che-core-db/src/main/java/org/eclipse/che/core/db}/jpa/CascadeRemovalException.java (95%) rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc => che-core-db/src/main/java/org/eclipse/che/core/db}/jpa/DetailedRollbackException.java (91%) rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc => che-core-db/src/main/java/org/eclipse/che/core/db}/jpa/DuplicateKeyException.java (90%) rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc => che-core-db/src/main/java/org/eclipse/che/core/db}/jpa/IntegrityConstraintViolationException.java (79%) create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/JpaInitializer.java rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc => che-core-db/src/main/java/org/eclipse/che/core/db}/jpa/eclipselink/GuiceEntityListenerInjectionManager.java (87%) rename core/{che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/guice/JpaInitializer.java => che-core-db/src/main/java/org/eclipse/che/core/db/jpa/guice/GuiceJpaInitializer.java} (58%) create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializationException.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializer.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/CustomSqlMigrationResolver.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializer.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/PlaceholderReplacerProvider.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinder.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScript.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreator.java create mode 100644 core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolver.java create mode 100644 core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializerTest.java create mode 100644 core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinderTest.java create mode 100644 core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreatorTest.java create mode 100644 core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolverTest.java create mode 100644 core/che-core-db/src/test/resources/logback-test.xml create mode 100644 core/che-core-db/src/test/resources/sql/1.0/1.init.sql create mode 100644 core/che-core-db/src/test/resources/sql/1.0/2.add_data.sql create mode 100644 core/che-core-db/src/test/resources/sql/2.0/1.modify_test_table.sql create mode 100644 core/che-core-db/src/test/resources/sql/2.0/postgresql/1.modify_test_table.sql create mode 100644 core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2JpaCleaner.java create mode 100644 core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2TestHelper.java rename core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/{AbstractTestListener.java => TestListenerAdapter.java} (95%) delete mode 100644 wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryJpaTckRepository.java delete mode 100644 wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/JpaTckModule.java delete mode 100644 wsmaster/che-core-api-factory/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule create mode 100644 wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/TestWorkspaceEntity.java create mode 100644 wsmaster/che-core-sql-schema/pom.xml create mode 100644 wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M8/1__init.sql create mode 100644 wsmaster/integration-tests/cascade-removal/pom.xml rename assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/jdbc/jpa/JpaEntitiesCascadeRemovalTest.java => wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java (81%) rename {assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api => wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa}/TestObjectsFactory.java (88%) rename wsmaster/{che-core-api-factory => integration-tests/cascade-removal}/src/test/resources/META-INF/persistence.xml (65%) create mode 100644 wsmaster/integration-tests/pom.xml create mode 100644 wsmaster/integration-tests/postgresql-tck/pom.xml create mode 100644 wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java create mode 100644 wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/persistence.xml create mode 100644 wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule create mode 100644 wsmaster/integration-tests/postgresql-tck/src/test/resources/logback-test.xml rename {assembly/assembly-wsmaster-war => wsmaster/wsmaster-local}/src/test/java/org/eclipse/che/api/local/LocalToJpaDataMigratorTest.java (64%) rename {assembly/assembly-wsmaster-war => wsmaster/wsmaster-local}/src/test/resources/META-INF/persistence.xml (72%) diff --git a/.gitignore b/.gitignore index ebad3a75fe5..193322c7c7b 100644 --- a/.gitignore +++ b/.gitignore @@ -48,7 +48,6 @@ config/ # Logs and databases # ###################### *.log -*.sql *.sqlite # OS generated files # diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index 7be3f3c518f..4c4a934035c 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -70,14 +70,6 @@ org.eclipse.che.core che-core-api-core - - org.eclipse.che.core - che-core-api-jdbc - - - org.eclipse.che.core - che-core-api-jdbc-vendor-h2 - org.eclipse.che.core che-core-api-machine @@ -110,6 +102,18 @@ org.eclipse.che.core che-core-commons-inject + + org.eclipse.che.core + che-core-db + + + org.eclipse.che.core + che-core-db-vendor-h2 + + + org.eclipse.che.core + che-core-sql-schema + org.eclipse.che.core wsmaster-local @@ -162,6 +166,10 @@ org.everrest everrest-websockets + + org.flywaydb + flyway-core + javax.servlet javax.servlet-api @@ -182,6 +190,11 @@ che-core-api-factory test + + org.eclipse.che.core + che-core-commons-test + test + org.mockito mockito-all @@ -210,6 +223,18 @@ true + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 9f9117d232d..290d8ff3494 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -13,27 +13,21 @@ import com.google.inject.AbstractModule; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; -import com.google.inject.persist.jpa.JpaPersistModule; -import org.eclipse.che.account.api.AccountModule; import org.eclipse.che.api.agent.server.launcher.AgentLauncher; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; import org.eclipse.che.api.core.rest.CheJsonProvider; import org.eclipse.che.api.core.rest.MessageBodyAdapter; import org.eclipse.che.api.core.rest.MessageBodyAdapterInterceptor; -import org.eclipse.che.api.machine.server.jpa.MachineJpaModule; import org.eclipse.che.api.machine.shared.Constants; -import org.eclipse.che.api.ssh.server.jpa.SshJpaModule; -import org.eclipse.che.api.user.server.CheUserCreator; import org.eclipse.che.api.user.server.TokenValidator; -import org.eclipse.che.api.user.server.jpa.UserJpaModule; import org.eclipse.che.api.workspace.server.WorkspaceConfigMessageBodyAdapter; import org.eclipse.che.api.workspace.server.WorkspaceMessageBodyAdapter; -import org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule; import org.eclipse.che.api.workspace.server.stack.StackMessageBodyAdapter; +import org.eclipse.che.core.db.schema.SchemaInitializer; import org.eclipse.che.inject.DynaModule; -import org.eclipse.che.plugin.docker.compose.ComposeModule; +import org.flywaydb.core.internal.util.PlaceholderReplacer; + +import javax.sql.DataSource; import static com.google.inject.matcher.Matchers.subclassesOf; import static org.eclipse.che.inject.Matchers.names; @@ -43,17 +37,24 @@ public class WsMasterModule extends AbstractModule { @Override protected void configure() { + // db related components modules + install(new com.google.inject.persist.jpa.JpaPersistModule("main")); + install(new org.eclipse.che.account.api.AccountModule()); + install(new org.eclipse.che.api.user.server.jpa.UserJpaModule()); + install(new org.eclipse.che.api.ssh.server.jpa.SshJpaModule()); + install(new org.eclipse.che.api.machine.server.jpa.MachineJpaModule()); + install(new org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule()); + + // db configuration + bind(DataSource.class).toProvider(org.eclipse.che.core.db.h2.H2DataSourceProvider.class); + bind(SchemaInitializer.class).to(org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer.class); + bind(org.eclipse.che.core.db.DBInitializer.class).asEagerSingleton(); + bind(PlaceholderReplacer.class).toProvider(org.eclipse.che.core.db.schema.impl.flyway.PlaceholderReplacerProvider.class); + + install(new org.eclipse.che.plugin.docker.compose.ComposeModule()); + + bind(org.eclipse.che.api.user.server.CheUserCreator.class); - install(new JpaPersistModule("main")); - bind(JpaInitializer.class).to(org.eclipse.che.api.core.h2.jdbc.jpa.guice.CheJpaInitializer.class).asEagerSingleton(); - bind(CheUserCreator.class); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); - install(new UserJpaModule()); - install(new SshJpaModule()); - install(new WorkspaceJpaModule()); - install(new AccountModule()); - install(new MachineJpaModule()); - install(new ComposeModule()); bind(TokenValidator.class).to(org.eclipse.che.api.local.DummyTokenValidator.class); bind(org.eclipse.che.api.local.LocalDataMigrator.class).asEagerSingleton(); diff --git a/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml b/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml index e993380aa4d..f6d0d510ade 100644 --- a/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml +++ b/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml @@ -42,10 +42,8 @@ true - + - - 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 20743cecb18..a1ec63e456d 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 @@ -210,3 +210,13 @@ org.everrest.asynchronous.cache.size=1024 # Path to asynchronous service org.everrest.asynchronous.service.path=/async/ + +# DB initialization and migration configuration +db.schema.flyway.baseline.enabled=true +db.schema.flyway.baseline.version=5.0.0.8.1 +db.schema.flyway.scripts.prefix= +db.schema.flyway.scripts.suffix=.sql +db.schema.flyway.scripts.version_separator=__ +db.schema.flyway.scripts.locations=classpath:che-schema + +db.jndi.datasource.name=java:/comp/env/jdbc/che diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/DescriptorEventAdapter.java b/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/DescriptorEventAdapter.java deleted file mode 100644 index cf577bbb6e3..00000000000 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/DescriptorEventAdapter.java +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa.eclipselink; - -import org.eclipse.persistence.descriptors.DescriptorEvent; -import org.eclipse.persistence.descriptors.DescriptorEventListener; - -import java.util.Vector; - -/** - * Adapter class for receiving EclipseLink events. - * The methods are empty, this class allows to implement - * only needed methods. - * - * @author Yevhenii Voevodin - */ -public abstract class DescriptorEventAdapter implements DescriptorEventListener { - - @Override - public void aboutToDelete(DescriptorEvent event) {} - - @Override - public void aboutToInsert(DescriptorEvent event) {} - - @Override - public void aboutToUpdate(DescriptorEvent event) {} - - @Override - public boolean isOverriddenEvent(DescriptorEvent event, Vector eventManagers) { return false; } - - @Override - public void postBuild(DescriptorEvent event) {} - - @Override - public void postClone(DescriptorEvent event) {} - - @Override - public void postDelete(DescriptorEvent event) {} - - @Override - public void postInsert(DescriptorEvent event) {} - - @Override - public void postMerge(DescriptorEvent event) {} - - @Override - public void postRefresh(DescriptorEvent event) {} - - @Override - public void postUpdate(DescriptorEvent event) {} - - @Override - public void postWrite(DescriptorEvent event) {} - - @Override - public void preDelete(DescriptorEvent event) {} - - @Override - public void preInsert(DescriptorEvent event) {} - - @Override - public void prePersist(DescriptorEvent event) {} - - @Override - public void preRemove(DescriptorEvent event) {} - - @Override - public void preUpdate(DescriptorEvent event) {} - - @Override - public void preUpdateWithChanges(DescriptorEvent event) {} - - @Override - public void preWrite(DescriptorEvent event) {} -} diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/EntityListenerInjectionManagerInitializer.java b/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/EntityListenerInjectionManagerInitializer.java deleted file mode 100644 index f80e2227c04..00000000000 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/EntityListenerInjectionManagerInitializer.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa.eclipselink; - -import com.google.inject.Inject; -import com.google.inject.Singleton; - -import org.eclipse.persistence.sessions.server.ServerSession; - -import javax.persistence.EntityManagerFactory; - -/** - * Sets up {@link GuiceEntityListenerInjectionManager}. - * - * @author Yevhenii Voevodin - */ -@Singleton -public class EntityListenerInjectionManagerInitializer { - - @Inject - public EntityListenerInjectionManagerInitializer(GuiceEntityListenerInjectionManager injManager, EntityManagerFactory emFactory) { - final ServerSession session = emFactory.unwrap(ServerSession.class); - session.setEntityListenerInjectionManager(injManager); - } -} diff --git a/core/che-core-api-jdbc-vendor-h2/pom.xml b/core/che-core-db-vendor-h2/pom.xml similarity index 79% rename from core/che-core-api-jdbc-vendor-h2/pom.xml rename to core/che-core-db-vendor-h2/pom.xml index 5e4b5af7aa7..4a4fd45a745 100644 --- a/core/che-core-api-jdbc-vendor-h2/pom.xml +++ b/core/che-core-db-vendor-h2/pom.xml @@ -18,20 +18,16 @@ org.eclipse.che.core 5.0.0-M8-SNAPSHOT - che-core-api-jdbc-vendor-h2 - Che Core :: API :: JDBC Vendor H2 + che-core-db-vendor-h2 + Che Core :: DB :: Vendor H2 - - com.google.inject.extensions - guice-persist - javax.inject javax.inject org.eclipse.che.core - che-core-api-jdbc + che-core-db org.eclipse.persistence diff --git a/core/che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc/jpa/guice/CheJpaInitializer.java b/core/che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2/H2DataSourceProvider.java similarity index 65% rename from core/che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc/jpa/guice/CheJpaInitializer.java rename to core/che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2/H2DataSourceProvider.java index 9451ba93325..ced7c81c14f 100644 --- a/core/che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc/jpa/guice/CheJpaInitializer.java +++ b/core/che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2/H2DataSourceProvider.java @@ -8,33 +8,33 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.h2.jdbc.jpa.guice; +package org.eclipse.che.core.db.h2; -import com.google.inject.persist.PersistService; - -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; +import org.eclipse.che.core.db.JndiDataSourceProvider; import javax.inject.Inject; import javax.inject.Named; -import javax.inject.Singleton; +import javax.inject.Provider; +import javax.sql.DataSource; import java.nio.file.Paths; /** - * Provides H2 specific initialization of persistent engine. + * Provides data source for h2 database. * - * @author Anton Korneta. + * @author Yevhenii Voevodin */ -@Singleton -public class CheJpaInitializer extends JpaInitializer { +public class H2DataSourceProvider implements Provider { @Inject @Named("che.database") private String storageRoot; @Inject + private JndiDataSourceProvider jndiDataSourceProvider; + @Override - public void init(PersistService persistService) { + public DataSource get() { System.setProperty("h2.baseDir", Paths.get(storageRoot).resolve("db").toString()); - super.init(persistService); + return jndiDataSourceProvider.get(); } } diff --git a/core/che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc/jpa/eclipselink/H2ExceptionHandler.java b/core/che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2/jpa/eclipselink/H2ExceptionHandler.java similarity index 88% rename from core/che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc/jpa/eclipselink/H2ExceptionHandler.java rename to core/che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2/jpa/eclipselink/H2ExceptionHandler.java index 4e074caf071..4e458178503 100644 --- a/core/che-core-api-jdbc-vendor-h2/src/main/java/org/eclipse/che/api/core/h2/jdbc/jpa/eclipselink/H2ExceptionHandler.java +++ b/core/che-core-db-vendor-h2/src/main/java/org/eclipse/che/core/db/h2/jpa/eclipselink/H2ExceptionHandler.java @@ -8,10 +8,10 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.h2.jdbc.jpa.eclipselink; +package org.eclipse.che.core.db.h2.jpa.eclipselink; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; -import org.eclipse.che.api.core.jdbc.jpa.IntegrityConstraintViolationException; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException; import org.eclipse.persistence.exceptions.DatabaseException; import org.eclipse.persistence.exceptions.ExceptionHandler; diff --git a/core/che-core-api-jdbc/pom.xml b/core/che-core-db-vendor-postgresql/pom.xml similarity index 65% rename from core/che-core-api-jdbc/pom.xml rename to core/che-core-db-vendor-postgresql/pom.xml index 77dc8cb167d..67e01d807b6 100644 --- a/core/che-core-api-jdbc/pom.xml +++ b/core/che-core-db-vendor-postgresql/pom.xml @@ -18,28 +18,16 @@ org.eclipse.che.core 5.0.0-M8-SNAPSHOT - che-core-api-jdbc - Che Core :: API :: JDBC + che-core-db-vendor-postgresql + Che Core :: DB :: Vendor PostgreSQL - - com.google.inject - guice - - - com.google.inject.extensions - guice-persist - org.eclipse.che.core - che-core-api-core + che-core-db org.eclipse.persistence eclipselink - - org.eclipse.persistence - javax.persistence - diff --git a/core/che-core-db-vendor-postgresql/src/main/java/org/eclipse/che/core/db/postgresql/jpa/eclipselink/PostgreSqlExceptionHandler.java b/core/che-core-db-vendor-postgresql/src/main/java/org/eclipse/che/core/db/postgresql/jpa/eclipselink/PostgreSqlExceptionHandler.java new file mode 100644 index 00000000000..d5455e218b6 --- /dev/null +++ b/core/che-core-db-vendor-postgresql/src/main/java/org/eclipse/che/core/db/postgresql/jpa/eclipselink/PostgreSqlExceptionHandler.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.postgresql.jpa.eclipselink; + +import org.eclipse.che.core.db.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException; +import org.eclipse.persistence.exceptions.DatabaseException; +import org.eclipse.persistence.exceptions.ExceptionHandler; + +import java.sql.SQLException; + +/** + * Rethrows vendor specific exceptions as common exceptions. + * See PostgreSQL error codes. + * + * @author Yevhenii Voevodin + * @author Sergii Kabashniuk + */ +public class PostgreSqlExceptionHandler implements ExceptionHandler { + public Object handleException(RuntimeException exception) { + if (exception instanceof DatabaseException && exception.getCause() instanceof SQLException) { + final SQLException sqlEx = (SQLException)exception.getCause(); + switch (sqlEx.getSQLState()) { + case "23505": + throw new DuplicateKeyException(exception.getMessage(), exception); + case "23503": + throw new IntegrityConstraintViolationException(exception.getMessage(), exception); + } + } + throw exception; + } +} diff --git a/core/che-core-db/pom.xml b/core/che-core-db/pom.xml new file mode 100644 index 00000000000..e55dff20c90 --- /dev/null +++ b/core/che-core-db/pom.xml @@ -0,0 +1,84 @@ + + + + 4.0.0 + + che-core-parent + org.eclipse.che.core + 5.0.0-M8-SNAPSHOT + + che-core-db + Che Core :: DB + + + com.google.guava + guava + + + com.google.inject + guice + + + com.google.inject.extensions + guice-persist + + + javax.inject + javax.inject + + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-commons-inject + + + org.eclipse.che.core + che-core-commons-lang + + + org.eclipse.persistence + eclipselink + + + org.eclipse.persistence + javax.persistence + + + org.flywaydb + flyway-core + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + test + + + com.h2database + h2 + test + + + org.testng + testng + test + + + diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/DBErrorCode.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/DBErrorCode.java similarity index 97% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/DBErrorCode.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/DBErrorCode.java index 236f077a258..e6a29c9a017 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/DBErrorCode.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/DBErrorCode.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc; +package org.eclipse.che.core.db; /** * Defines common database error codes which should diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/DBInitializer.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/DBInitializer.java new file mode 100644 index 00000000000..aa84a590b56 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/DBInitializer.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db; + +import org.eclipse.che.core.db.jpa.JpaInitializer; +import org.eclipse.che.core.db.jpa.eclipselink.GuiceEntityListenerInjectionManager; +import org.eclipse.che.core.db.schema.SchemaInitializationException; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.persistence.sessions.server.ServerSession; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.persistence.EntityManagerFactory; + +/** + * Initializes database components. + * + *

Those components which require any persistence operations on their bootstrap + * have to depend on this component. For example: + *

+ * class StackExistsChecker {
+ *
+ *     @@Inject
+ *     @SuppressWarnings("unused")
+ *     private DBInitializer dbInitializer;
+ *
+ *     @PostConstruct
+ *     public void check() {
+ *         ....
+ *     }
+ * }
+ * 
+ * In this way it is guaranteed that all database related components + * will be appropriately initialized before {@code check} method is executed. + * + * @author Yevhenii Voevodin + */ +@Singleton +public class DBInitializer { + + @Inject + public DBInitializer(SchemaInitializer schemaInitializer, JpaInitializer jpaInitializer) throws SchemaInitializationException { + // schema must be initialized before any other component that may interact with database + schemaInitializer.init(); + + // jpa initialization goes next + jpaInitializer.init(); + } + + @Inject + public void setUpInjectionManager(GuiceEntityListenerInjectionManager injManager, EntityManagerFactory emFactory) { + final ServerSession session = emFactory.unwrap(ServerSession.class); + session.setEntityListenerInjectionManager(injManager); + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/JndiDataSourceProvider.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/JndiDataSourceProvider.java new file mode 100644 index 00000000000..5d6fe161157 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/JndiDataSourceProvider.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db; + +import com.google.inject.Inject; + +import javax.inject.Named; +import javax.inject.Provider; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; + +/** + * Provides data source based on jndi resource name. + * + * @author Yevhenii Voevodin + */ +public class JndiDataSourceProvider implements Provider { + + @Inject + @Named("db.jndi.datasource.name") + private String name; + + @Override + public DataSource get() { + try { + final InitialContext context = new InitialContext(); + return (DataSource)context.lookup(name); + } catch (NamingException x) { + throw new IllegalStateException(x.getLocalizedMessage(), x); + } + } +} diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/CascadeRemovalEvent.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/event/CascadeRemovalEvent.java similarity index 94% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/CascadeRemovalEvent.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/event/CascadeRemovalEvent.java index 51b57a885f0..092077bb190 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/CascadeRemovalEvent.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/event/CascadeRemovalEvent.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa.event; +package org.eclipse.che.core.db.event; /** * Special event type which is needed only for diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/CascadeRemovalEventSubscriber.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/event/CascadeRemovalEventSubscriber.java similarity index 96% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/CascadeRemovalEventSubscriber.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/event/CascadeRemovalEventSubscriber.java index a7d5729c0f1..00dc95e8953 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/CascadeRemovalEventSubscriber.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/event/CascadeRemovalEventSubscriber.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa.event; +package org.eclipse.che.core.db.event; import org.eclipse.che.api.core.notification.EventSubscriber; diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/RemovalContext.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/event/RemovalContext.java similarity index 95% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/RemovalContext.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/event/RemovalContext.java index 081bb78a4e9..27a2cbbfc73 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/event/RemovalContext.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/event/RemovalContext.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa.event; +package org.eclipse.che.core.db.event; /** * Context that is used only for sharing the state of diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/CascadeRemovalException.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/CascadeRemovalException.java similarity index 95% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/CascadeRemovalException.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/CascadeRemovalException.java index 09ef753eba8..a473b10b91b 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/CascadeRemovalException.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/CascadeRemovalException.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa; +package org.eclipse.che.core.db.jpa; import javax.persistence.RollbackException; diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/DetailedRollbackException.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/DetailedRollbackException.java similarity index 91% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/DetailedRollbackException.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/DetailedRollbackException.java index 10c92c9c383..c3978bf68db 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/DetailedRollbackException.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/DetailedRollbackException.java @@ -8,9 +8,9 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa; +package org.eclipse.che.core.db.jpa; -import org.eclipse.che.api.core.jdbc.DBErrorCode; +import org.eclipse.che.core.db.DBErrorCode; import javax.persistence.RollbackException; diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/DuplicateKeyException.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/DuplicateKeyException.java similarity index 90% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/DuplicateKeyException.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/DuplicateKeyException.java index eb26489a8c6..417215a3178 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/DuplicateKeyException.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/DuplicateKeyException.java @@ -8,9 +8,9 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa; +package org.eclipse.che.core.db.jpa; -import org.eclipse.che.api.core.jdbc.DBErrorCode; +import org.eclipse.che.core.db.DBErrorCode; /** * Thrown when data couldn't be updated/stored due to unique constrain violation. diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/IntegrityConstraintViolationException.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/IntegrityConstraintViolationException.java similarity index 79% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/IntegrityConstraintViolationException.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/IntegrityConstraintViolationException.java index 33c9b4dd15a..6c30b8d6130 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/IntegrityConstraintViolationException.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/IntegrityConstraintViolationException.java @@ -8,11 +8,9 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa; +package org.eclipse.che.core.db.jpa; -import org.eclipse.che.api.core.jdbc.DBErrorCode; - -import static org.eclipse.che.api.core.jdbc.DBErrorCode.INTEGRITY_CONSTRAINT_VIOLATION; +import org.eclipse.che.core.db.DBErrorCode; /** * Throws during inserts/updates entity that restricted by referential integrity @@ -24,6 +22,6 @@ public class IntegrityConstraintViolationException extends DetailedRollbackException { public IntegrityConstraintViolationException(String message, Throwable cause) { - super(message, cause, INTEGRITY_CONSTRAINT_VIOLATION); + super(message, cause, DBErrorCode.INTEGRITY_CONSTRAINT_VIOLATION); } } diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/JpaInitializer.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/JpaInitializer.java new file mode 100644 index 00000000000..8f72fa96de0 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/JpaInitializer.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.jpa; + +import com.google.inject.ImplementedBy; + +import org.eclipse.che.core.db.jpa.guice.GuiceJpaInitializer; + +/** + * Initializes jpa components. + * + * @author Yevhenii Voevodin + */ +@ImplementedBy(GuiceJpaInitializer.class) +public interface JpaInitializer { + + /** Initialized jpa components. */ + void init(); +} diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/GuiceEntityListenerInjectionManager.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/eclipselink/GuiceEntityListenerInjectionManager.java similarity index 87% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/GuiceEntityListenerInjectionManager.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/eclipselink/GuiceEntityListenerInjectionManager.java index 60dcde32861..8bd0694fb5b 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/eclipselink/GuiceEntityListenerInjectionManager.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/eclipselink/GuiceEntityListenerInjectionManager.java @@ -8,15 +8,15 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa.eclipselink; +package org.eclipse.che.core.db.jpa.eclipselink; import com.google.inject.Inject; import com.google.inject.Injector; -import com.google.inject.Singleton; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.internal.sessions.cdi.EntityListenerInjectionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.naming.NamingException; @@ -44,11 +44,9 @@ * * @author Yevhenii Voevodin */ -@Singleton public class GuiceEntityListenerInjectionManager implements EntityListenerInjectionManager { - @Inject - private JpaInitializer jpaInitializer; + private static final Logger LOG = LoggerFactory.getLogger(GuiceEntityListenerInjectionManager.class); @Inject private Injector injector; @@ -58,6 +56,7 @@ public Object createEntityListenerAndInjectDependancies(Class entityListenerClas try { return injector.getInstance(entityListenerClass); } catch (RuntimeException x) { + LOG.error(x.getLocalizedMessage(), x); throw new NamingException(x.getLocalizedMessage()); } } diff --git a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/guice/JpaInitializer.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/guice/GuiceJpaInitializer.java similarity index 58% rename from core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/guice/JpaInitializer.java rename to core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/guice/GuiceJpaInitializer.java index 3eabba17ba3..16ca662fece 100644 --- a/core/che-core-api-jdbc/src/main/java/org/eclipse/che/api/core/jdbc/jpa/guice/JpaInitializer.java +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/jpa/guice/GuiceJpaInitializer.java @@ -8,12 +8,16 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.core.jdbc.jpa.guice; +package org.eclipse.che.core.db.jpa.guice; -import com.google.inject.Inject; -import com.google.inject.Singleton; import com.google.inject.persist.PersistService; +import org.eclipse.che.core.db.jpa.JpaInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; + /** * Should be bound as eager singleton. * See doc @@ -21,11 +25,18 @@ * @author Yevhenii Voevodin * @author Anton Korneta */ -@Singleton -public class JpaInitializer { +public class GuiceJpaInitializer implements JpaInitializer { + + private static final Logger LOG = LoggerFactory.getLogger(GuiceJpaInitializer.class); @Inject - public void init(PersistService persistService) { - persistService.start(); + private PersistService persistService; + + public void init() { + try { + persistService.start(); + } catch (Exception x) { + LOG.error(x.getLocalizedMessage(), x); + } } } diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializationException.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializationException.java new file mode 100644 index 00000000000..f42fa986b74 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializationException.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema; + +/** + * Thrown when any schema initialization/migration problem occurs. + * + * @author Yevhenii Voevodin + */ +public class SchemaInitializationException extends Exception { + + public SchemaInitializationException(String message, Throwable cause) { + super(message, cause); + } + + public SchemaInitializationException(String message) { + super(message); + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializer.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializer.java new file mode 100644 index 00000000000..8e320deb66e --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/SchemaInitializer.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema; + +/** + * Initializes database schema or migrates an old version of it to a new one. + * + * @author Yevhenii Voevodin + */ +public interface SchemaInitializer { + + /** + * Initializes database schema or migrates an old schema to a new one. + * + * @throws SchemaInitializationException + * thrown when any error occurs during schema initialization/migration + */ + void init() throws SchemaInitializationException; +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/CustomSqlMigrationResolver.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/CustomSqlMigrationResolver.java new file mode 100644 index 00000000000..4a25fb59c54 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/CustomSqlMigrationResolver.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import com.google.common.hash.Hashing; +import com.google.common.io.ByteSource; + +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.api.MigrationType; +import org.flywaydb.core.api.MigrationVersion; +import org.flywaydb.core.api.resolver.BaseMigrationResolver; +import org.flywaydb.core.api.resolver.ResolvedMigration; +import org.flywaydb.core.internal.dbsupport.DbSupport; +import org.flywaydb.core.internal.resolver.ResolvedMigrationImpl; +import org.flywaydb.core.internal.resolver.sql.SqlMigrationExecutor; +import org.flywaydb.core.internal.util.Location; +import org.flywaydb.core.internal.util.PlaceholderReplacer; +import org.flywaydb.core.internal.util.scanner.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.lang.String.format; +import static java.util.stream.Collectors.toList; + +/** + * Resolves SQL migrations from the configured locations, + * allows overriding of default scripts with vendor specific ones. + * + *
    Migration scripts must follow the next rules: + *
  • It must be placed in the project dir directory e.g. 5.0.1
  • + *
  • Project dir directory must be placed in dedicated directory e.g. resources/sql
  • + *
  • Migration/Initialization script name must start with a number e.g 1.init.sql, + * this number indicates the subversion of the database migration, e.g. for dir 5.0.0 + * and migration script 1.init.sql database migration dir will be 5.0.0.1
  • + *
  • If a file is not a part of migration it shouldn't end with migration prefix e.g. .sql + * then resolver will ignore it
  • + *
+ * + *

For the structure: + *

+ *   resources/
+ *      sql/
+ *        5.0.0/
+ *          1.init.sql
+ *        5.0.0-M1/
+ *          1.rename_fields.sql
+ *          2.add_workspace_constraint.sql
+ *          postgresql/
+ *            2.add_workspace_constraint.sql
+ *        5.0.1/
+ *          1.stacks_migration.sql
+ * 
+ * + * And configuration: + *
+ *     prefix - ""
+ *     suffix - ".sql"
+ *     separator - "."
+ *     locations - "classpath:sql"
+ * 
+ * + *
    4 database migrations will be resolved + *
  • 5.0.0.1 - initialization script based on file sql/5.0.0/1.init.sql
  • + *
  • 5.0.0.1.1 - modification script based on file sql/5.0.0-M1/1.rename_fields.sql
  • + *
  • 5.0.0.1.2 - modification script(if postgresql is current provider) based on file + * sql/5.0.0-M1/postgresql/2.add_workspace_constraint.sql
  • + *
  • 5.0.1.1 - modification script based on file sql/5.0.1/1.stacks_migrations.sql
  • + *
+ * + *

It is also possible to configure several locations then all of those locations + * will be analyzed for migration scripts existence. For example: + * + * + *

For the structure: + *

+ *  che/
+ *    resources/
+ *       che-schema/
+ *         5.0.0/
+ *          1.init.sql
+ *  another-project/
+ *    resources/
+ *      custom-schema/
+ *        5.0.0/
+ *          2.init_additional_tables.sql
+ * 
+ * + * And configuration: + *
+ *     prefix - ""
+ *     suffix - ".sql"
+ *     separator - "."
+ *     locations - "classpath:che-schema, classpath:custom-schema"
+ * 
+ * + *
    2 database migrations will be resolved + *
  • 5.0.0.1 - initialization script based on file che-schema/5.0.0/1.init.sql
  • + *
  • 5.0.0.2 - modification script based on file custom-schema/5.0.0/2.init_additional_tables.sql
  • + *
+ * + * @author Yevhenii Voevodin + */ +public class CustomSqlMigrationResolver extends BaseMigrationResolver { + + private static final Logger LOG = LoggerFactory.getLogger(CustomSqlMigrationResolver.class); + + private final String vendorName; + private final ResourcesFinder finder; + private final VersionResolver versionResolver; + private final SqlScriptCreator scriptsCreator; + private final DbSupport dbSupport; + private final PlaceholderReplacer placeholderReplacer; + + public CustomSqlMigrationResolver(String dbProviderName, + DbSupport dbSupport, + PlaceholderReplacer placeholderReplacer) { + this.vendorName = dbProviderName; + this.dbSupport = dbSupport; + this.placeholderReplacer = placeholderReplacer; + this.finder = new ResourcesFinder(); + this.versionResolver = new VersionResolver(); + this.scriptsCreator = new SqlScriptCreator(); + } + + @Override + public Collection resolveMigrations() { + try { + return resolveSqlMigrations(); + } catch (IOException | SQLException x) { + throw new RuntimeException(x.getLocalizedMessage(), x); + } + } + + private List resolveSqlMigrations() throws IOException, SQLException { + LOG.info("Searching for sql scripts in locations {}", Arrays.toString(flywayConfiguration.getLocations())); + final Map> allResources = finder.findResources(flywayConfiguration); + LOG.debug("Found scripts: {}", allResources); + + final Map> scriptsInDir = new HashMap<>(); + for (Location location : allResources.keySet()) { + final List resources = allResources.get(location); + for (Resource resource : resources) { + final SqlScript newScript = scriptsCreator.createScript(location, resource); + if (!scriptsInDir.containsKey(newScript.dir)) { + scriptsInDir.put(newScript.dir, new HashMap<>(4)); + } + final Map existingScripts = scriptsInDir.get(newScript.dir); + final SqlScript existingScript = existingScripts.get(newScript.name); + if (existingScript == null) { + existingScripts.put(newScript.name, newScript); + } else if (Objects.equals(existingScript.vendor, newScript.vendor)) { + throw new FlywayException(format("More than one script with name '%s' is registered for " + + "database vendor '%s', script '%s' conflicts with '%s'", + newScript.name, + existingScript.vendor, + newScript, + existingScript)); + } else if (vendorName.equals(newScript.vendor)) { + existingScripts.put(newScript.name, newScript); + } + } + } + + final Map migrations = new HashMap<>(); + for (SqlScript script : scriptsInDir.values() + .stream() + .flatMap(scripts -> scripts.values().stream()) + .collect(toList())) { + final ResolvedMigrationImpl migration = new ResolvedMigrationImpl(); + migration.setVersion(versionResolver.resolve(script, flywayConfiguration)); + migration.setScript(script.resource.getLocation()); + migration.setPhysicalLocation(script.resource.getLocationOnDisk()); + migration.setType(MigrationType.SQL); + migration.setDescription(script.name); + migration.setChecksum(ByteSource.wrap(script.resource.loadAsBytes()).hash(Hashing.crc32()).asInt()); + migration.setExecutor(new SqlMigrationExecutor(dbSupport, + script.resource, + placeholderReplacer, + flywayConfiguration.getEncoding())); + if (migrations.put(migration.getVersion(), migration) != null) { + throw new FlywayException("Two migrations with the same version detected"); + } + } + return new ArrayList<>(migrations.values()); + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializer.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializer.java new file mode 100644 index 00000000000..2f1178ebbcd --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializer.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import com.google.inject.Inject; +import com.google.inject.name.Named; + +import org.eclipse.che.core.db.schema.SchemaInitializationException; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.flywaydb.core.Flyway; +import org.flywaydb.core.internal.dbsupport.DbSupport; +import org.flywaydb.core.internal.dbsupport.DbSupportFactory; +import org.flywaydb.core.internal.util.PlaceholderReplacer; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Flyway based schema initializer. + * + * @author Yevhenii Voevodin + */ +public class FlywaySchemaInitializer implements SchemaInitializer { + + private final DataSource dataSource; + private final String[] locations; + private final String scriptsPrefix; + private final String scriptsSuffix; + private final String versionSeparator; + private final boolean baselineOnMigrate; + private final String baselineVersion; + private final PlaceholderReplacer placeholderReplacer; + + /** + * Creates a new instance of flyway schema initializer. + * + * @param scriptsLocations + * the locations where to search migration scripts, + * if locations is not prefixed or prefixed with classpath: + * then initializer will try to find scripts in classpath using + * {@code Thread.currentThread().}{@link Thread#getContextClassLoader() getContextClassLoader()} + * @param scriptsPrefix + * prefix of migration scripts e.g. 'v' or empty string + * @param scriptsSuffix + * suffix of migration scripts e.g. '.sql' + * @param versionSeparator + * separate version from the other part of script name e.g. '.' or '__' + * @param baselineOnMigrate + * whether to ignore scripts up to the version configured by {@code baselineVersion} + * @param baselineVersion + * up to this version all the scripts ignored, unless schema is initialized first time, + * note that scripts with version equal to baseline version are also ignored + * @param dataSource + * data source used for migrations + * @param placeholderReplacer + * used to replace variables in script with configured values + */ + @Inject + public FlywaySchemaInitializer(@Named("db.schema.flyway.scripts.locations") String[] scriptsLocations, + @Named("db.schema.flyway.scripts.prefix") String scriptsPrefix, + @Named("db.schema.flyway.scripts.suffix") String scriptsSuffix, + @Named("db.schema.flyway.scripts.version_separator") String versionSeparator, + @Named("db.schema.flyway.baseline.enabled") boolean baselineOnMigrate, + @Named("db.schema.flyway.baseline.version") String baselineVersion, + DataSource dataSource, + PlaceholderReplacer placeholderReplacer) { + this.dataSource = dataSource; + this.locations = scriptsLocations; + this.scriptsPrefix = scriptsPrefix; + this.scriptsSuffix = scriptsSuffix; + this.versionSeparator = versionSeparator; + this.baselineOnMigrate = baselineOnMigrate; + this.baselineVersion = baselineVersion; + this.placeholderReplacer = placeholderReplacer; + } + + /** Creates a new flyway based initializer with default values. */ + public FlywaySchemaInitializer(DataSource dataSource, String... locations) { + this(locations, + "", + ".sql", + "__", + false, + "", + dataSource, + PlaceholderReplacer.NO_PLACEHOLDERS); + } + + @Override + public void init() throws SchemaInitializationException { + try (final Connection conn = dataSource.getConnection()) { + final Flyway flyway = new Flyway(); + flyway.setDataSource(dataSource); + flyway.setLocations(locations); + flyway.setClassLoader(Thread.currentThread().getContextClassLoader()); + final DbSupport dbSupport = DbSupportFactory.createDbSupport(conn, true); + final String productName = conn.getMetaData().getDatabaseProductName().toLowerCase(); + flyway.setResolvers(new CustomSqlMigrationResolver(productName, dbSupport, placeholderReplacer)); + flyway.setSkipDefaultResolvers(true); + flyway.setBaselineOnMigrate(baselineOnMigrate); + if (baselineOnMigrate) { + flyway.setBaselineVersionAsString(baselineVersion); + } + flyway.setSqlMigrationSeparator(versionSeparator); + flyway.setSqlMigrationSuffix(scriptsSuffix); + flyway.setSqlMigrationPrefix(scriptsPrefix); + flyway.migrate(); + } catch (SQLException | RuntimeException x) { + throw new SchemaInitializationException(x.getLocalizedMessage(), x); + } + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/PlaceholderReplacerProvider.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/PlaceholderReplacerProvider.java new file mode 100644 index 00000000000..b50d3d8a97f --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/PlaceholderReplacerProvider.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.eclipse.che.inject.ConfigurationProperties; +import org.flywaydb.core.internal.util.PlaceholderReplacer; + +import javax.inject.Inject; +import javax.inject.Provider; + +/** + * Placeholder replacer that uses configuration properties. + * + * @author Yevhenii Voevodin + */ +public class PlaceholderReplacerProvider implements Provider { + + private final PlaceholderReplacer replacer; + + @Inject + public PlaceholderReplacerProvider(ConfigurationProperties properties) { + replacer = new PlaceholderReplacer(properties.getProperties(".*"), "${", "}"); + } + + @Override + public PlaceholderReplacer get() { + return replacer; + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinder.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinder.java new file mode 100644 index 00000000000..bb9e0ce7a50 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinder.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.flywaydb.core.api.configuration.FlywayConfiguration; +import org.flywaydb.core.internal.util.Location; +import org.flywaydb.core.internal.util.scanner.Resource; +import org.flywaydb.core.internal.util.scanner.classpath.ClassPathScanner; +import org.flywaydb.core.internal.util.scanner.filesystem.FileSystemScanner; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * Searches for sql scripts in given places. + * + * @author Yevhenii Voevodin + */ +class ResourcesFinder { + + /** + * Finds script resources in configured {@link FlywayConfiguration#getLocations()}. + * + * @param configuration + * flyway configuration to find scripts + * @return found scripts or an empty list if nothing found + * @throws IOException + * when any io error occurs during scripts look up + */ + Map> findResources(FlywayConfiguration configuration) throws IOException { + final String prefix = configuration.getSqlMigrationPrefix(); + final String suffix = configuration.getSqlMigrationSuffix(); + final ClassPathScanner cpScanner = new ClassPathScanner(configuration.getClassLoader()); + final FileSystemScanner fsScanner = new FileSystemScanner(); + final Map> resources = new HashMap<>(); + for (String rawLocation : configuration.getLocations()) { + final Location location = new Location(rawLocation); + if (location.isClassPath()) { + resources.put(location, newArrayList(cpScanner.scanForResources(location, prefix, suffix))); + } else { + resources.put(location, newArrayList(fsScanner.scanForResources(location, prefix, suffix))); + } + } + return resources; + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScript.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScript.java new file mode 100644 index 00000000000..11875834986 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScript.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.flywaydb.core.internal.util.Location; +import org.flywaydb.core.internal.util.scanner.Resource; + +import java.util.Objects; + +/** + * Data object for holding information about sql script. + * + * @author Yevhenii Voevodin + */ +class SqlScript { + + final Resource resource; + final Location location; + final String dir; + final String vendor; + final String name; + + SqlScript(Resource resource, Location location, String dir, String vendor, String name) { + this.resource = resource; + this.location = location; + this.name = name; + this.vendor = vendor; + this.dir = dir; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof SqlScript)) { + return false; + } + final SqlScript that = (SqlScript)obj; + return Objects.equals(resource, that.resource) + && Objects.equals(location, that.location) + && Objects.equals(dir, that.dir) + && Objects.equals(vendor, that.vendor) + && Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 31 * hash + Objects.hashCode(resource); + hash = 31 * hash + Objects.hashCode(location); + hash = 31 * hash + Objects.hashCode(dir); + hash = 31 * hash + Objects.hashCode(vendor); + hash = 31 * hash + Objects.hashCode(name); + return hash; + } + + @Override + public String toString() { + return "SqlScript{" + + "resource=" + resource + + ", location=" + location + + ", dir='" + dir + '\'' + + ", vendor='" + vendor + '\'' + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreator.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreator.java new file mode 100644 index 00000000000..515ba5d3154 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreator.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.internal.util.Location; +import org.flywaydb.core.internal.util.scanner.Resource; + +import java.io.File; + +import static java.lang.String.format; + +/** + * Creates new {@link SqlScript} instance from given resource. + * + * @author Yevhenii Voevodin + */ +class SqlScriptCreator { + + /** + * Create a new instance of script based on location and resource. + * + * @param location + * root location of the given resource + * @param resource + * script resource + * @return a new instance of sql script based on location and resource + * @throws FlywayException + * when script can't be created from the resource + */ + SqlScript createScript(Location location, Resource resource) { + final String separator = location.isClassPath() ? "/" : File.separator; + // '/root-location/5.0.0-M7/v1__init.sql' -> '5.0.0-M7/v1__init.sql' + final String relLocation = resource.getLocation().substring(location.getPath().length() + 1); + final String[] paths = relLocation.split(separator); + // 5.0.0-M1/v1__init.sql + if (paths.length == 2) { + return new SqlScript(resource, location, paths[0], null, paths[1]); + } + // 5.0.0-M1/postgresql/v1__init.sql + if (paths.length == 3) { + return new SqlScript(resource, location, paths[0], paths[1], paths[2]); + } + throw new FlywayException(format("Sql script location must be either in 'location-root/version-dir' " + + "or in 'location-root/version-dir/provider-name', but script '%s' is not in root '%s'", + resource.getLocation(), + location.getPath())); + } +} diff --git a/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolver.java b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolver.java new file mode 100644 index 00000000000..9b2bfb18d37 --- /dev/null +++ b/core/che-core-db/src/main/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolver.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.api.MigrationVersion; +import org.flywaydb.core.api.configuration.FlywayConfiguration; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.lang.String.format; + +/** + * Creates versions for scripts depending on the provided data. + *
    A few examples: + *
  • 5.0.0-M7/v1__init.sql => 5.0.0.7.1
  • + *
  • 5.0.0-M8/v2.1__modify.sql => 5.0.0.8.2.1
  • + *
+ * + * @author Yevhenii Voevodin + */ +class VersionResolver { + + private static final Pattern NOT_VERSION_CHARS_PATTERN = Pattern.compile("[^0-9.]"); + + private final Map normalizedDirs = new HashMap<>(); + + /** + * Creates migration version based on script data. + * + * @param script + * script for which to resolve the version + * @param configuration + * flyway configuration used for resolution parameters + */ + MigrationVersion resolve(SqlScript script, FlywayConfiguration configuration) { + String normalizedDir = normalizedDirs.get(script.dir); + if (normalizedDir == null) { + // 5.0.0-M1 -> 5.0.0.M1 -> 5.0.0.1 + normalizedDir = NOT_VERSION_CHARS_PATTERN.matcher(script.dir.replace("-", ".")).replaceAll(""); + normalizedDirs.put(script.dir, normalizedDir); + } + + // separate version from the other part of the name + final int sepIdx = script.name.indexOf(configuration.getSqlMigrationSeparator()); + if (sepIdx == -1) { + throw new FlywayException(format("sql script name '%s' is not valid, name must contain '%s'", + script.name, + configuration.getSqlMigrationSeparator())); + } + + // check whether part before separator is not empty + String version = script.name.substring(0, sepIdx); + if (version.isEmpty()) { + throw new FlywayException(format("sql script name '%s' is not valid, name must provide version like " + + "'%s4%smigration_description.sql", + configuration.getSqlMigrationPrefix(), + script.name, + configuration.getSqlMigrationSeparator())); + } + + // extract sql script version without prefix + final String prefix = configuration.getSqlMigrationPrefix(); + if (!isNullOrEmpty(prefix) && script.name.startsWith(prefix)) { + version = version.substring(prefix.length()); + } + return MigrationVersion.fromVersion(normalizedDir + '.' + version); + } +} diff --git a/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializerTest.java b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializerTest.java new file mode 100644 index 00000000000..15361a2cbd2 --- /dev/null +++ b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/FlywaySchemaInitializerTest.java @@ -0,0 +1,339 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; + +import org.eclipse.che.commons.lang.IoUtil; +import org.eclipse.che.core.db.schema.SchemaInitializationException; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.flywaydb.core.internal.util.PlaceholderReplacer; +import org.h2.jdbcx.JdbcDataSource; +import org.h2.tools.RunScript; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import javax.sql.DataSource; +import java.io.IOException; +import java.io.StringReader; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + * Tests {@link FlywaySchemaInitializer}. + * + * @author Yevhenii Voevodin + */ +public class FlywaySchemaInitializerTest { + + private static final String SCRIPTS_ROOT = "flyway/sql"; + + private JdbcDataSource dataSource; + + @BeforeMethod + public void setUp() throws URISyntaxException { + dataSource = new JdbcDataSource(); + dataSource.setUrl("jdbc:h2:mem:flyway_test;DB_CLOSE_DELAY=-1"); + } + + @AfterMethod + public void cleanup() throws SQLException, URISyntaxException { + try (Connection conn = dataSource.getConnection()) { + RunScript.execute(conn, new StringReader("SHUTDOWN")); + } + IoUtil.deleteRecursive(targetDir().resolve(Paths.get(SCRIPTS_ROOT)).toFile()); + } + + @Test + public void initializesSchemaWhenDatabaseIsEmpty() throws Exception { + createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"); + createScript("1.0/2__add_data.sql", "INSERT INTO test VALUES(1, 'test1');" + + "INSERT INTO test VALUES(2, 'test2');" + + "INSERT INTO test VALUES(3, 'test3');"); + createScript("2.0/1__add_more_data.sql", "INSERT INTO test VALUES(4, 'test4');"); + createScript("2.0/postgresql/1__add_more_data.sql", "INSERT INTO test VALUES(4, 'postgresql-data');"); + + final SchemaInitializer initializer = FlywayInitializerBuilder.from(dataSource).build(); + initializer.init(); + + assertEquals(queryEntities(), Sets.newHashSet(new TestEntity(1, "test1"), + new TestEntity(2, "test2"), + new TestEntity(3, "test3"), + new TestEntity(4, "test4"))); + + // second init must do nothing, so there are no conflicts + initializer.init(); + } + + @Test(expectedExceptions = SchemaInitializationException.class) + public void failsIfBaseLineIsNotConfiguredProperly() throws Exception { + execQuery("CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));" + + "INSERT INTO test VALUES(1, 'test1');" + + "INSERT INTO test VALUES(2, 'test2');" + + "INSERT INTO test VALUES(3, 'test3');"); + createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"); + + FlywayInitializerBuilder.from(dataSource) + .setBaselineOnMigrate(true) + .setBaselineVersion("1.0") + .build() + .init(); + } + + @Test + public void executesOnlyThoseMigrationsWhichGoAfterBaseline() throws Exception { + execQuery("CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"); + createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"); + createScript("2.0/1__add_data.sql", "INSERT INTO test VALUES(1, 'test1');" + + "INSERT INTO test VALUES(2, 'test2');" + + "INSERT INTO test VALUES(3, 'test3');"); + final FlywaySchemaInitializer initializer = FlywayInitializerBuilder.from(dataSource) + .setBaselineOnMigrate(true) + .setBaselineVersion("1.0.1") + .build(); + + initializer.init(); + + assertEquals(queryEntities(), Sets.newHashSet(new TestEntity(1, "test1"), + new TestEntity(2, "test2"), + new TestEntity(3, "test3"))); + + // second init must do nothing, so there are no conflicts + initializer.init(); + } + + @Test + public void initializesSchemaWhenDatabaseIsEmptyAndBaselineIsConfigured() throws Exception { + createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"); + createScript("2.0/1__add_data.sql", "INSERT INTO test VALUES(1, 'test1');" + + "INSERT INTO test VALUES(2, 'test2');" + + "INSERT INTO test VALUES(3, 'test3');"); + + final FlywaySchemaInitializer initializer = FlywayInitializerBuilder.from(dataSource) + .setBaselineOnMigrate(true) + .setBaselineVersion("1.0.1") + .build(); + initializer.init(); + + assertEquals(queryEntities(), Sets.newHashSet(new TestEntity(1, "test1"), + new TestEntity(2, "test2"), + new TestEntity(3, "test3"))); + + // second init must do nothing, so there are no conflicts + initializer.init(); + } + + @Test + public void selectsProviderSpecificScriptsInPreferenceToDefaultOnes() throws Exception { + createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"); + createScript("2.0/1__add_data.sql", "INSERT INTO test VALUES(1, 'default data');"); + createScript("2.0/h2/1__add_data.sql", "INSERT INTO test VALUES(1, 'h2 data');"); + + final FlywaySchemaInitializer initializer = FlywayInitializerBuilder.from(dataSource).build(); + initializer.init(); + + assertEquals(queryEntities(), Sets.newHashSet(new TestEntity(1, "h2 data"))); + + // second init must do nothing, so there are no conflicts + initializer.init(); + } + + @Test + public void replacesVariablesWhenPlaceholderReplacerIsConfigured() throws Exception { + createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));" + + "INSERT INTO test VALUES(1, '${variable}');"); + + FlywayInitializerBuilder.from(dataSource) + .setReplacer(new PlaceholderReplacer(ImmutableMap.of("variable", "test"), "${", "}")) + .build() + .init(); + + assertEquals(queryEntities(), Sets.newHashSet(new TestEntity(1, "test"))); + } + + private Set queryEntities() throws SQLException { + final Set entities = new HashSet<>(); + try (Connection conn = dataSource.getConnection()) { + final ResultSet result = RunScript.execute(conn, new StringReader("SELECT * FROM test")); + while (result.next()) { + entities.add(new TestEntity(result.getLong("id"), result.getString("text"))); + } + } + return entities; + } + + private ResultSet execQuery(String query) throws SQLException { + try (Connection conn = dataSource.getConnection()) { + return RunScript.execute(conn, new StringReader(query)); + } + } + + private static Path createScript(String relativePath, String content) throws URISyntaxException, IOException { + return createFile(targetDir().resolve(Paths.get(SCRIPTS_ROOT)) + .resolve(relativePath).toString(), + content); + } + + private static Path createFile(String filepath, String content) throws URISyntaxException, IOException { + final Path path = targetDir().resolve(Paths.get(filepath)); + if (!Files.exists(path.getParent())) { + Files.createDirectories(path.getParent()); + } + Files.write(path, content.getBytes(StandardCharsets.UTF_8)); + return path; + } + + private static Path targetDir() throws URISyntaxException { + final URL url = Thread.currentThread().getContextClassLoader().getResource("."); + assertNotNull(url); + return Paths.get(url.toURI()).getParent(); + } + + private static class TestEntity { + final long id; + final String text; + + private TestEntity(long id, String text) { + this.id = id; + this.text = text; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TestEntity)) { + return false; + } + final TestEntity that = (TestEntity)obj; + return id == that.id + && Objects.equals(text, that.text); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 31 * hash + Long.hashCode(id); + hash = 31 * hash + Objects.hashCode(text); + return hash; + } + + @Override + public String toString() { + return "TestEntity{" + + "id=" + id + + ", text='" + text + '\'' + + '}'; + } + } + + private static class FlywayInitializerBuilder { + + public static FlywayInitializerBuilder from(DataSource dataSource) { + try { + final String scriptsRoot = targetDir().resolve(Paths.get(SCRIPTS_ROOT)).toString(); + return new FlywayInitializerBuilder().setDataSource(dataSource) + .setScriptsPrefix("") + .setScriptsSuffix(".sql") + .setVersionSeparator("__") + .setReplacer(PlaceholderReplacer.NO_PLACEHOLDERS) + .setBaselineOnMigrate(false) + .addLocation("filesystem:" + scriptsRoot); + } catch (Exception x) { + throw new RuntimeException(x.getMessage(), x); + } + } + + private DataSource dataSource; + private List locations; + private String scriptsPrefix; + private String scriptsSuffix; + private String versionSeparator; + private boolean baselineOnMigrate; + private String baselineVersion; + private PlaceholderReplacer replacer; + + public FlywayInitializerBuilder setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + return this; + } + + public FlywayInitializerBuilder setReplacer(PlaceholderReplacer replacer) { + this.replacer = replacer; + return this; + } + + public FlywayInitializerBuilder addLocation(String location) { + if (locations == null) { + locations = new ArrayList<>(); + } + locations.add(location); + return this; + } + + public FlywayInitializerBuilder setScriptsPrefix(String scriptsPrefix) { + this.scriptsPrefix = scriptsPrefix; + return this; + } + + public FlywayInitializerBuilder setScriptsSuffix(String scriptsSuffix) { + this.scriptsSuffix = scriptsSuffix; + return this; + } + + public FlywayInitializerBuilder setVersionSeparator(String versionSeparator) { + this.versionSeparator = versionSeparator; + return this; + } + + public FlywayInitializerBuilder setBaselineOnMigrate(boolean baselineOnMigrate) { + this.baselineOnMigrate = baselineOnMigrate; + return this; + } + + public FlywayInitializerBuilder setBaselineVersion(String baselineVersion) { + this.baselineVersion = baselineVersion; + return this; + } + + public FlywaySchemaInitializer build() { + if (locations == null) { + throw new IllegalStateException("locations required"); + } + return new FlywaySchemaInitializer(locations.toArray(new String[locations.size()]), + scriptsPrefix, + scriptsSuffix, + versionSeparator, + baselineOnMigrate, + baselineVersion, + dataSource, + replacer); + } + } +} diff --git a/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinderTest.java b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinderTest.java new file mode 100644 index 00000000000..f3dd50aa745 --- /dev/null +++ b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/ResourcesFinderTest.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.configuration.FlywayConfiguration; +import org.flywaydb.core.internal.util.Location; +import org.flywaydb.core.internal.util.scanner.Resource; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.google.common.collect.Sets.newHashSet; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + * Tests {@link ResourcesFinder}. + * + * @author Yevhenii Voevodin + */ +public class ResourcesFinderTest { + + private final List cleanAfter = new ArrayList<>(); + private final Flyway flyway = new Flyway(); + + @BeforeMethod + public void setUpDefaults() { + flyway.setSqlMigrationSuffix(".sql"); + flyway.setSqlMigrationPrefix(""); + } + + @AfterMethod + public void cleanup() throws IOException { + for (Path path : cleanAfter) { + Files.delete(path); + } + cleanAfter.clear(); + } + + @Test + public void findsScriptsInClassPath() throws Exception { + flyway.setLocations("classpath:finder-sql-files"); + cleanAfter.addAll(createFiles("finder-sql-files/1.0/1.sql", + "finder-sql-files/1.0/2.sql", + "finder-sql-files/2.0/1.sql", + "finder-sql-files/2.0/postgresql/1.sql")); + + final Set locations = findResources(flyway).get("classpath:finder-sql-files"); + + assertEquals(locations, newHashSet("finder-sql-files/1.0/1.sql", + "finder-sql-files/1.0/2.sql", + "finder-sql-files/2.0/1.sql", + "finder-sql-files/2.0/postgresql/1.sql")); + } + + @Test + public void findsScriptsOnFileSystem() throws Exception { + final List paths = createFiles("finder-sql-files/1.0/1.sql", + "finder-sql-files/1.0/2.sql", + "finder-sql-files/2.0/1.sql", + "finder-sql-files/2.0/postgresql/1.sql"); + cleanAfter.addAll(paths); + final Path finderSqlFiles = paths.get(0).getParent().getParent(); + final String fsLocation = "filesystem:" + finderSqlFiles.toAbsolutePath(); + flyway.setLocations(fsLocation); + + final Set locations = findResources(flyway).get(fsLocation); + + assertEquals(locations, + newHashSet(finderSqlFiles.resolve("1.0").resolve("1.sql").toString(), + finderSqlFiles.resolve("1.0").resolve("2.sql").toString(), + finderSqlFiles.resolve("2.0").resolve("1.sql").toString(), + finderSqlFiles.resolve("2.0").resolve("postgresql").resolve("1.sql").toString())); + } + + @Test + public void findsFileSystemAndClassPathScripts() throws Exception { + final List paths = createFiles("finder-fs-sql-files/1.0/1.sql", + "finder-fs-sql-files/2.0/2.sql", + "finder-cp-sql-files/1.0/2.sql", + "finder-cp-sql-files/2.0/postgresql/1.sql"); + cleanAfter.addAll(paths); + final Path finderFsSqlFiles = paths.get(0).getParent().getParent(); + final String fsLocation = "filesystem:" + finderFsSqlFiles.toAbsolutePath(); + final String cpLocation = "classpath:finder-cp-sql-files"; + flyway.setLocations(fsLocation, cpLocation); + + final Map> locations = findResources(flyway); + + assertEquals(locations.get(fsLocation), newHashSet(finderFsSqlFiles.resolve("1.0") + .resolve("1.sql") + .toString(), + finderFsSqlFiles.resolve("2.0") + .resolve("2.sql") + .toString())); + assertEquals(locations.get(cpLocation), newHashSet("finder-cp-sql-files/1.0/2.sql", + "finder-cp-sql-files/2.0/postgresql/1.sql")); + } + + private static Map> findResources(FlywayConfiguration configuration) throws IOException { + final Map> resources = new ResourcesFinder().findResources(configuration); + final Map> locations = new HashMap<>(); + for (Map.Entry> entry : resources.entrySet()) { + locations.put(entry.getKey().toString(), entry.getValue() + .stream() + .map(Resource::getLocation) + .collect(Collectors.toSet())); + } + return locations; + } + + private static List createFiles(String... paths) throws URISyntaxException, IOException { + final URL url = Thread.currentThread().getContextClassLoader().getResource("."); + assertNotNull(url); + final Path classesDir = Paths.get(url.toURI()); + final List createdFiles = new ArrayList<>(paths.length); + for (String stringPath : paths) { + final Path path = classesDir.resolve(Paths.get(stringPath)); + if (!Files.exists(path.getParent())) { + Files.createDirectories(path.getParent()); + } + Files.write(path, path.toString().getBytes(StandardCharsets.UTF_8)); + createdFiles.add(path); + } + return createdFiles; + } +} diff --git a/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreatorTest.java b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreatorTest.java new file mode 100644 index 00000000000..82bfbacba51 --- /dev/null +++ b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/SqlScriptCreatorTest.java @@ -0,0 +1,67 @@ + +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.internal.util.Location; +import org.flywaydb.core.internal.util.scanner.Resource; +import org.flywaydb.core.internal.util.scanner.filesystem.FileSystemResource; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +/** + * Tests {@link SqlScriptCreator}. + * + * @author Yevhenii Voevodin + */ +public class SqlScriptCreatorTest { + + @Test + public void createsScript() throws Exception { + final Location location = new Location("filesystem:schema"); + final Resource resource = new FileSystemResource("schema/5.0.0-M7/v1__init.sql"); + + final SqlScriptCreator scriptsCreator = new SqlScriptCreator(); + final SqlScript script = scriptsCreator.createScript(location, resource); + + assertEquals(script.name, "v1__init.sql"); + assertEquals(script.location, location); + assertEquals(script.dir, "5.0.0-M7"); + assertEquals(script.resource.getLocation(), resource.getLocation()); + assertNull(script.vendor); + } + + @Test + public void createsVendorScript() throws Exception { + final Location location = new Location("filesystem:schema"); + final Resource resource = new FileSystemResource("schema/5.0.0-M7/postgresql/v1__init.sql"); + + final SqlScriptCreator scriptsCreator = new SqlScriptCreator(); + final SqlScript script = scriptsCreator.createScript(location, resource); + + assertEquals(script.name, "v1__init.sql"); + assertEquals(script.location, location); + assertEquals(script.dir, "5.0.0-M7"); + assertEquals(script.resource.getLocation(), resource.getLocation()); + assertEquals(script.vendor, "postgresql"); + } + + @Test(expectedExceptions = FlywayException.class) + public void failsToCreateResourceWhenPathIsInvalid() throws Exception { + final Location location = new Location("filesystem:schema"); + final Resource resource = new FileSystemResource("schema/v1__init.sql"); + + new SqlScriptCreator().createScript(location, resource); + } +} diff --git a/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolverTest.java b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolverTest.java new file mode 100644 index 00000000000..b22870e3e24 --- /dev/null +++ b/core/che-core-db/src/test/java/org/eclipse/che/core/db/schema/impl/flyway/VersionResolverTest.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.core.db.schema.impl.flyway; + +import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.api.MigrationVersion; +import org.flywaydb.core.internal.util.Location; +import org.flywaydb.core.internal.util.scanner.filesystem.FileSystemResource; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +/** + * Tests {@link VersionResolver}. + * + * @author Yevhenii Voevodin + */ +public class VersionResolverTest { + + private final Flyway flyway = new Flyway(); + private final VersionResolver resolver = new VersionResolver(); + + @BeforeMethod + public void setUpDefaults() { + flyway.setSqlMigrationSuffix(".sql"); + flyway.setSqlMigrationPrefix(""); + flyway.setSqlMigrationSeparator("__"); + } + + @Test(dataProvider = "validScripts") + public void resolvesVersion(String dir, String name, String expectedVersion) { + final SqlScript script = new SqlScript(new FileSystemResource("sql/" + dir + "/" + name), + new Location("filesystem:sql"), + dir, + null, + name); + + assertEquals(resolver.resolve(script, flyway), MigrationVersion.fromVersion(expectedVersion)); + } + + @Test(dataProvider = "invalidScripts", expectedExceptions = FlywayException.class) + public void failsToResolveVersions(String dir, String name) throws Exception { + final SqlScript script = new SqlScript(new FileSystemResource("sql/" + dir + "/" + name), + new Location("filesystem:sql"), + dir, + null, + name); + resolver.resolve(script, flyway); + } + + @DataProvider + public static Object[][] invalidScripts() { + return new String[][] { + {"1.0", "2016-11-11__init.sql"}, + {"1.0", "one__init.sql"}, + {"1.0", "__init.sql"}, + {"1.0", "version1__script.sql"}, + {"1.0", "1..1__script.sql"}, + {"5..0.0", "1__init.sql"} + }; + } + + @DataProvider + public static Object[][] validScripts() { + return new Object[][] { + {"5.0.0-M7", "1__init.sql", "5.0.0.7.1"}, + {"5.0.0-M7", "1.1__init_sub_tables.sql", "5.0.0.7.1.1"}, + {"6.0", "0.1__specific_update.sql", "6.0.0.1"}, + {"1.0", "1__simple.sql", "1.0.1"} + }; + } +} diff --git a/core/che-core-db/src/test/resources/logback-test.xml b/core/che-core-db/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..208835c280e --- /dev/null +++ b/core/che-core-db/src/test/resources/logback-test.xml @@ -0,0 +1,34 @@ + + + + + + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + target/log/codenvy.log + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + + + + + diff --git a/core/che-core-db/src/test/resources/sql/1.0/1.init.sql b/core/che-core-db/src/test/resources/sql/1.0/1.init.sql new file mode 100644 index 00000000000..8ca4f9dedcb --- /dev/null +++ b/core/che-core-db/src/test/resources/sql/1.0/1.init.sql @@ -0,0 +1,17 @@ +-- +-- Copyright (c) 2012-2016 Codenvy, S.A. +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v1.0 +-- which accompanies this distribution, and is available at +-- http://www.eclipse.org/legal/epl-v10.html +-- +-- Contributors: +-- Codenvy, S.A. - initial API and implementation +-- + +CREATE TABLE test ( + id INT, + text TEXT, + + PRIMARY KEY (id) +); diff --git a/core/che-core-db/src/test/resources/sql/1.0/2.add_data.sql b/core/che-core-db/src/test/resources/sql/1.0/2.add_data.sql new file mode 100644 index 00000000000..7ed58b3ddfa --- /dev/null +++ b/core/che-core-db/src/test/resources/sql/1.0/2.add_data.sql @@ -0,0 +1,14 @@ +-- +-- Copyright (c) 2012-2016 Codenvy, S.A. +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v1.0 +-- which accompanies this distribution, and is available at +-- http://www.eclipse.org/legal/epl-v10.html +-- +-- Contributors: +-- Codenvy, S.A. - initial API and implementation +-- + +INSERT INTO test VALUES(1, 'test1'); +INSERT INTO test VALUES(2, 'test2'); +INSERT INTO test VALUES(3, 'test3'); diff --git a/core/che-core-db/src/test/resources/sql/2.0/1.modify_test_table.sql b/core/che-core-db/src/test/resources/sql/2.0/1.modify_test_table.sql new file mode 100644 index 00000000000..7ec3ed47e93 --- /dev/null +++ b/core/che-core-db/src/test/resources/sql/2.0/1.modify_test_table.sql @@ -0,0 +1,11 @@ +-- +-- Copyright (c) 2012-2016 Codenvy, S.A. +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v1.0 +-- which accompanies this distribution, and is available at +-- http://www.eclipse.org/legal/epl-v10.html +-- +-- Contributors: +-- Codenvy, S.A. - initial API and implementation +-- + diff --git a/core/che-core-db/src/test/resources/sql/2.0/postgresql/1.modify_test_table.sql b/core/che-core-db/src/test/resources/sql/2.0/postgresql/1.modify_test_table.sql new file mode 100644 index 00000000000..7ec3ed47e93 --- /dev/null +++ b/core/che-core-db/src/test/resources/sql/2.0/postgresql/1.modify_test_table.sql @@ -0,0 +1,11 @@ +-- +-- Copyright (c) 2012-2016 Codenvy, S.A. +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v1.0 +-- which accompanies this distribution, and is available at +-- http://www.eclipse.org/legal/epl-v10.html +-- +-- Contributors: +-- Codenvy, S.A. - initial API and implementation +-- + diff --git a/core/commons/che-core-commons-test/pom.xml b/core/commons/che-core-commons-test/pom.xml index 6e9e00630c6..51157543944 100644 --- a/core/commons/che-core-commons-test/pom.xml +++ b/core/commons/che-core-commons-test/pom.xml @@ -25,6 +25,10 @@ true + + com.h2database + h2 + org.mockito mockito-core diff --git a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2JpaCleaner.java b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2JpaCleaner.java new file mode 100644 index 00000000000..038d2fb3793 --- /dev/null +++ b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2JpaCleaner.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.commons.test.db; + +import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.h2.jdbcx.JdbcDataSource; +import org.h2.tools.RunScript; + +import javax.sql.DataSource; +import java.io.StringReader; +import java.sql.Connection; +import java.sql.SQLException; + +/** + * @author Yevhenii Voevodin + */ +public class H2JpaCleaner extends JpaCleaner { + + private final DataSource dataSource; + + public H2JpaCleaner(DataSource dataSource) { + this.dataSource = dataSource; + } + + public H2JpaCleaner() { + this(H2TestHelper.inMemoryDefault()); + } + + @Override + public void clean() { + super.clean(); + try (Connection conn = dataSource.getConnection()) { + RunScript.execute(conn, new StringReader("SHUTDOWN")); + } catch (SQLException x) { + throw new RuntimeException(x.getMessage(), x); + } + } +} diff --git a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2TestHelper.java b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2TestHelper.java new file mode 100644 index 00000000000..9c68ce037d4 --- /dev/null +++ b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/db/H2TestHelper.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.commons.test.db; + +import org.h2.jdbcx.JdbcDataSource; +import org.h2.tools.RunScript; + +import javax.sql.DataSource; +import java.io.StringReader; +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Provides utility methods to work with h2 in tests. + * + * @author Yevhenii Voevodin + */ +public final class H2TestHelper { + + public static final String DEFAULT_IN_MEMORY_DB_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; + + /** + * Creates new default datasource to in memory database + * with url {@value #DEFAULT_IN_MEMORY_DB_URL}. + * Boots database if this is invoked first time, database + * won't be shutdown until 'SHUTDOWN' query is executed + * or {@link #shutdownDefault()} is called directly. + * + * @return datasource to the in memory database + */ + public static DataSource inMemoryDefault() { + final JdbcDataSource dataSource = new JdbcDataSource(); + dataSource.setUrl(DEFAULT_IN_MEMORY_DB_URL); + return dataSource; + } + + /** + * Shutdowns default in memory database with url {@value #DEFAULT_IN_MEMORY_DB_URL}. + * + * @throws SQLException + * when any sql error occurs + */ + public static void shutdownDefault() throws SQLException { + try (Connection conn = inMemoryDefault().getConnection()) { + RunScript.execute(conn, new StringReader("SHUTDOWN")); + } + } +} diff --git a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/TckListener.java b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/TckListener.java index 4735583c1d3..e09bff4ce7b 100644 --- a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/TckListener.java +++ b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/TckListener.java @@ -105,7 +105,7 @@ * @see org.testng.IInvokedMethodListener * @see TckResourcesCleaner */ -public class TckListener extends AbstractTestListener { +public class TckListener extends TestListenerAdapter { private Injector injector; private Object instance; @@ -158,7 +158,7 @@ private Module createModule(ITestContext testContext, String name) { if (!moduleIterator.hasNext()) { throw new IllegalStateException(format("Couldn't find a TckModule configuration. " + "You probably forgot to configure resources/META-INF/services/%s, or even " + - "provide an implementation of the TckModule which is required by the tck test class %s", + "provide an implementation of the TckModule which is required by the jpa test class %s", TckModule.class.getName(), name)); } diff --git a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/AbstractTestListener.java b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/TestListenerAdapter.java similarity index 95% rename from core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/AbstractTestListener.java rename to core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/TestListenerAdapter.java index a02e977a23e..5ca3a3f3ede 100644 --- a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/AbstractTestListener.java +++ b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/TestListenerAdapter.java @@ -20,7 +20,7 @@ * * @author Yevhenii Voevodin */ -public abstract class AbstractTestListener implements ITestListener { +public abstract class TestListenerAdapter implements ITestListener { @Override public void onTestStart(ITestResult result) {} diff --git a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/repository/JpaTckRepository.java b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/repository/JpaTckRepository.java index 9f29436e683..2ca194431ee 100644 --- a/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/repository/JpaTckRepository.java +++ b/core/commons/che-core-commons-test/src/main/java/org/eclipse/che/commons/test/tck/repository/JpaTckRepository.java @@ -45,9 +45,9 @@ public class JpaTckRepository implements TckRepository { @Inject protected UnitOfWork uow; - private final Class entityClass; + private final Class entityClass; - public JpaTckRepository(Class entityClass) { + public JpaTckRepository(Class entityClass) { this.entityClass = entityClass; } diff --git a/core/commons/che-core-commons-test/src/test/java/org/eclipse/che/commons/test/tck/DBServerListener.java b/core/commons/che-core-commons-test/src/test/java/org/eclipse/che/commons/test/tck/DBServerListener.java index 7b8b7a8ce82..5fcd377986a 100644 --- a/core/commons/che-core-commons-test/src/test/java/org/eclipse/che/commons/test/tck/DBServerListener.java +++ b/core/commons/che-core-commons-test/src/test/java/org/eclipse/che/commons/test/tck/DBServerListener.java @@ -18,7 +18,7 @@ * * @author Yevhenii Voevodin */ -public class DBServerListener extends AbstractTestListener { +public class DBServerListener extends TestListenerAdapter { public static final String DB_SERVER_URL_ATTRIBUTE_NAME = "db_server_url"; public static final String DB_SERVER_URL = "localhost:12345"; diff --git a/core/pom.xml b/core/pom.xml index a6bda978f32..b8a13261083 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -31,7 +31,8 @@ che-core-typescript-dto-maven-plugin che-core-api-core che-core-api-model - che-core-api-jdbc - che-core-api-jdbc-vendor-h2 + che-core-db + che-core-db-vendor-h2 + che-core-db-vendor-postgresql diff --git a/pom.xml b/pom.xml index 85f49568fee..003e7e3e2fa 100644 --- a/pom.xml +++ b/pom.xml @@ -168,16 +168,6 @@ che-core-api-infrastructure-local ${che.version} - - org.eclipse.che.core - che-core-api-jdbc - ${project.version} - - - org.eclipse.che.core - che-core-api-jdbc-vendor-h2 - ${project.version} - org.eclipse.che.core che-core-api-languageserver @@ -312,6 +302,21 @@ che-core-commons-xml ${che.version} + + org.eclipse.che.core + che-core-db + ${project.version} + + + org.eclipse.che.core + che-core-db-vendor-h2 + ${project.version} + + + org.eclipse.che.core + che-core-db-vendor-postgresql + ${project.version} + org.eclipse.che.core che-core-git-impl-jgit @@ -347,6 +352,11 @@ che-core-ide-ui ${che.version} + + org.eclipse.che.core + che-core-sql-schema + ${che.version} + org.eclipse.che.core wsagent-local @@ -902,6 +912,11 @@ che-sample-plugin-wizard-shared ${che.version} + + org.postgresql + postgresql + ${jdbc.postgresql-driver.version} + org.eclipse.che.core che-core-commons-test diff --git a/wsmaster/che-core-api-account/pom.xml b/wsmaster/che-core-api-account/pom.xml index 20f650499c7..18c440ba4ab 100644 --- a/wsmaster/che-core-api-account/pom.xml +++ b/wsmaster/che-core-api-account/pom.xml @@ -48,7 +48,7 @@ org.eclipse.che.core - che-core-api-jdbc + che-core-db provided @@ -78,17 +78,27 @@ org.eclipse.che.core - che-core-api-jdbc-vendor-h2 + che-core-commons-json test org.eclipse.che.core - che-core-commons-json + che-core-commons-test test org.eclipse.che.core - che-core-commons-test + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema + test + + + org.flywaydb + flyway-core test @@ -131,6 +141,24 @@
+ + org.apache.maven.plugins + maven-dependency-plugin + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + diff --git a/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/event/BeforeAccountRemovedEvent.java b/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/event/BeforeAccountRemovedEvent.java index 8b4cedbd14a..87d59985187 100644 --- a/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/event/BeforeAccountRemovedEvent.java +++ b/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/event/BeforeAccountRemovedEvent.java @@ -11,7 +11,7 @@ package org.eclipse.che.account.event; import org.eclipse.che.account.spi.AccountImpl; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEvent; +import org.eclipse.che.core.db.event.CascadeRemovalEvent; /** * Published before {@link AccountImpl account} removed. diff --git a/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/AccountImpl.java b/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/AccountImpl.java index 30c6f17b90f..1bdc591f236 100644 --- a/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/AccountImpl.java +++ b/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/AccountImpl.java @@ -13,12 +13,10 @@ import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.account.spi.jpa.AccountEntityListener; -import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.Id; -import javax.persistence.Index; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; @@ -28,6 +26,7 @@ * Data object for {@link Account}. * * @author Sergii Leschenko + * @author Yevhenii Voevodin */ @Entity(name = "Account") @NamedQueries( @@ -38,17 +37,18 @@ "WHERE a.name = :name") } ) -@Table(indexes = @Index(columnList = "name", unique = true)) +@Table(name = "account") @EntityListeners(AccountEntityListener.class) public class AccountImpl implements Account { @Id + @Column(name = "id") protected String id; - @Column(nullable = false) + @Column(nullable = false, name = "name") protected String name; - @Basic + @Column(name = "type") private String type; public AccountImpl() {} diff --git a/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/jpa/AccountEntityListener.java b/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/jpa/AccountEntityListener.java index 86ada2c34c6..9991ed89051 100644 --- a/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/jpa/AccountEntityListener.java +++ b/wsmaster/che-core-api-account/src/main/java/org/eclipse/che/account/spi/jpa/AccountEntityListener.java @@ -13,7 +13,7 @@ import org.eclipse.che.account.event.BeforeAccountRemovedEvent; import org.eclipse.che.account.spi.AccountImpl; -import org.eclipse.che.api.core.jdbc.jpa.CascadeRemovalException; +import org.eclipse.che.core.db.jpa.CascadeRemovalException; import org.eclipse.che.api.core.notification.EventService; import javax.inject.Inject; diff --git a/wsmaster/che-core-api-account/src/test/java/org/eclipse/che/account/spi/tck/jpa/AccountJpaTckModule.java b/wsmaster/che-core-api-account/src/test/java/org/eclipse/che/account/spi/tck/jpa/AccountJpaTckModule.java index 73079213d84..28875e9eb9e 100644 --- a/wsmaster/che-core-api-account/src/test/java/org/eclipse/che/account/spi/tck/jpa/AccountJpaTckModule.java +++ b/wsmaster/che-core-api-account/src/test/java/org/eclipse/che/account/spi/tck/jpa/AccountJpaTckModule.java @@ -16,24 +16,28 @@ import org.eclipse.che.account.spi.AccountDao; import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.account.spi.jpa.JpaAccountDao; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; -import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.eclipse.che.commons.test.db.H2JpaCleaner; import org.eclipse.che.commons.test.tck.TckModule; import org.eclipse.che.commons.test.tck.TckResourcesCleaner; import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; + +import static org.eclipse.che.commons.test.db.H2TestHelper.inMemoryDefault; /** * @author Sergii Leschenko + * @author Yevhenii Voevodin */ public class AccountJpaTckModule extends TckModule { @Override protected void configure() { install(new JpaPersistModule("main")); - bind(JpaInitializer.class).asEagerSingleton(); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); - bind(TckResourcesCleaner.class).to(JpaCleaner.class); + bind(DBInitializer.class).asEagerSingleton(); + bind(SchemaInitializer.class).toInstance(new FlywaySchemaInitializer(inMemoryDefault(), "che-schema")); + bind(TckResourcesCleaner.class).to(H2JpaCleaner.class); bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(AccountImpl.class)); diff --git a/wsmaster/che-core-api-account/src/test/resources/META-INF/persistence.xml b/wsmaster/che-core-api-account/src/test/resources/META-INF/persistence.xml index 0df1419c141..531ccfb07d6 100644 --- a/wsmaster/che-core-api-account/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/che-core-api-account/src/test/resources/META-INF/persistence.xml @@ -19,13 +19,12 @@ true - + - + - diff --git a/wsmaster/che-core-api-factory/pom.xml b/wsmaster/che-core-api-factory/pom.xml index 66d84f36534..08baecd1e1a 100644 --- a/wsmaster/che-core-api-factory/pom.xml +++ b/wsmaster/che-core-api-factory/pom.xml @@ -114,17 +114,17 @@
org.eclipse.che.core - che-core-api-jdbc + che-core-api-machine provided org.eclipse.che.core - che-core-api-machine + che-core-api-machine-shared provided org.eclipse.che.core - che-core-api-machine-shared + che-core-db provided @@ -149,7 +149,7 @@ org.eclipse.che.core - che-core-api-jdbc-vendor-h2 + che-core-api-account test @@ -157,6 +157,11 @@ che-core-commons-json test + + org.eclipse.che.core + che-core-db-vendor-h2 + test + org.eclipse.persistence eclipselink @@ -225,6 +230,15 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + **/FactoryDaoTest.java + + + diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryImage.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryImage.java index 86350b43c6f..e88e150ade4 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryImage.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryImage.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.factory.server; -import javax.persistence.Basic; +import javax.persistence.Column; import javax.persistence.Embeddable; import java.util.Arrays; import java.util.Objects; @@ -19,13 +19,13 @@ @Embeddable public class FactoryImage { - @Basic + @Column(name = "imagedata") private byte[] imageData; - @Basic + @Column(name = "mediatype") private String mediaType; - @Basic + @Column(name = "name") private String name; public FactoryImage() {} diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java index 0f47dfe29fd..00ad472a567 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java @@ -15,9 +15,9 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; -import org.eclipse.che.api.core.jdbc.jpa.IntegrityConstraintViolationException; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEventSubscriber; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException; +import org.eclipse.che.core.db.event.CascadeRemovalEventSubscriber; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.factory.server.model.impl.FactoryImpl; import org.eclipse.che.api.factory.server.spi.FactoryDao; diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java index 7dbdf64ef58..fce0d12638b 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java @@ -13,10 +13,15 @@ import org.eclipse.che.api.core.model.factory.Action; import javax.persistence.Basic; +import javax.persistence.CollectionTable; +import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; +import javax.persistence.Table; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -27,16 +32,21 @@ * @author Anton Korneta */ @Entity(name = "Action") +@Table(name = "action") public class ActionImpl implements Action { @Id @GeneratedValue + @Column(name = "entityid") private Long entityId; - @Basic + @Column(name = "id") private String id; @ElementCollection + @CollectionTable(name = "action_properties", joinColumns = @JoinColumn(name = "action_entityid")) + @MapKeyColumn(name = "properties_key") + @Column(name = "properties") private Map properties; public ActionImpl() {} diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/AuthorImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/AuthorImpl.java index 0ee622dbbd7..e18730fe814 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/AuthorImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/AuthorImpl.java @@ -12,7 +12,7 @@ import org.eclipse.che.api.core.model.factory.Author; -import javax.persistence.Basic; +import javax.persistence.Column; import javax.persistence.Embeddable; import java.util.Objects; @@ -24,10 +24,10 @@ @Embeddable public class AuthorImpl implements Author { - @Basic + @Column(name = "created") private Long created; - @Basic + @Column(name = "userid") private String userId; public AuthorImpl() {} @@ -72,7 +72,7 @@ public boolean equals(Object obj) { public int hashCode() { int result = 7; result = 31 * result + Objects.hashCode(userId); - result = 31 * result + Long.hashCode(created); + result = 31 * result + Objects.hashCode(created); return result; } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonAttributesImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonAttributesImpl.java index 5def3b61c49..a0bf2a88e4c 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonAttributesImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonAttributesImpl.java @@ -12,7 +12,7 @@ import org.eclipse.che.api.core.model.factory.ButtonAttributes; -import javax.persistence.Basic; +import javax.persistence.Column; import javax.persistence.Embeddable; import java.util.Objects; @@ -24,16 +24,16 @@ @Embeddable public class ButtonAttributesImpl implements ButtonAttributes { - @Basic + @Column(name = "color") private String color; - @Basic + @Column(name = "logo") private String logo; - @Basic + @Column(name = "style") private String style; - @Basic + @Column(name = "counter") private Boolean counter; public ButtonAttributesImpl() {} @@ -99,7 +99,7 @@ public boolean equals(Object obj) { return Objects.equals(color, other.color) && Objects.equals(logo, other.logo) && Objects.equals(style, other.style) - && counter == other.counter; + && Objects.equals(counter, other.counter); } @Override @@ -108,7 +108,7 @@ public int hashCode() { result = 31 * result + Objects.hashCode(color); result = 31 * result + Objects.hashCode(logo); result = 31 * result + Objects.hashCode(style); - result = 31 * result + Boolean.hashCode(counter); + result = 31 * result + Objects.hashCode(counter); return result; } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java index a84dd924190..2654cf363e2 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java @@ -13,12 +13,14 @@ import org.eclipse.che.api.core.model.factory.Button; import org.eclipse.che.api.core.model.factory.ButtonAttributes; +import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.Table; import java.util.Objects; /** @@ -27,16 +29,19 @@ * @author Anton Korneta */ @Entity(name = "Button") +@Table(name = "button") public class ButtonImpl implements Button { @Id @GeneratedValue + @Column(name = "id") private Long id; @Embedded private ButtonAttributesImpl attributes; @Enumerated(EnumType.STRING) + @Column(name = "type") private Type type; public ButtonImpl(ButtonAttributes attributes, diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java index c760bfe00a5..0d25c66dbc6 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java @@ -22,10 +22,12 @@ import org.eclipse.che.commons.lang.NameGenerator; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Embedded; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; @@ -40,7 +42,7 @@ * @author Anton Korneta */ @Entity(name = "Factory") -@Table +@Table(name = "factory") // TODO fix after issue: https://github.com/eclipse/che/issues/2110 //(uniqueConstraints = {@UniqueConstraint(columnNames = {"name", "userId"})}) public class FactoryImpl implements Factory { @@ -50,34 +52,41 @@ public static FactoryImplBuilder builder() { } @Id + @Column(name = "id") private String id; - @Column(nullable = true) + @Column(name = "name", nullable = true) private String name; - @Column(nullable = false) + @Column(name = "version", nullable = false) private String version; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, optional = false) + @JoinColumn(name = "workspace_id") private WorkspaceConfigImpl workspace; @Embedded private AuthorImpl creator; - @OneToOne - @JoinColumn(insertable = false, updatable = false, name = "userId") + // Mapping exists for explicit constraints which allows + // jpa backend to perform operations in correct order + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(insertable = false, updatable = false, name = "userid") private UserImpl userEntity; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "button_id") private ButtonImpl button; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "ide_id") private IdeImpl ide; @Embedded private PoliciesImpl policies; @ElementCollection + @CollectionTable(name = "factory_images", joinColumns = @JoinColumn(name = "factory_id")) private Set images; public FactoryImpl() {} diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java index e818b797a72..458b4320624 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java @@ -16,10 +16,13 @@ import org.eclipse.che.api.core.model.factory.OnProjectsLoaded; import javax.persistence.CascadeType; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; import javax.persistence.OneToOne; +import javax.persistence.Table; import java.util.Objects; /** @@ -28,19 +31,24 @@ * @author Anton Korneta */ @Entity(name = "Ide") +@Table(name = "ide") public class IdeImpl implements Ide { @Id @GeneratedValue + @Column(name = "id") private Long id; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "onapploaded_id") private OnAppLoadedImpl onAppLoaded; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "onprojectsloaded_id") private OnProjectsLoadedImpl onProjectsLoaded; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "onappclosed_id") private OnAppClosedImpl onAppClosed; public IdeImpl() {} diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java index aa2d7b66a7b..14e872827ef 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java @@ -13,10 +13,14 @@ import org.eclipse.che.api.core.model.factory.Action; import org.eclipse.che.api.core.model.factory.OnAppClosed; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; import javax.persistence.OneToMany; +import javax.persistence.Table; import java.util.ArrayList; import java.util.List; @@ -29,13 +33,18 @@ * @author Anton Korneta */ @Entity(name = "OnAppClosed") +@Table(name = "onappclosed") public class OnAppClosedImpl implements OnAppClosed { @Id @GeneratedValue + @Column(name = "id") private Long id; @OneToMany(cascade = ALL, orphanRemoval = true) + @JoinTable(name = "onappclosed_action", + joinColumns = @JoinColumn(name = "onappclosed_id"), + inverseJoinColumns = @JoinColumn(name = "actions_entityid")) private List actions; public OnAppClosedImpl() {} diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java index 169d0e7db6d..e9b843e10fe 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java @@ -13,10 +13,14 @@ import org.eclipse.che.api.core.model.factory.Action; import org.eclipse.che.api.core.model.factory.OnAppLoaded; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; import javax.persistence.OneToMany; +import javax.persistence.Table; import java.util.ArrayList; import java.util.List; @@ -29,13 +33,18 @@ import static javax.persistence.CascadeType.ALL; @Entity(name = "OnAppLoaded") +@Table(name = "onapploaded") public class OnAppLoadedImpl implements OnAppLoaded { @Id @GeneratedValue + @Column(name = "id") private Long id; @OneToMany(cascade = ALL, orphanRemoval = true) + @JoinTable(name = "onapploaded_action", + joinColumns = @JoinColumn(name = "onapploaded_id"), + inverseJoinColumns = @JoinColumn(name = "actions_entityid")) private List actions; public OnAppLoadedImpl() {} diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java index fcf9862f62b..45201efa24b 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java @@ -14,10 +14,14 @@ import org.eclipse.che.api.core.model.factory.OnProjectsLoaded; import javax.persistence.CascadeType; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; import javax.persistence.OneToMany; +import javax.persistence.Table; import java.util.ArrayList; import java.util.List; @@ -29,13 +33,18 @@ * @author Anton Korneta */ @Entity(name = "OnProjectsLoaded") +@Table(name = "onprojectsloaded") public class OnProjectsLoadedImpl implements OnProjectsLoaded { @Id @GeneratedValue + @Column(name = "id") private Long id; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinTable(name = "onprojectsloaded_action", + joinColumns = @JoinColumn(name = "onprojectsloaded_id"), + inverseJoinColumns = @JoinColumn(name = "actions_entityid")) private List actions; public OnProjectsLoadedImpl() {} diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/PoliciesImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/PoliciesImpl.java index 518a77f8765..baf4d173eb6 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/PoliciesImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/PoliciesImpl.java @@ -25,7 +25,7 @@ @Embeddable public class PoliciesImpl implements Policies { - @Basic + @Column(name = "referer") private String referer; @Column(name = "match_reopen") @@ -34,10 +34,10 @@ public class PoliciesImpl implements Policies { @Column(name = "creation_strategy") private String create; - @Basic + @Column(name = "until") private Long until; - @Basic + @Column(name = "since") private Long since; public PoliciesImpl() {} diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryJpaTckRepository.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryJpaTckRepository.java deleted file mode 100644 index c7e938a1357..00000000000 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryJpaTckRepository.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.factory.server.jpa; - -import com.google.inject.persist.Transactional; - -import org.eclipse.che.api.factory.server.model.impl.FactoryImpl; -import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.commons.test.tck.repository.TckRepository; -import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; - -import javax.inject.Inject; -import javax.inject.Provider; -import javax.persistence.EntityManager; -import java.util.Collection; - -/** - * @author Anton Korneta - */ -@Transactional -public class FactoryJpaTckRepository implements TckRepository { - - @Inject - private Provider managerProvider; - - @Override - public void createAll(Collection factories) throws TckRepositoryException { - final EntityManager manager = managerProvider.get(); - for (FactoryImpl factory : factories) { - final String id = factory.getCreator().getUserId(); - manager.persist(new UserImpl(id, "email_" + id, "name_" + id)); - manager.persist(factory); - } - } - - @Override - public void removeAll() throws TckRepositoryException { - final EntityManager manager = managerProvider.get(); - manager.createQuery("SELECT factory FROM Factory factory", FactoryImpl.class) - .getResultList() - .forEach(manager::remove); - } -} diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/JpaTckModule.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/JpaTckModule.java deleted file mode 100644 index 18ac04fa8da..00000000000 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/JpaTckModule.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.factory.server.jpa; - -import com.google.inject.Singleton; -import com.google.inject.TypeLiteral; -import com.google.inject.persist.jpa.JpaPersistModule; - -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; -import org.eclipse.che.api.factory.server.model.impl.FactoryImpl; -import org.eclipse.che.api.factory.server.spi.FactoryDao; -import org.eclipse.che.api.user.server.jpa.JpaProfileDao; -import org.eclipse.che.api.user.server.jpa.JpaUserDao; -import org.eclipse.che.api.user.server.model.impl.ProfileImpl; -import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.api.user.server.spi.ProfileDao; -import org.eclipse.che.api.user.server.spi.UserDao; -import org.eclipse.che.commons.test.tck.JpaCleaner; -import org.eclipse.che.commons.test.tck.TckModule; -import org.eclipse.che.commons.test.tck.TckResourcesCleaner; -import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; -import org.eclipse.che.commons.test.tck.repository.TckRepository; -import org.eclipse.che.security.PasswordEncryptor; -import org.eclipse.che.security.SHA512PasswordEncryptor; - -/** - * @author Anton Korneta - */ -public class JpaTckModule extends TckModule { - - @Override - protected void configure() { - install(new JpaPersistModule("main")); - bind(JpaInitializer.class).asEagerSingleton(); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); - bind(TckResourcesCleaner.class).to(JpaCleaner.class); - - bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(UserImpl.class)); - bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(FactoryImpl.class)); - bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(ProfileImpl.class)); - - - bind(UserDao.class).to(JpaUserDao.class); - bind(ProfileDao.class).to(JpaProfileDao.class); - bind(FactoryDao.class).to(JpaFactoryDao.class); - - bind(PasswordEncryptor.class).to(SHA512PasswordEncryptor.class).in(Singleton.class); - - } -} diff --git a/wsmaster/che-core-api-factory/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule b/wsmaster/che-core-api-factory/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule deleted file mode 100644 index a2e5fdb60c3..00000000000 --- a/wsmaster/che-core-api-factory/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule +++ /dev/null @@ -1 +0,0 @@ -org.eclipse.che.api.factory.server.jpa.JpaTckModule diff --git a/wsmaster/che-core-api-machine/pom.xml b/wsmaster/che-core-api-machine/pom.xml index 187da6b7da6..c6ebcbdb97b 100644 --- a/wsmaster/che-core-api-machine/pom.xml +++ b/wsmaster/che-core-api-machine/pom.xml @@ -102,7 +102,7 @@ org.eclipse.che.core - che-core-api-jdbc + che-core-db provided @@ -128,7 +128,7 @@ org.eclipse.che.core - che-core-api-jdbc-vendor-h2 + che-core-api-account test @@ -141,6 +141,16 @@ che-core-commons-test test + + org.eclipse.che.core + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema + test + org.eclipse.jetty jetty-server @@ -166,6 +176,11 @@ everrest-test test + + org.flywaydb + flyway-core + test + org.mockito mockito-core @@ -205,6 +220,24 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/event/BeforeRecipeRemovedEvent.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/event/BeforeRecipeRemovedEvent.java index 81e28e84a3b..ae41d31b2de 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/event/BeforeRecipeRemovedEvent.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/event/BeforeRecipeRemovedEvent.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.machine.server.event; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEvent; +import org.eclipse.che.core.db.event.CascadeRemovalEvent; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; /** diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaRecipeDao.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaRecipeDao.java index 7b93f1e43d3..b51102bb178 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaRecipeDao.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaRecipeDao.java @@ -15,8 +15,8 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; -import org.eclipse.che.api.core.jdbc.jpa.IntegrityConstraintViolationException; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.machine.server.event.RecipePersistedEvent; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java index b38644e52ab..c1585e1891d 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java @@ -13,7 +13,7 @@ import com.google.inject.persist.Transactional; import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; import org.eclipse.che.api.machine.server.exception.SnapshotException; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.spi.SnapshotDao; diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/RecipeEntityListener.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/RecipeEntityListener.java index 109ebe93432..8aae27fc907 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/RecipeEntityListener.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/RecipeEntityListener.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.machine.server.jpa; -import org.eclipse.che.api.core.jdbc.jpa.CascadeRemovalException; +import org.eclipse.che.core.db.jpa.CascadeRemovalException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.machine.server.event.BeforeRecipeRemovedEvent; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java index af74959ae80..6063d7735fa 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java @@ -12,13 +12,16 @@ import org.eclipse.che.api.core.model.machine.Command; +import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; import javax.persistence.MapKeyColumn; +import javax.persistence.Table; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -29,22 +32,25 @@ * @author Eugene Voevodin */ @Entity(name = "Command") +@Table(name = "command") public class CommandImpl implements Command { @Id @GeneratedValue + @Column(name = "id") private Long id; - @Column(nullable = false) + @Column(name = "name", nullable = false) private String name; - @Column(nullable = false, columnDefinition = "TEXT") + @Column(name = "commandline", nullable = false, columnDefinition = "TEXT") private String commandLine; - @Column(nullable = false) + @Column(name = "type", nullable = false) private String type; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "command_attributes", joinColumns = @JoinColumn(name = "command_id")) @MapKeyColumn(name = "name") @Column(name = "value", columnDefinition = "TEXT") private Map attributes; diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java index 3f5109b540c..d962486c1d8 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java @@ -12,7 +12,6 @@ import org.eclipse.che.api.core.model.machine.MachineSource; -import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Embeddable; import java.util.Objects; @@ -30,10 +29,10 @@ public class MachineSourceImpl implements MachineSource { @Column(name = "source_type") private String type; - @Basic + @Column(name = "location") private String location; - @Column(columnDefinition = "TEXT") + @Column(name = "content", columnDefinition = "TEXT") private String content; public MachineSourceImpl() {} diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java index b9a51f503ba..65abe38edc0 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java @@ -16,12 +16,10 @@ import org.eclipse.che.api.machine.server.spi.Instance; import org.eclipse.che.commons.lang.NameGenerator; -import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.Id; -import javax.persistence.Index; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; @@ -52,7 +50,7 @@ " AND snapshot.envName = :envName") } ) -@Table(indexes = @Index(columnList = "workspaceId, envName, machineName", unique = true)) +@Table(name = "snapshot") public class SnapshotImpl implements Snapshot { public static SnapshotBuilder builder() { @@ -60,27 +58,28 @@ public static SnapshotBuilder builder() { } @Id + @Column(name = "id") private String id; - @Column(nullable = false) + @Column(name = "workspaceid", nullable = false) private String workspaceId; - @Column(nullable = false) + @Column(name = "machinename", nullable = false) private String machineName; - @Column(nullable = false) + @Column(name = "envname", nullable = false) private String envName; - @Basic + @Column(name = "type") private String type; - @Basic + @Column(name = "isdev") private boolean isDev; - @Basic + @Column(name = "creationdate") private long creationDate; - @Column(columnDefinition = "TEXT") + @Column(name = "description", columnDefinition = "TEXT") private String description; @Embedded diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/recipe/RecipeImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/recipe/RecipeImpl.java index deb3ccbb3c4..8c664989004 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/recipe/RecipeImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/recipe/RecipeImpl.java @@ -14,14 +14,14 @@ import org.eclipse.che.api.machine.server.jpa.RecipeEntityListener; import org.eclipse.che.api.machine.shared.ManagedRecipe; -import javax.persistence.Basic; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.Id; -import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.Table; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -33,30 +33,32 @@ * @author Anton Korneta */ @Entity(name = "Recipe") +@Table(name = "recipe") @EntityListeners(RecipeEntityListener.class) public class RecipeImpl implements ManagedRecipe { @Id + @Column(name = "id") private String id; - @Basic + @Column(name = "name") private String name; - @Basic + @Column(name = "creator") private String creator; - @Basic + @Column(name = "type") private String type; - @Column(columnDefinition = "TEXT") + @Column(name = "script", columnDefinition = "TEXT") private String script; - @Column(columnDefinition = "TEXT") + @Column(name = "description", columnDefinition = "TEXT") private String description; @ElementCollection @Column(name = "tag") - @CollectionTable(indexes = @Index(columnList = "tag")) + @CollectionTable(name = "recipe_tags", joinColumns = @JoinColumn(name = "recipe_id")) private List tags; public RecipeImpl() { diff --git a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java index d66a26bc595..9fc4e006e9d 100644 --- a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java +++ b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java @@ -13,17 +13,25 @@ import com.google.inject.TypeLiteral; import com.google.inject.persist.jpa.JpaPersistModule; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; +import org.eclipse.che.account.spi.AccountImpl; +import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; import org.eclipse.che.api.machine.server.spi.RecipeDao; import org.eclipse.che.api.machine.server.spi.SnapshotDao; -import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.eclipse.che.commons.test.db.H2JpaCleaner; +import org.eclipse.che.commons.test.db.H2TestHelper; import org.eclipse.che.commons.test.tck.TckModule; import org.eclipse.che.commons.test.tck.TckResourcesCleaner; import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; + +import java.util.Collection; +import java.util.stream.Collectors; /** * @author Anton Korneta @@ -33,14 +41,28 @@ public class JpaTckModule extends TckModule { @Override protected void configure() { install(new JpaPersistModule("main")); - bind(JpaInitializer.class).asEagerSingleton(); - bind(TckResourcesCleaner.class).to(JpaCleaner.class); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); + bind(DBInitializer.class).asEagerSingleton(); + bind(SchemaInitializer.class).toInstance(new FlywaySchemaInitializer(H2TestHelper.inMemoryDefault(), "che-schema")); + bind(TckResourcesCleaner.class).to(H2JpaCleaner.class); bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(RecipeImpl.class)); bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(SnapshotImpl.class)); + bind(new TypeLiteral>() {}).toInstance(new TestWorkspacesTckRepository()); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(AccountImpl.class)); bind(RecipeDao.class).to(JpaRecipeDao.class); bind(SnapshotDao.class).to(JpaSnapshotDao.class); } + + private static class TestWorkspacesTckRepository extends JpaTckRepository { + + public TestWorkspacesTckRepository() { super(TestWorkspaceEntity.class); } + + @Override + public void createAll(Collection entities) throws TckRepositoryException { + super.createAll(entities.stream() + .map(TestWorkspaceEntity::new) + .collect(Collectors.toList())); + } + } } diff --git a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/TestWorkspaceEntity.java b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/TestWorkspaceEntity.java new file mode 100644 index 00000000000..e6de94ed790 --- /dev/null +++ b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/TestWorkspaceEntity.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.machine.server.jpa; + +import org.eclipse.che.api.core.model.workspace.Workspace; +import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; +import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; +import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; + +/** + * Test implementation of {@link Workspace}, + * default one can't be used due to circular dependency. + * + * @author Yevhenii Voevodin + */ +@Entity(name = "Workspace") +@Table(name = "workspace") +public class TestWorkspaceEntity implements Workspace { + + @Id + @Column(name = "id") + private String id; + + @Column(name = "accountid") + private String accountId; + + public TestWorkspaceEntity() {} + + public TestWorkspaceEntity(Workspace workspace) { + this(workspace.getId(), workspace.getNamespace()); + } + + public TestWorkspaceEntity(String id, String accountId) { + this.id = id; + this.accountId = accountId; + } + + public String getId() { + return id; + } + + @Override + public String getNamespace() { + return "placeholder"; + } + + @Override + public WorkspaceStatus getStatus() { + return WorkspaceStatus.STOPPED; + } + + @Override + public Map getAttributes() { + return Collections.emptyMap(); + } + + @Override + public boolean isTemporary() { + return false; + } + + @Override + public WorkspaceConfig getConfig() { + return null; + } + + @Override + public WorkspaceRuntime getRuntime() { + return null; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TestWorkspaceEntity)) { + return false; + } + final TestWorkspaceEntity that = (TestWorkspaceEntity)obj; + return Objects.equals(id, that.id) + && Objects.equals(accountId, that.accountId); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + Objects.hashCode(accountId); + return hash; + } + + @Override + public String toString() { + return "TestWorkspaceEntity{" + + "id='" + id + '\'' + + ", accountId='" + accountId + '\'' + + '}'; + } +} diff --git a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java index 28a8f6fab5c..1b3ea0eee9a 100644 --- a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java +++ b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java @@ -13,7 +13,12 @@ import com.google.common.collect.Sets; import com.google.inject.Inject; +import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.model.workspace.Workspace; +import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; +import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; +import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.machine.server.exception.SnapshotException; import org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; @@ -29,6 +34,7 @@ import java.util.HashSet; import java.util.List; +import java.util.Map; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -48,7 +54,8 @@ public class SnapshotDaoTest { private static final int SNAPSHOTS_SIZE = 6; - private SnapshotImpl[] snapshots; + private SnapshotImpl[] snapshots; + private TestWorkspace[] workspaces; @Inject private SnapshotDao snapshotDao; @@ -56,21 +63,42 @@ public class SnapshotDaoTest { @Inject private TckRepository snaphotRepo; + @Inject + private TckRepository workspaceRepo; + + @Inject + private TckRepository accountRepo; + @BeforeMethod private void createSnapshots() throws TckRepositoryException { + // one account for all the workspaces + final AccountImpl account = new AccountImpl("account1", "name", "type"); + + // workspaces + workspaces = new TestWorkspace[SNAPSHOTS_SIZE / 3]; + for (int i = 0; i < workspaces.length; i++) { + workspaces[i] = new TestWorkspace("workspace-" + i, account.getId()); + } + + // snapshots snapshots = new SnapshotImpl[SNAPSHOTS_SIZE]; for (int i = 0; i < SNAPSHOTS_SIZE; i++) { snapshots[i] = createSnapshot("snapshot-" + i, - "workspace-" + i / 3, // 3 snapshot share the same workspace id + workspaces[i / 3].getId(), // 3 snapshot share the same workspace id "environment-" + i / 2, // 2 snapshots share the same env name "machine-" + i); } + + accountRepo.createAll(singletonList(account)); + workspaceRepo.createAll(asList(workspaces)); snaphotRepo.createAll(asList(snapshots)); } @AfterMethod private void removeSnapshots() throws TckRepositoryException { snaphotRepo.removeAll(); + workspaceRepo.removeAll(); + accountRepo.removeAll(); } @Test @@ -126,7 +154,7 @@ public void shouldThrowNpeWhenSearchingSnapshotsByNullWorkspaceId() throws Excep @Test(dependsOnMethods = "shouldGetSnapshotById") public void shouldSaveSnapshot() throws Exception { final SnapshotImpl newSnapshot = createSnapshot("new-snapshot", - "workspace-id", + workspaces[0].getId(), "env-name", "machine-name"); @@ -194,8 +222,9 @@ public void replacesSnapshots() throws Exception { singletonList(newSnapshot)); assertEquals(new HashSet<>(replaced), Sets.newHashSet(snapshots[0], snapshots[1])); - assertEquals(new HashSet<>(snapshotDao.findSnapshots(snapshots[0].getWorkspaceId())), - Sets.newHashSet(newSnapshot, snapshots[2])); + final HashSet actual = new HashSet<>(snapshotDao.findSnapshots(this.snapshots[0].getWorkspaceId())); + final HashSet expected = Sets.newHashSet(newSnapshot, this.snapshots[2]); + assertEquals(actual, expected); } @DataProvider(name = "missingSnapshots") @@ -235,4 +264,36 @@ private static SnapshotImpl createSnapshot(String id, .setMachineName(machineName) .build(); } + + private static class TestWorkspace implements Workspace { + + private final String id; + private final String accountId; + + public TestWorkspace(String id, String accountId) { + this.id = id; + this.accountId = accountId; + } + + @Override + public String getId() { return id; } + + @Override + public String getNamespace() { return accountId; } + + @Override + public WorkspaceStatus getStatus() { return null; } + + @Override + public Map getAttributes() { return null; } + + @Override + public boolean isTemporary() { return false; } + + @Override + public WorkspaceConfig getConfig() { return null; } + + @Override + public WorkspaceRuntime getRuntime() { return null; } + } } diff --git a/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml b/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml index 6b7e9b56efe..932e2803dc1 100644 --- a/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml @@ -18,17 +18,17 @@ org.eclipse.che.api.machine.server.recipe.RecipeImpl org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl org.eclipse.che.api.machine.server.model.impl.SnapshotImpl + org.eclipse.che.account.spi.AccountImpl + org.eclipse.che.api.machine.server.jpa.TestWorkspaceEntity true - + - + - - diff --git a/wsmaster/che-core-api-ssh/pom.xml b/wsmaster/che-core-api-ssh/pom.xml index ae075058b7f..a434d8575db 100644 --- a/wsmaster/che-core-api-ssh/pom.xml +++ b/wsmaster/che-core-api-ssh/pom.xml @@ -70,10 +70,6 @@ org.eclipse.che.core che-core-api-dto - - org.eclipse.che.core - che-core-api-jdbc - org.eclipse.che.core che-core-api-ssh-shared @@ -90,6 +86,10 @@ org.eclipse.che.core che-core-commons-test + + org.eclipse.che.core + che-core-db + org.eclipse.persistence javax.persistence @@ -111,7 +111,7 @@ org.eclipse.che.core - che-core-api-jdbc-vendor-h2 + che-core-api-account test @@ -119,6 +119,16 @@ che-core-commons-lang test + + org.eclipse.che.core + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema + test + org.eclipse.persistence eclipselink @@ -129,6 +139,11 @@ everrest-assured test + + org.flywaydb + flyway-core + test + org.hamcrest hamcrest-core @@ -257,6 +272,24 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + diff --git a/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/jpa/JpaSshDao.java b/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/jpa/JpaSshDao.java index 07e233157f3..8211da7dff5 100644 --- a/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/jpa/JpaSshDao.java +++ b/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/jpa/JpaSshDao.java @@ -15,8 +15,8 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEventSubscriber; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.event.CascadeRemovalEventSubscriber; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl; import org.eclipse.che.api.ssh.server.spi.SshDao; diff --git a/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/model/impl/SshPairImpl.java b/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/model/impl/SshPairImpl.java index c9734ca6003..b69f3082a7b 100644 --- a/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/model/impl/SshPairImpl.java +++ b/wsmaster/che-core-api-ssh/src/main/java/org/eclipse/che/api/ssh/server/model/impl/SshPairImpl.java @@ -23,6 +23,7 @@ import javax.persistence.ManyToOne; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; +import javax.persistence.Table; import java.util.Objects; /** @@ -43,20 +44,24 @@ } ) @IdClass(SshPairPrimaryKey.class) +@Table(name = "sshkeypair") public class SshPairImpl implements SshPair { @Id + @Column(name = "owner") private String owner; @Id + @Column(name = "service") private String service; @Id + @Column(name = "name") private String name; - @Column(columnDefinition = "TEXT") + @Column(name = "publickey", columnDefinition = "TEXT") private String publicKey; - @Column(columnDefinition = "TEXT") + @Column(name = "privatekey", columnDefinition = "TEXT") private String privateKey; @ManyToOne diff --git a/wsmaster/che-core-api-ssh/src/test/java/org/eclipse/che/api/ssh/server/jpa/SshTckModule.java b/wsmaster/che-core-api-ssh/src/test/java/org/eclipse/che/api/ssh/server/jpa/SshTckModule.java index 1597e84437d..2bf685ff78c 100644 --- a/wsmaster/che-core-api-ssh/src/test/java/org/eclipse/che/api/ssh/server/jpa/SshTckModule.java +++ b/wsmaster/che-core-api-ssh/src/test/java/org/eclipse/che/api/ssh/server/jpa/SshTckModule.java @@ -13,32 +13,34 @@ import com.google.inject.TypeLiteral; import com.google.inject.persist.jpa.JpaPersistModule; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl; import org.eclipse.che.api.ssh.server.spi.SshDao; import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.eclipse.che.commons.test.db.H2JpaCleaner; +import org.eclipse.che.commons.test.db.H2TestHelper; import org.eclipse.che.commons.test.tck.TckModule; import org.eclipse.che.commons.test.tck.TckResourcesCleaner; import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; /** * @author Mihail Kuznyetsov + * @author Yevhenii Voevodin */ public class SshTckModule extends TckModule { @Override protected void configure() { + install(new JpaPersistModule("main")); + bind(DBInitializer.class).asEagerSingleton(); + bind(SchemaInitializer.class).toInstance(new FlywaySchemaInitializer(H2TestHelper.inMemoryDefault(), "che-schema")); + bind(TckResourcesCleaner.class).to(H2JpaCleaner.class); + bind(SshDao.class).to(JpaSshDao.class); bind(new TypeLiteral>(){}).toInstance(new JpaTckRepository<>(SshPairImpl.class)); bind(new TypeLiteral>(){}).toInstance(new JpaTckRepository<>(UserImpl.class)); - - install(new JpaPersistModule("main")); - bind(JpaInitializer.class).asEagerSingleton(); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); - bind(org.eclipse.che.api.core.h2.jdbc.jpa.eclipselink.H2ExceptionHandler.class); - bind(TckResourcesCleaner.class).to(JpaCleaner.class); } } diff --git a/wsmaster/che-core-api-ssh/src/test/resources/META-INF/persistence.xml b/wsmaster/che-core-api-ssh/src/test/resources/META-INF/persistence.xml index 57239dcebf0..e9c6989426b 100644 --- a/wsmaster/che-core-api-ssh/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/che-core-api-ssh/src/test/resources/META-INF/persistence.xml @@ -16,18 +16,17 @@ org.eclipse.persistence.jpa.PersistenceProvider org.eclipse.che.api.ssh.server.model.impl.SshPairImpl - org.eclipse.che.account.spi.AccountImpl org.eclipse.che.api.user.server.model.impl.UserImpl + org.eclipse.che.account.spi.AccountImpl true - + - + - diff --git a/wsmaster/che-core-api-user/pom.xml b/wsmaster/che-core-api-user/pom.xml index d10a5010eb6..da43480eed7 100644 --- a/wsmaster/che-core-api-user/pom.xml +++ b/wsmaster/che-core-api-user/pom.xml @@ -72,6 +72,10 @@ org.eclipse.che.core che-core-commons-lang + + org.eclipse.che.core + che-core-commons-test + org.slf4j slf4j-api @@ -83,7 +87,7 @@ org.eclipse.che.core - che-core-api-jdbc + che-core-db provided @@ -108,7 +112,7 @@ org.eclipse.che.core - che-core-api-jdbc-vendor-h2 + che-core-commons-inject test @@ -118,7 +122,12 @@ org.eclipse.che.core - che-core-commons-test + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema test @@ -136,6 +145,11 @@ everrest-core test + + org.flywaydb + flyway-core + test + org.mockito @@ -174,6 +188,24 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/CheUserCreator.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/CheUserCreator.java index e81f21a7643..298ca2c11b4 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/CheUserCreator.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/CheUserCreator.java @@ -13,9 +13,8 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; import org.eclipse.che.api.user.server.model.impl.UserImpl; +import org.eclipse.che.core.db.DBInitializer; import javax.annotation.PostConstruct; import javax.inject.Inject; @@ -36,10 +35,7 @@ public class CheUserCreator { @Inject @SuppressWarnings("unused") - // this work around needed for Guice to help initialize components in right sequence, - // because instance of EntityListenerInjectionManagerInitializer should be created before - // jpa callback components (such as UserEntityListener) - private EntityListenerInjectionManagerInitializer initializer; + private DBInitializer initializer; @PostConstruct public void createCheUser() throws ServerException { diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/event/BeforeUserRemovedEvent.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/event/BeforeUserRemovedEvent.java index 3288fe9adb9..8963090a4bd 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/event/BeforeUserRemovedEvent.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/event/BeforeUserRemovedEvent.java @@ -10,8 +10,8 @@ *******************************************************************************/ package org.eclipse.che.api.user.server.event; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEvent; import org.eclipse.che.api.core.notification.EventOrigin; +import org.eclipse.che.core.db.event.CascadeRemovalEvent; import org.eclipse.che.api.user.server.model.impl.UserImpl; /** diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaPreferenceDao.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaPreferenceDao.java index 5be9df38543..85b64d34a26 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaPreferenceDao.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaPreferenceDao.java @@ -13,7 +13,7 @@ import com.google.inject.persist.Transactional; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEventSubscriber; +import org.eclipse.che.core.db.event.CascadeRemovalEventSubscriber; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.user.server.event.BeforeUserRemovedEvent; import org.eclipse.che.api.user.server.spi.PreferenceDao; diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaProfileDao.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaProfileDao.java index 58f2d54ade3..bf1b2923dda 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaProfileDao.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaProfileDao.java @@ -15,9 +15,9 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; -import org.eclipse.che.api.core.jdbc.jpa.IntegrityConstraintViolationException; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEventSubscriber; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException; +import org.eclipse.che.core.db.event.CascadeRemovalEventSubscriber; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.user.server.event.BeforeUserRemovedEvent; import org.eclipse.che.api.user.server.model.impl.ProfileImpl; diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaUserDao.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaUserDao.java index c9d1892dd72..430aad83099 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaUserDao.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/JpaUserDao.java @@ -16,10 +16,10 @@ import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.CascadeRemovalException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.user.server.event.PostUserRemovedEvent; +import org.eclipse.che.core.db.jpa.CascadeRemovalException; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; import org.eclipse.che.api.user.server.model.impl.UserImpl; import org.eclipse.che.api.user.server.spi.UserDao; import org.eclipse.che.security.PasswordEncryptor; diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/PreferenceEntity.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/PreferenceEntity.java index 698b97f4d92..11945110dad 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/PreferenceEntity.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/PreferenceEntity.java @@ -10,15 +10,15 @@ *******************************************************************************/ package org.eclipse.che.api.user.server.jpa; -import org.eclipse.che.api.user.server.model.impl.UserImpl; +import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.Id; -import javax.persistence.Lob; +import javax.persistence.JoinColumn; import javax.persistence.MapKeyColumn; -import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Table; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -27,17 +27,18 @@ * Describes JPA implementation of user's preferences. * * @author Anton Korneta + * @author Yevhenii Voevodin */ @Entity(name = "Preference") +@Table(name = "preference") public class PreferenceEntity { @Id + @Column(name = "userid") private String userId; - @PrimaryKeyJoinColumn - private UserImpl user; - @ElementCollection + @CollectionTable(name = "preference_preferences", joinColumns = @JoinColumn(name = "preference_userid")) @MapKeyColumn(name = "name") @Column(name = "value", columnDefinition = "TEXT") private Map preferences; diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/UserEntityListener.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/UserEntityListener.java index 56fb8f3f34f..cb7c6ccc6d7 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/UserEntityListener.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/jpa/UserEntityListener.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.user.server.jpa; -import org.eclipse.che.api.core.jdbc.jpa.CascadeRemovalException; +import org.eclipse.che.core.db.jpa.CascadeRemovalException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.user.server.event.BeforeUserPersistedEvent; import org.eclipse.che.api.user.server.event.BeforeUserRemovedEvent; diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/ProfileImpl.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/ProfileImpl.java index 89a26b350eb..a42fa20d21c 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/ProfileImpl.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/ProfileImpl.java @@ -20,7 +20,7 @@ import javax.persistence.JoinColumn; import javax.persistence.MapKeyColumn; import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.UniqueConstraint; +import javax.persistence.Table; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -31,9 +31,11 @@ * @author Yevhenii Voevodin */ @Entity(name = "Profile") +@Table(name = "profile") public class ProfileImpl implements Profile { @Id + @Column(name = "userid") private String userId; @PrimaryKeyJoinColumn @@ -42,8 +44,7 @@ public class ProfileImpl implements Profile { @ElementCollection @MapKeyColumn(name = "name") @Column(name = "value", nullable = false) - @CollectionTable(joinColumns = @JoinColumn(name = "user_id"), - uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "name"})) + @CollectionTable(name = "profile_attributes", joinColumns = @JoinColumn(name = "user_id")) private Map attributes; public ProfileImpl() {} diff --git a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/UserImpl.java b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/UserImpl.java index 4d8e6ad9d5d..eeccc3cdde3 100644 --- a/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/UserImpl.java +++ b/wsmaster/che-core-api-user/src/main/java/org/eclipse/che/api/user/server/model/impl/UserImpl.java @@ -14,7 +14,6 @@ import org.eclipse.che.api.core.model.user.User; import org.eclipse.che.api.user.server.jpa.UserEntityListener; -import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.CollectionTable; import javax.persistence.Column; @@ -60,21 +59,22 @@ } ) @EntityListeners(UserEntityListener.class) -@Table(indexes = {@Index(columnList = "email", unique = true)}) +@Table(name = "usr") public class UserImpl implements User { public static final String PERSONAL_ACCOUNT = "personal"; @Id + @Column(name = "id") private String id; @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(nullable = false) + @JoinColumn(nullable = false, name = "account_id") private AccountImpl account; - @Column(nullable = false) + @Column(nullable = false, name = "email") private String email; - @Basic + @Column(name = "password") private String password; @ElementCollection diff --git a/wsmaster/che-core-api-user/src/test/java/org/eclipse/che/api/user/server/jpa/JpaTckModule.java b/wsmaster/che-core-api-user/src/test/java/org/eclipse/che/api/user/server/jpa/JpaTckModule.java index 86bc5c50acc..876060d3c27 100644 --- a/wsmaster/che-core-api-user/src/test/java/org/eclipse/che/api/user/server/jpa/JpaTckModule.java +++ b/wsmaster/che-core-api-user/src/test/java/org/eclipse/che/api/user/server/jpa/JpaTckModule.java @@ -12,31 +12,29 @@ import com.google.inject.Singleton; import com.google.inject.TypeLiteral; -import com.google.inject.name.Names; import com.google.inject.persist.jpa.JpaPersistModule; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; import org.eclipse.che.api.user.server.model.impl.ProfileImpl; import org.eclipse.che.api.user.server.model.impl.UserImpl; import org.eclipse.che.api.user.server.spi.PreferenceDao; import org.eclipse.che.api.user.server.spi.ProfileDao; import org.eclipse.che.api.user.server.spi.UserDao; -import org.eclipse.che.api.user.server.spi.tck.PreferenceDaoTest; -import org.eclipse.che.api.user.server.spi.tck.ProfileDaoTest; -import org.eclipse.che.api.user.server.spi.tck.UserDaoTest; import org.eclipse.che.commons.lang.Pair; -import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.eclipse.che.commons.test.db.H2JpaCleaner; import org.eclipse.che.commons.test.tck.TckModule; import org.eclipse.che.commons.test.tck.TckResourcesCleaner; import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; import org.eclipse.che.security.PasswordEncryptor; import org.eclipse.che.security.SHA512PasswordEncryptor; -import javax.inject.Named; import java.util.Map; +import static org.eclipse.che.commons.test.db.H2TestHelper.inMemoryDefault; + /** * @author Yevhenii Voevodin */ @@ -45,9 +43,9 @@ public class JpaTckModule extends TckModule { @Override protected void configure() { install(new JpaPersistModule("main")); - bind(JpaInitializer.class).asEagerSingleton(); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); - bind(TckResourcesCleaner.class).to(JpaCleaner.class); + bind(DBInitializer.class).asEagerSingleton(); + bind(SchemaInitializer.class).toInstance(new FlywaySchemaInitializer(inMemoryDefault(), "che-schema")); + bind(TckResourcesCleaner.class).to(H2JpaCleaner.class); bind(new TypeLiteral>() {}).to(UserJpaTckRepository.class); bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(ProfileImpl.class)); @@ -56,7 +54,7 @@ protected void configure() { bind(UserDao.class).to(JpaUserDao.class); bind(ProfileDao.class).to(JpaProfileDao.class); bind(PreferenceDao.class).to(JpaPreferenceDao.class); - // SHA-512 ecnryptor is faster than PBKDF2 so it is better for testing + // SHA-512 encryptor is faster than PBKDF2 so it is better for testing bind(PasswordEncryptor.class).to(SHA512PasswordEncryptor.class).in(Singleton.class); } } diff --git a/wsmaster/che-core-api-user/src/test/resources/META-INF/persistence.xml b/wsmaster/che-core-api-user/src/test/resources/META-INF/persistence.xml index ad8838bff7f..515a3863a16 100644 --- a/wsmaster/che-core-api-user/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/che-core-api-user/src/test/resources/META-INF/persistence.xml @@ -22,13 +22,12 @@ true - + - + - diff --git a/wsmaster/che-core-api-workspace/pom.xml b/wsmaster/che-core-api-workspace/pom.xml index 4d2ce46f832..a4b77075b14 100644 --- a/wsmaster/che-core-api-workspace/pom.xml +++ b/wsmaster/che-core-api-workspace/pom.xml @@ -130,7 +130,7 @@ org.eclipse.che.core - che-core-api-jdbc + che-core-db provided @@ -160,12 +160,17 @@ org.eclipse.che.core - che-core-api-jdbc-vendor-h2 + che-core-commons-test test org.eclipse.che.core - che-core-commons-test + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema test @@ -183,6 +188,11 @@ everrest-test test + + org.flywaydb + flyway-core + test + org.mockito @@ -221,6 +231,24 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeStackRemovedEvent.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeStackRemovedEvent.java index d16be41c97c..f1ece9c3c26 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeStackRemovedEvent.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeStackRemovedEvent.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.workspace.server.event; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEvent; +import org.eclipse.che.core.db.event.CascadeRemovalEvent; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; /** diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeWorkspaceRemovedEvent.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeWorkspaceRemovedEvent.java index 902507012dc..7cbff6cc505 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeWorkspaceRemovedEvent.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/event/BeforeWorkspaceRemovedEvent.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.workspace.server.event; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEvent; +import org.eclipse.che.core.db.event.CascadeRemovalEvent; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; /** diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java index 9bca589ec33..eefb27f66c2 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java @@ -15,7 +15,7 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.workspace.server.event.StackPersistedEvent; import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java index 1d1cf7d73d5..e41e101a8dc 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java @@ -16,8 +16,8 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEventSubscriber; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; +import org.eclipse.che.core.db.event.CascadeRemovalEventSubscriber; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.api.workspace.server.event.BeforeWorkspaceRemovedEvent; @@ -49,7 +49,7 @@ public class JpaWorkspaceDao implements WorkspaceDao { @Inject private EventService eventService; @Inject - private Provider manager; + private Provider managerProvider; @Override public WorkspaceImpl create(WorkspaceImpl workspace) throws ConflictException, ServerException { @@ -96,7 +96,7 @@ public void remove(String id) throws ConflictException, ServerException { public WorkspaceImpl get(String id) throws NotFoundException, ServerException { requireNonNull(id, "Required non-null id"); try { - final WorkspaceImpl workspace = manager.get().find(WorkspaceImpl.class, id); + final WorkspaceImpl workspace = managerProvider.get().find(WorkspaceImpl.class, id); if (workspace == null) { throw new NotFoundException(format("Workspace with id '%s' doesn't exist", id)); } @@ -112,11 +112,11 @@ public WorkspaceImpl get(String name, String namespace) throws NotFoundException requireNonNull(name, "Required non-null name"); requireNonNull(namespace, "Required non-null namespace"); try { - return manager.get() - .createNamedQuery("Workspace.getByName", WorkspaceImpl.class) - .setParameter("namespace", namespace) - .setParameter("name", name) - .getSingleResult(); + return managerProvider.get() + .createNamedQuery("Workspace.getByName", WorkspaceImpl.class) + .setParameter("namespace", namespace) + .setParameter("name", name) + .getSingleResult(); } catch (NoResultException noResEx) { throw new NotFoundException(format("Workspace with name '%s' in namespace '%s' doesn't exist", name, @@ -131,10 +131,10 @@ public WorkspaceImpl get(String name, String namespace) throws NotFoundException public List getByNamespace(String namespace) throws ServerException { requireNonNull(namespace, "Required non-null namespace"); try { - return manager.get() - .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) - .setParameter("namespace", namespace) - .getResultList(); + return managerProvider.get() + .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) + .setParameter("namespace", namespace) + .getResultList(); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -145,7 +145,7 @@ public List getByNamespace(String namespace) throws ServerExcepti public List getWorkspaces(String userId) throws ServerException { // TODO respect userId when workers become a part of che try { - return manager.get().createNamedQuery("Workspace.getAll", WorkspaceImpl.class).getResultList(); + return managerProvider.get().createNamedQuery("Workspace.getAll", WorkspaceImpl.class).getResultList(); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -156,27 +156,28 @@ protected void doCreate(WorkspaceImpl workspace) { if (workspace.getConfig() != null) { workspace.getConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); } - manager.get().persist(workspace); + managerProvider.get().persist(workspace); } @Transactional protected void doRemove(String id) { - final WorkspaceImpl workspace = manager.get().find(WorkspaceImpl.class, id); + final WorkspaceImpl workspace = managerProvider.get().find(WorkspaceImpl.class, id); if (workspace != null) { - manager.get().remove(workspace); + final EntityManager manager = managerProvider.get(); + manager.remove(workspace); } eventService.publish(new WorkspaceRemovedEvent(workspace)); } @Transactional protected WorkspaceImpl doUpdate(WorkspaceImpl update) throws NotFoundException { - if (manager.get().find(WorkspaceImpl.class, update.getId()) == null) { + if (managerProvider.get().find(WorkspaceImpl.class, update.getId()) == null) { throw new NotFoundException(format("Workspace with id '%s' doesn't exist", update.getId())); } if (update.getConfig() != null) { update.getConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); } - return manager.get().merge(update); + return managerProvider.get().merge(update); } @Singleton diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/StackEntityListener.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/StackEntityListener.java index 2ab85d1c603..9ae2f651f9c 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/StackEntityListener.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/StackEntityListener.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.workspace.server.jpa; -import org.eclipse.che.api.core.jdbc.jpa.CascadeRemovalException; +import org.eclipse.che.core.db.jpa.CascadeRemovalException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.workspace.server.event.BeforeStackRemovedEvent; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceEntityListener.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceEntityListener.java index 6f0349f997f..dccf968f0fc 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceEntityListener.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceEntityListener.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.workspace.server.jpa; -import org.eclipse.che.api.core.jdbc.jpa.CascadeRemovalException; +import org.eclipse.che.core.db.jpa.CascadeRemovalException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.workspace.server.event.BeforeWorkspaceRemovedEvent; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java index ecdecf2a8cb..50151c1a323 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java @@ -15,13 +15,16 @@ import org.eclipse.che.api.core.model.workspace.ExtendedMachine; import javax.persistence.CascadeType; +import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; +import javax.persistence.Table; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -32,17 +35,20 @@ * @author Yevhenii Voevodin */ @Entity(name = "Environment") +@Table(name = "environment") public class EnvironmentImpl implements Environment { @Id @GeneratedValue + @Column(name = "id") private Long id; @Embedded private EnvironmentRecipeImpl recipe; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JoinColumn + @JoinColumn(name = "machines_id") + @MapKeyColumn(name = "machines_key") private Map machines; public EnvironmentImpl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentRecipeImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentRecipeImpl.java index 251a1b9b693..729d8ad04b8 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentRecipeImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentRecipeImpl.java @@ -23,16 +23,16 @@ @Embeddable public class EnvironmentRecipeImpl implements EnvironmentRecipe { - @Basic + @Column(name = "type") private String type; - @Basic + @Column(name = "contenttype") private String contentType; - @Column(columnDefinition = "TEXT") + @Column(name = "content", columnDefinition = "TEXT") private String content; - @Column(columnDefinition = "TEXT") + @Column(name = "location", columnDefinition = "TEXT") private String location; public EnvironmentRecipeImpl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java index 1ef6312ae3c..69099971194 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java @@ -14,13 +14,17 @@ import org.eclipse.che.api.core.model.workspace.ServerConf2; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; +import javax.persistence.Table; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -32,20 +36,30 @@ * @author Alexander Garagatyi */ @Entity(name = "ExternalMachine") +@Table(name = "externalmachine") public class ExtendedMachineImpl implements ExtendedMachine { @Id @GeneratedValue + @Column(name = "id") private Long id; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "externalmachine_agents", + joinColumns = @JoinColumn(name = "externalmachine_id")) + @Column(name = "agents") private List agents; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "externalmachine_attributes", + joinColumns = @JoinColumn(name = "externalmachine_id")) + @MapKeyColumn(name = "attributes_key") + @Column(name = "attributes") private Map attributes; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JoinColumn + @JoinColumn(name = "servers_id") + @MapKeyColumn(name = "servers_key") private Map servers; public ExtendedMachineImpl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java index f83d69b7fc9..3c3589a7fc4 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java @@ -14,8 +14,8 @@ import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.model.project.SourceStorage; -import javax.persistence.Basic; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; @@ -29,6 +29,7 @@ import javax.persistence.PostLoad; import javax.persistence.PrePersist; import javax.persistence.PreUpdate; +import javax.persistence.Table; import javax.persistence.Transient; import java.util.ArrayList; import java.util.HashMap; @@ -45,32 +46,37 @@ * @author Dmitry Shnurenko */ @Entity(name = "ProjectConfig") +@Table(name = "projectconfig") public class ProjectConfigImpl implements ProjectConfig { @Id @GeneratedValue + @Column(name = "id") private Long id; - @Column(nullable = false) + @Column(name = "path", nullable = false) private String path; - @Column + @Column(name = "name") private String name; - @Basic + @Column(name = "type") private String type; - @Column(columnDefinition = "TEXT") + @Column(name = "description", columnDefinition = "TEXT") private String description; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "source_id") private SourceStorageImpl source; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "projectconfig_mixins", joinColumns = @JoinColumn(name = "projectconfig_id")) + @Column(name = "mixins") private List mixins; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JoinColumn + @JoinColumn(name = "dbattributes_id") @MapKey(name = "name") private Map dbAttributes; @@ -209,7 +215,7 @@ public String toString() { } /** - * Synchronizes instance attribute with db attributes, + * Synchronizes instance attributes with db attributes, * should be called by internal components in needed places, * this can't be done neither by {@link PrePersist} nor by {@link PreUpdate} * as when the entity is merged the transient attribute won't be passed @@ -240,16 +246,20 @@ private void postLoadAttributes() { } @Entity(name = "ProjectAttribute") + @Table(name = "projectattribute") private static class Attribute { @Id @GeneratedValue + @Column(name = "id") private Long id; - @Basic + @Column(name = "name") private String name; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "projectattribute_values", joinColumns = @JoinColumn(name = "projectattribute_id")) + @Column(name = "values") private List values; public Attribute() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java index 387b35e2a60..f972c69db81 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java @@ -12,12 +12,16 @@ import org.eclipse.che.api.core.model.workspace.ServerConf2; -import javax.persistence.Basic; +import javax.persistence.CollectionTable; +import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; +import javax.persistence.Table; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -26,19 +30,25 @@ * @author Alexander Garagatyi */ @Entity(name = "ServerConf") +@Table(name = "serverconf") public class ServerConf2Impl implements ServerConf2 { @Id @GeneratedValue + @Column(name = "id") private Long id; - @Basic + @Column(name = "port") private String port; - @Basic + @Column(name = "protocol") private String protocol; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "serverconf_properties", + joinColumns = @JoinColumn(name = "serverconf_id")) + @MapKeyColumn(name = "properties_key") + @Column(name = "properties") private Map properties; public ServerConf2Impl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java index 989cb73877f..08b18ac74b7 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java @@ -12,13 +12,16 @@ import org.eclipse.che.api.core.model.project.SourceStorage; -import javax.persistence.Basic; +import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; +import javax.persistence.Table; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -29,19 +32,24 @@ * @author Yevhenii Voevodin */ @Entity(name = "SourceStorage") +@Table(name = "sourcestorage") public class SourceStorageImpl implements SourceStorage { @Id @GeneratedValue + @Column(name = "id") private Long id; - @Basic + @Column(name = "type") private String type; - @Column(columnDefinition = "TEXT") + @Column(name = "location", columnDefinition = "TEXT") private String location; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "sourcestorage_parameters", joinColumns = @JoinColumn(name = "sourcestorage_id")) + @MapKeyColumn(name = "parameters_key") + @Column(name = "parameters") private Map parameters; public SourceStorageImpl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java index 1ac45747c3b..47340d0f7a7 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java @@ -24,9 +24,11 @@ import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; import javax.persistence.PrePersist; import javax.persistence.PreUpdate; +import javax.persistence.Table; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -44,6 +46,7 @@ * @author Yevhenii Voevodin */ @Entity(name = "WorkspaceConfig") +@Table(name = "workspaceconfig") public class WorkspaceConfigImpl implements WorkspaceConfig { public static WorkspaceConfigImplBuilder builder() { @@ -52,27 +55,29 @@ public static WorkspaceConfigImplBuilder builder() { @Id @GeneratedValue + @Column(name = "id") private Long id; - @Column(nullable = false) + @Column(name = "name", nullable = false) private String name; - @Column(columnDefinition = "TEXT") + @Column(name = "description", columnDefinition = "TEXT") private String description; - @Column(nullable = false) + @Column(name = "defaultenv", nullable = false) private String defaultEnv; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JoinColumn + @JoinColumn(name = "commands_id") private List commands; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JoinColumn + @JoinColumn(name = "projects_id") private List projects; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JoinColumn + @JoinColumn(name = "environments_id") + @MapKeyColumn(name = "environments_key") private Map environments; public WorkspaceConfigImpl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java index e340c8487c0..b4f09cda382 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java @@ -12,7 +12,6 @@ import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.account.spi.AccountImpl; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.DescriptorEventAdapter; import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; @@ -21,9 +20,10 @@ import org.eclipse.che.api.workspace.server.jpa.WorkspaceEntityListener; import org.eclipse.che.commons.lang.NameGenerator; import org.eclipse.persistence.descriptors.DescriptorEvent; +import org.eclipse.persistence.descriptors.DescriptorEventAdapter; -import javax.persistence.Basic; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; @@ -32,6 +32,7 @@ import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.MapKeyColumn; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToMany; @@ -40,7 +41,6 @@ import javax.persistence.PreUpdate; import javax.persistence.Table; import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,7 +52,7 @@ * @author Yevhenii Voevodin */ @Entity(name = "Workspace") -@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"name", "accountId"})) +@Table(name = "workspace") @NamedQueries( { @NamedQuery(name = "Workspace.getByNamespace", @@ -71,6 +71,7 @@ public static WorkspaceImplBuilder builder() { } @Id + @Column(name = "id") private String id; /** @@ -78,29 +79,33 @@ public static WorkspaceImplBuilder builder() { * this attribute is stored for unique constraint with account id. * See {@link #syncName()}. */ - @Column + @Column(name = "name") private String name; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "config_id") private WorkspaceConfigImpl config; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "workspace_attributes", joinColumns = @JoinColumn(name = "workspace_id")) + @MapKeyColumn(name = "attributes_key") + @Column(name = "attributes") private Map attributes; - @Basic + @Column(name = "istemporary") private boolean isTemporary; - // This mapping is present here just for generation of the constraint between + @ManyToOne + @JoinColumn(name = "accountid", nullable = false) + private AccountImpl account; + + // This mapping is for explicit constraint between // snapshots and workspace, it's impossible to do so on snapshot side - // as workspace and machine are different modules and cyclic reference will appear + // as workspace and machine are different modules and cyclic reference will appear. @OneToMany(fetch = FetchType.LAZY) @JoinColumn(name = "workspaceId", insertable = false, updatable = false) private List snapshots; - @ManyToOne - @JoinColumn(name = "accountId", nullable = false) - private AccountImpl account; - @Transient private WorkspaceStatus status; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackComponentImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackComponentImpl.java index f8fe52a9dee..93b55318531 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackComponentImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackComponentImpl.java @@ -13,6 +13,7 @@ import org.eclipse.che.api.workspace.shared.stack.StackComponent; import javax.persistence.Basic; +import javax.persistence.Column; import javax.persistence.Embeddable; import java.util.Objects; @@ -24,10 +25,10 @@ @Embeddable public class StackComponentImpl implements StackComponent { - @Basic + @Column(name = "name") private String name; - @Basic + @Column(name = "version") private String version; public StackComponentImpl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackImpl.java index 46c04d52ee8..63ac8c14860 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackImpl.java @@ -19,7 +19,6 @@ import org.eclipse.che.api.workspace.shared.stack.StackSource; import org.eclipse.che.commons.lang.NameGenerator; -import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.CollectionTable; import javax.persistence.Column; @@ -28,10 +27,11 @@ import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.Id; -import javax.persistence.Index; +import javax.persistence.JoinColumn; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToOne; +import javax.persistence.Table; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -59,6 +59,7 @@ ) @EntityListeners(StackEntityListener.class) +@Table(name = "stack") public class StackImpl implements Stack { public static StackBuilder builder() { @@ -66,32 +67,35 @@ public static StackBuilder builder() { } @Id + @Column(name = "id") private String id; - @Column(unique = true, nullable = false) + @Column(name = "name", unique = true, nullable = false) private String name; - @Column(columnDefinition = "TEXT") + @Column(name = "description", columnDefinition = "TEXT") private String description; - @Basic + @Column(name = "scope") private String scope; - @Basic + @Column(name = "creator") private String creator; @ElementCollection @Column(name = "tag") - @CollectionTable(indexes = @Index(columnList = "tag")) + @CollectionTable(name = "stack_tags", joinColumns = @JoinColumn(name = "stack_id")) private List tags; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "workspaceconfig_id") private WorkspaceConfigImpl workspaceConfig; @Embedded private StackSourceImpl source; @ElementCollection + @CollectionTable(name = "stack_components", joinColumns = @JoinColumn(name = "stack_id")) private List components; @Embedded diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackSourceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackSourceImpl.java index 1f3f55f45bc..921c4bc44ae 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackSourceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/stack/StackSourceImpl.java @@ -14,6 +14,7 @@ import org.eclipse.che.api.workspace.shared.stack.StackSource; import javax.persistence.Basic; +import javax.persistence.Column; import javax.persistence.Embeddable; import java.util.Objects; @@ -25,10 +26,10 @@ @Embeddable public class StackSourceImpl implements StackSource { - @Basic + @Column(name = "type") private String type; - @Basic + @Column(name = "origin") private String origin; public StackSourceImpl() {} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/StackLoader.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/StackLoader.java index 8f250fef5a7..73944155b97 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/StackLoader.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/StackLoader.java @@ -21,7 +21,7 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; +import org.eclipse.che.core.db.DBInitializer; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; import org.eclipse.che.api.workspace.server.spi.StackDao; import org.eclipse.che.api.workspace.server.stack.image.StackIcon; @@ -60,7 +60,7 @@ public class StackLoader { public StackLoader(@Named("che.stacks.storage") String stacksPath, @Named("che.stacks.images") String stackIconFolder, StackDao stackDao, - EntityListenerInjectionManagerInitializer installer) { + DBInitializer dbInitializer) { this.stackJsonPath = Paths.get(stacksPath); this.stackIconFolderPath = Paths.get(stackIconFolder); this.stackDao = stackDao; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/image/StackIcon.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/image/StackIcon.java index e88c9d56514..6c7d46ae724 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/image/StackIcon.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/stack/image/StackIcon.java @@ -30,10 +30,10 @@ public class StackIcon { @Column(name = "icon_name") private String name; - @Basic + @Column(name = "mediatype") private String mediaType; - @Basic + @Column(name = "data") private byte[] data; public StackIcon() {} diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDaoTest.java index d58062cf794..e20024b60b3 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDaoTest.java @@ -14,7 +14,9 @@ import com.google.inject.Injector; import org.eclipse.che.account.spi.AccountImpl; -import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; +import org.eclipse.che.commons.test.db.H2JpaCleaner; +import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.eclipse.che.core.db.jpa.DuplicateKeyException; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.testng.annotations.AfterMethod; @@ -39,12 +41,14 @@ public class JpaWorkspaceDaoTest { private EntityManager manager; private JpaWorkspaceDao workspaceDao; + private JpaCleaner cleaner; @BeforeMethod private void setUpManager() { final Injector injector = Guice.createInjector(new WorkspaceTckModule()); manager = injector.getInstance(EntityManager.class); workspaceDao = injector.getInstance(JpaWorkspaceDao.class); + cleaner = injector.getInstance(H2JpaCleaner.class); } @AfterMethod @@ -57,7 +61,7 @@ private void cleanup() { manager.remove(entity); } manager.getTransaction().commit(); - manager.getEntityManagerFactory().close(); + cleaner.clean(); } @Test diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java index fa800fde801..39176866ee4 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java @@ -14,17 +14,19 @@ import com.google.inject.persist.jpa.JpaPersistModule; import org.eclipse.che.account.spi.AccountImpl; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; import org.eclipse.che.api.workspace.server.spi.StackDao; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; -import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.eclipse.che.commons.test.db.H2JpaCleaner; +import org.eclipse.che.commons.test.db.H2TestHelper; import org.eclipse.che.commons.test.tck.TckModule; import org.eclipse.che.commons.test.tck.TckResourcesCleaner; import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; /** * @author Yevhenii Voevodin @@ -34,10 +36,9 @@ public class WorkspaceTckModule extends TckModule { @Override protected void configure() { install(new JpaPersistModule("main")); - bind(JpaInitializer.class).asEagerSingleton(); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); - bind(org.eclipse.che.api.core.h2.jdbc.jpa.eclipselink.H2ExceptionHandler.class); - bind(TckResourcesCleaner.class).to(JpaCleaner.class); + bind(DBInitializer.class).asEagerSingleton(); + bind(SchemaInitializer.class).toInstance(new FlywaySchemaInitializer(H2TestHelper.inMemoryDefault(), "che-schema")); + bind(TckResourcesCleaner.class).to(H2JpaCleaner.class); bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(AccountImpl.class)); bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(WorkspaceImpl.class)); diff --git a/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml b/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml index 049b389a0a0..9928cb7c97d 100644 --- a/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml @@ -33,14 +33,12 @@ true - + - + - - diff --git a/wsmaster/che-core-sql-schema/pom.xml b/wsmaster/che-core-sql-schema/pom.xml new file mode 100644 index 00000000000..f69d2a3f2b9 --- /dev/null +++ b/wsmaster/che-core-sql-schema/pom.xml @@ -0,0 +1,23 @@ + + + + 4.0.0 + + che-master-parent + org.eclipse.che.core + 5.0.0-M8-SNAPSHOT + + che-core-sql-schema + Che Core :: SQL :: Schema + diff --git a/wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M8/1__init.sql b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M8/1__init.sql new file mode 100644 index 00000000000..68a131fe789 --- /dev/null +++ b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M8/1__init.sql @@ -0,0 +1,424 @@ +-- +-- Copyright (c) 2012-2016 Codenvy, S.A. +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v1.0 +-- which accompanies this distribution, and is available at +-- http://www.eclipse.org/legal/epl-v10.html +-- +-- Contributors: +-- Codenvy, S.A. - initial API and implementation +-- + +-- Account --------------------------------------------------------------------- +CREATE TABLE account ( + id VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + type VARCHAR(255), + + PRIMARY KEY (id) +); +-- indexes +CREATE UNIQUE INDEX index_account_name ON account (name); +-------------------------------------------------------------------------------- + + +-- User ------------------------------------------------------------------------ +CREATE TABLE usr ( + id VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL, + account_id VARCHAR(255) NOT NULL, + password VARCHAR(255), + + PRIMARY KEY (id) +); +-- indexes +CREATE UNIQUE INDEX index_usr_email ON usr (email); +-- constraints +ALTER TABLE usr ADD CONSTRAINT fk_usr_account_id FOREIGN KEY (account_id) REFERENCES account (id); +-------------------------------------------------------------------------------- + + +-- User aliases ---------------------------------------------------------------- +CREATE TABLE user_aliases ( + user_id VARCHAR(255), + alias VARCHAR(255) NOT NULL UNIQUE +); +--indexes +CREATE INDEX index_user_aliases_alias ON user_aliases (alias); +--constraints +ALTER TABLE user_aliases ADD CONSTRAINT fk_user_aliases_user_id FOREIGN KEY (user_id) REFERENCES usr (id); +-------------------------------------------------------------------------------- + + +-- Profile --------------------------------------------------------------------- +CREATE TABLE profile ( + userid VARCHAR(255) NOT NULL, + + PRIMARY KEY (userid) +); +-- constraints +ALTER TABLE profile ADD CONSTRAINT fk_profile_userid FOREIGN KEY (userid) REFERENCES usr (id); +-------------------------------------------------------------------------------- + + +-- Profile Attribute ----------------------------------------------------------- +CREATE TABLE profile_attributes ( + user_id VARCHAR(255), + value VARCHAR(255) NOT NULL, + name VARCHAR(255) +); +-- constraints +ALTER TABLE profile_attributes ADD CONSTRAINT unq_profile_attributes_0 UNIQUE (user_id, name); +ALTER TABLE profile_attributes ADD CONSTRAINT fk_profile_attributes_user_id FOREIGN KEY (user_id) REFERENCES profile (userid); +-------------------------------------------------------------------------------- + + +-- Preferences ----------------------------------------------------------------- +CREATE TABLE preference ( + userid VARCHAR(255) NOT NULL, + + PRIMARY KEY (userid) +); +-- constraints +ALTER TABLE preference ADD CONSTRAINT fk_preference_userid FOREIGN KEY (userid) REFERENCES usr (id); +-------------------------------------------------------------------------------- + + +-- Preferences Preferences ----------------------------------------------------- +CREATE TABLE preference_preferences ( + preference_userid VARCHAR(255), + value TEXT, + name VARCHAR(255) +); +-- constraints +ALTER TABLE preference_preferences ADD CONSTRAINT fk_preference_preferences_preference_userid FOREIGN KEY (preference_userid) REFERENCES preference (userid); +-------------------------------------------------------------------------------- + + +-- SSH ------------------------------------------------------------------------- +CREATE TABLE sshkeypair ( + owner VARCHAR(255) NOT NULL, + service VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + privatekey TEXT, + publickey TEXT, + + PRIMARY KEY (owner, service, name) +); +-- constraints +ALTER TABLE sshkeypair ADD CONSTRAINT fk_sshkeypair_owner FOREIGN KEY (owner) REFERENCES usr (id); +-------------------------------------------------------------------------------- + + +-- Workspace configuration ----------------------------------------------------- +CREATE TABLE workspaceconfig ( + id BIGINT NOT NULL, + defaultenv VARCHAR(255) NOT NULL, + description TEXT, + name VARCHAR(255) NOT NULL, + + PRIMARY KEY (id) +); +-------------------------------------------------------------------------------- + + +-- Workspace ------------------------------------------------------------------- +CREATE TABLE workspace ( + id VARCHAR(255) NOT NULL, + istemporary BOOLEAN, + name VARCHAR(255), + accountid VARCHAR(255) NOT NULL, + config_id BIGINT, + + PRIMARY KEY (id) +); +--constraints +ALTER TABLE workspace ADD CONSTRAINT unq_workspace_0 UNIQUE (name, accountid); +ALTER TABLE workspace ADD CONSTRAINT fx_workspace_accountid FOREIGN KEY (accountid) REFERENCES account (id); +ALTER TABLE workspace ADD CONSTRAINT fk_workspace_config_id FOREIGN KEY (config_id) REFERENCES workspaceconfig (id); +-------------------------------------------------------------------------------- + + +--Workspace attributes --------------------------------------------------------- +CREATE TABLE workspace_attributes ( + workspace_id VARCHAR(255), + attributes VARCHAR(255), + attributes_key VARCHAR(255) +); +--constraints +ALTER TABLE workspace_attributes ADD CONSTRAINT fk_workspace_attributes_workspace_id FOREIGN KEY (workspace_id) REFERENCES workspace (id); +-------------------------------------------------------------------------------- + + +-- Project source -------------------------------------------------------------- +CREATE TABLE sourcestorage ( + id BIGINT NOT NULL, + location TEXT, + type VARCHAR(255), + + PRIMARY KEY (id) +); +-------------------------------------------------------------------------------- + + +-- Project source parameters---------------------------------------------------- +CREATE TABLE sourcestorage_parameters ( + sourcestorage_id BIGINT, + parameters VARCHAR(255), + parameters_key VARCHAR(255) +); +--constraints +ALTER TABLE sourcestorage_parameters ADD CONSTRAINT fk_sourcestorage_parameters_sourcestorage_id FOREIGN KEY (sourcestorage_id) REFERENCES sourcestorage (id); +-------------------------------------------------------------------------------- + + +-- Project configuration ------------------------------------------------------- +CREATE TABLE projectconfig ( + id BIGINT NOT NULL, + description TEXT, + name VARCHAR(255), + path VARCHAR(255) NOT NULL, + type VARCHAR(255), + source_id BIGINT, + projects_id BIGINT, + + PRIMARY KEY (id) +); + +-- constraints +ALTER TABLE projectconfig ADD CONSTRAINT fk_projectconfig_projects_id FOREIGN KEY (projects_id) REFERENCES workspaceconfig (id); +ALTER TABLE projectconfig ADD CONSTRAINT fk_projectconfig_source_id FOREIGN KEY (source_id) REFERENCES sourcestorage (id); +-------------------------------------------------------------------------------- + + +-- Project attributes ---------------------------------------------------------- +CREATE TABLE projectattribute ( + id BIGINT NOT NULL, + name VARCHAR(255), + dbattributes_id BIGINT, + + PRIMARY KEY (id) +); +--constraints +ALTER TABLE projectattribute ADD CONSTRAINT fk_projectattribute_dbattributes_id FOREIGN KEY (dbattributes_id) REFERENCES projectconfig (id); +-------------------------------------------------------------------------------- + + +-- Project attribute values ---------------------------------------------------- +CREATE TABLE projectattribute_values ( + projectattribute_id BIGINT, + values VARCHAR(255) +); +--constraints +ALTER TABLE projectattribute_values ADD CONSTRAINT fk_projectattribute_values_projectattribute_id FOREIGN KEY (projectattribute_id) REFERENCES projectattribute (id); +-------------------------------------------------------------------------------- + + +-- Project mixins -------------------------------------------------------------- +CREATE TABLE projectconfig_mixins ( + projectconfig_id BIGINT, + mixins VARCHAR(255) +); +--constraints +ALTER TABLE projectconfig_mixins ADD CONSTRAINT fk_projectconfig_mixins_projectconfig_id FOREIGN KEY (projectconfig_id) REFERENCES projectconfig (id); +-------------------------------------------------------------------------------- + + +-- Commands -------------------------------------------------------------------- +CREATE TABLE command ( + id BIGINT NOT NULL, + commandline TEXT, + name VARCHAR(255) NOT NULL, + type VARCHAR(255) NOT NULL, + commands_id BIGINT, + + PRIMARY KEY (id) +); +--constraints +ALTER TABLE command ADD CONSTRAINT fk_command_commands_id FOREIGN KEY (commands_id) REFERENCES workspaceconfig (id); +-------------------------------------------------------------------------------- + + +-- Command attributes ---------------------------------------------------------- +CREATE TABLE command_attributes ( + command_id BIGINT, + value TEXT, + name VARCHAR(255) +); +--constraints +ALTER TABLE command_attributes ADD CONSTRAINT fk_command_attributes_command_id FOREIGN KEY (command_id) REFERENCES command (id); +-------------------------------------------------------------------------------- + + +-- Workspace Environments ------------------------------------------------------ +CREATE TABLE environment ( + id BIGINT NOT NULL, + content TEXT, + contenttype VARCHAR(255), + location TEXT, + type VARCHAR(255), + environments_id BIGINT, + environments_key VARCHAR(255), + + PRIMARY KEY (id) +); +--constraints +ALTER TABLE environment ADD CONSTRAINT fk_environment_environments_id FOREIGN KEY (environments_id) REFERENCES workspaceconfig (id); +-------------------------------------------------------------------------------- + + +-- Environment machines -------------------------------------------------------- +CREATE TABLE externalmachine ( + id BIGINT NOT NULL, + machines_id BIGINT, + machines_key VARCHAR(255), + + PRIMARY KEY (id) +); +--constraints +ALTER TABLE externalmachine ADD CONSTRAINT fk_externalmachine_machines_id FOREIGN KEY (machines_id) REFERENCES environment (id); +-------------------------------------------------------------------------------- + + +-- Environment machine agents ------------------------------------------------- +CREATE TABLE externalmachine_agents ( + externalmachine_id BIGINT, + agents VARCHAR(255) +); +-- constraints +ALTER TABLE externalmachine_agents ADD CONSTRAINT fk_externalmachine_agents_externalmachine_id FOREIGN KEY (externalmachine_id) REFERENCES externalmachine (id); +-------------------------------------------------------------------------------- + + +-- Environment machine attributes ---------------------------------------------- +CREATE TABLE externalmachine_attributes ( + externalmachine_id BIGINT, + attributes VARCHAR(255), + attributes_key VARCHAR(255) +); +--constraints +ALTER TABLE externalmachine_attributes ADD CONSTRAINT fk_externalmachine_attributes_externalmachine_id FOREIGN KEY (externalmachine_id) REFERENCES externalmachine (id); +-------------------------------------------------------------------------------- + + +-- Machine servers configuration ----------------------------------------------- +CREATE TABLE serverconf ( + id BIGINT NOT NULL, + port VARCHAR(255), + protocol VARCHAR(255), + servers_id BIGINT, + servers_key VARCHAR(255), + + PRIMARY KEY (id) +); +--constraints +ALTER TABLE serverconf ADD CONSTRAINT fk_serverconf_servers_id FOREIGN KEY (servers_id) REFERENCES externalmachine (id); +-------------------------------------------------------------------------------- + +-- Machine server properties --------------------------------------------------- +CREATE TABLE serverconf_properties ( + serverconf_id BIGINT, + properties VARCHAR(255), + properties_key VARCHAR(255) +); +--constraints +ALTER TABLE serverconf_properties ADD CONSTRAINT fk_serverconf_properties_serverconf_id FOREIGN KEY (serverconf_id) REFERENCES serverconf (id); +-------------------------------------------------------------------------------- + + +-- Workspace snapshots --------------------------------------------------------- +CREATE TABLE snapshot ( + id VARCHAR(255) NOT NULL, + creationdate BIGINT, + description TEXT, + envname VARCHAR(255) NOT NULL, + isdev BOOLEAN, + machinename VARCHAR(255) NOT NULL, + type VARCHAR(255), + workspaceid VARCHAR(255) NOT NULL, + content TEXT, + location VARCHAR(255), + source_type VARCHAR(255), + + PRIMARY KEY (id) +); +--indexes +CREATE UNIQUE INDEX index_snapshot_workspaceid_envname_machinename ON snapshot (workspaceid, envname, machinename); +--constraints +ALTER TABLE snapshot ADD CONSTRAINT fk_snapshot_workspaceid FOREIGN KEY (workspaceid) REFERENCES workspace (id); +-------------------------------------------------------------------------------- + + +-- Recipe ---------------------------------------------------------------------- +CREATE TABLE recipe ( + id VARCHAR(255) NOT NULL, + creator VARCHAR(255), + description TEXT, + name VARCHAR(255), + script TEXT, + type VARCHAR(255), + + PRIMARY KEY (id) +); +-------------------------------------------------------------------------------- + + +-- Recipe tags ----------------------------------------------------------------- +CREATE TABLE recipe_tags ( + recipe_id VARCHAR(255), + tag VARCHAR(255) +); +--indexes +CREATE INDEX index_recipe_tags_tag ON recipe_tags (tag); +--constraints +ALTER TABLE recipe_tags ADD CONSTRAINT fs_recipe_tags_recipe_id FOREIGN KEY (recipe_id) REFERENCES recipe (id); +-------------------------------------------------------------------------------- + + +-- Stack ----------------------------------------------------------------------- +CREATE TABLE stack ( + id VARCHAR(255) NOT NULL, + creator VARCHAR(255), + description TEXT, + name VARCHAR(255) NOT NULL UNIQUE, + scope VARCHAR(255), + origin VARCHAR(255), + type VARCHAR(255), + data BYTEA, + mediatype VARCHAR(255), + icon_name VARCHAR(255), + workspaceconfig_id BIGINT, + + PRIMARY KEY (id) +); +--constraints +ALTER TABLE stack ADD CONSTRAINT fk_stack_workspaceconfig_id FOREIGN KEY (workspaceconfig_id) REFERENCES workspaceconfig (id); +-------------------------------------------------------------------------------- + + +-- Stack components ------------------------------------------------------------ +CREATE TABLE stack_components ( + name VARCHAR(255), + version VARCHAR(255), + stack_id VARCHAR(255) +); +--constraints +ALTER TABLE stack_components ADD CONSTRAINT fk_stack_components_stack_id FOREIGN KEY (stack_id) REFERENCES stack (id); +-------------------------------------------------------------------------------- + + +-- Stack tags ------------------------------------------------------------------ +CREATE TABLE stack_tags ( + stack_id VARCHAR(255), + tag VARCHAR(255) +); +--indexes +CREATE INDEX index_stack_tags_tag ON stack_tags (tag); +--constraints +ALTER TABLE stack_tags ADD CONSTRAINT fk_stack_tags_stack_id FOREIGN KEY (stack_id) REFERENCES stack (id); +-------------------------------------------------------------------------------- + +-- Sequence table -------------------------------------------------------------- +CREATE TABLE SEQUENCE (SEQ_NAME VARCHAR(50) NOT NULL, SEQ_COUNT NUMERIC(38), PRIMARY KEY (SEQ_NAME)); +INSERT INTO SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 0); +-------------------------------------------------------------------------------- diff --git a/wsmaster/integration-tests/cascade-removal/pom.xml b/wsmaster/integration-tests/cascade-removal/pom.xml new file mode 100644 index 00000000000..929e344c091 --- /dev/null +++ b/wsmaster/integration-tests/cascade-removal/pom.xml @@ -0,0 +1,152 @@ + + + + 4.0.0 + + integration-tests-parent + org.eclipse.che.core + 5.0.0-M8-SNAPSHOT + + cascade-removal + Integration Tests :: Cascade Removal + + + com.google.guava + guava + test + + + com.google.inject + guice + test + + + com.google.inject.extensions + guice-persist + test + + + com.h2database + h2 + test + + + javax.annotation + javax.annotation-api + test + + + javax.inject + javax.inject + test + + + org.eclipse.che.core + che-core-api-account + test + + + org.eclipse.che.core + che-core-api-core + test + + + org.eclipse.che.core + che-core-api-machine + test + + + org.eclipse.che.core + che-core-api-ssh + test + + + org.eclipse.che.core + che-core-api-user + test + + + org.eclipse.che.core + che-core-api-workspace + test + + + org.eclipse.che.core + che-core-commons-inject + test + + + org.eclipse.che.core + che-core-commons-test + test + + + org.eclipse.che.core + che-core-db + test + + + org.eclipse.che.core + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema + test + + + org.eclipse.persistence + javax.persistence + test + + + org.mockito + mockito-all + test + + + org.mockito + mockito-core + test + + + org.testng + testng + test + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + + + + diff --git a/assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/jdbc/jpa/JpaEntitiesCascadeRemovalTest.java b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java similarity index 81% rename from assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/jdbc/jpa/JpaEntitiesCascadeRemovalTest.java rename to wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java index e11b009f89e..b47f3f4714f 100644 --- a/assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/jdbc/jpa/JpaEntitiesCascadeRemovalTest.java +++ b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.jdbc.jpa; +package org.eclipse.che.core.db.jpa; import com.google.inject.AbstractModule; import com.google.inject.Guice; @@ -23,15 +23,7 @@ import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEvent; -import org.eclipse.che.api.core.jdbc.jpa.event.CascadeRemovalEventSubscriber; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; import org.eclipse.che.api.core.notification.EventService; -import org.eclipse.che.api.factory.server.jpa.FactoryJpaModule; -import org.eclipse.che.api.factory.server.jpa.JpaFactoryDao.RemoveFactoriesBeforeUserRemovedEventSubscriber; -import org.eclipse.che.api.factory.server.model.impl.FactoryImpl; -import org.eclipse.che.api.factory.server.spi.FactoryDao; import org.eclipse.che.api.machine.server.jpa.MachineJpaModule; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.spi.SnapshotDao; @@ -56,9 +48,12 @@ import org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; -import org.eclipse.che.commons.lang.Pair; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.event.CascadeRemovalEvent; +import org.eclipse.che.core.db.event.CascadeRemovalEventSubscriber; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; import org.eclipse.che.inject.lifecycle.InitModule; -import org.mockito.Mockito; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -70,14 +65,15 @@ import java.util.Map; import java.util.concurrent.Callable; -import static java.util.Collections.singletonList; -import static org.eclipse.che.api.TestObjectsFactory.createFactory; -import static org.eclipse.che.api.TestObjectsFactory.createPreferences; -import static org.eclipse.che.api.TestObjectsFactory.createProfile; -import static org.eclipse.che.api.TestObjectsFactory.createSnapshot; -import static org.eclipse.che.api.TestObjectsFactory.createSshPair; -import static org.eclipse.che.api.TestObjectsFactory.createUser; -import static org.eclipse.che.api.TestObjectsFactory.createWorkspace; +import static org.eclipse.che.commons.test.db.H2TestHelper.inMemoryDefault; +import static org.eclipse.che.core.db.jpa.TestObjectsFactory.createPreferences; +import static org.eclipse.che.core.db.jpa.TestObjectsFactory.createProfile; +import static org.eclipse.che.core.db.jpa.TestObjectsFactory.createSnapshot; +import static org.eclipse.che.core.db.jpa.TestObjectsFactory.createSshPair; +import static org.eclipse.che.core.db.jpa.TestObjectsFactory.createUser; +import static org.eclipse.che.core.db.jpa.TestObjectsFactory.createWorkspace; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; @@ -90,7 +86,7 @@ * * @author Yevhenii Voevodin */ -public class JpaEntitiesCascadeRemovalTest { +public class CascadeRemovalTest { private Injector injector; private EventService eventService; @@ -100,7 +96,6 @@ public class JpaEntitiesCascadeRemovalTest { private WorkspaceDao workspaceDao; private SnapshotDao snapshotDao; private SshDao sshDao; - private FactoryDao factoryDao; /** User is a root of dependency tree. */ private UserImpl user; @@ -119,10 +114,6 @@ public class JpaEntitiesCascadeRemovalTest { private SshPairImpl sshPair1; private SshPairImpl sshPair2; - /** Factories depend on user. */ - private FactoryImpl factory1; - private FactoryImpl factory2; - /** Snapshots depend on workspace. */ private SnapshotImpl snapshot1; private SnapshotImpl snapshot2; @@ -135,20 +126,18 @@ public void setUp() throws Exception { @Override protected void configure() { bind(EventService.class).in(Singleton.class); - - bind(JpaInitializer.class).asEagerSingleton(); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); install(new InitModule(PostConstruct.class)); install(new JpaPersistModule("test")); + bind(SchemaInitializer.class).toInstance(new FlywaySchemaInitializer(inMemoryDefault(), "che-schema")); + bind(DBInitializer.class).asEagerSingleton(); install(new UserJpaModule()); install(new AccountModule()); install(new SshJpaModule()); install(new WorkspaceJpaModule()); install(new MachineJpaModule()); - install(new FactoryJpaModule()); bind(WorkspaceManager.class); - final WorkspaceRuntimes wR = Mockito.mock(WorkspaceRuntimes.class); - when(wR.hasRuntime(Mockito.anyString())).thenReturn(false); + final WorkspaceRuntimes wR = mock(WorkspaceRuntimes.class); + when(wR.hasRuntime(anyString())).thenReturn(false); bind(WorkspaceRuntimes.class).toInstance(wR); bind(AccountManager.class); bind(Boolean.class).annotatedWith(Names.named("che.workspace.auto_snapshot")).toInstance(false); @@ -163,7 +152,6 @@ protected void configure() { sshDao = injector.getInstance(SshDao.class); snapshotDao = injector.getInstance(SnapshotDao.class); workspaceDao = injector.getInstance(WorkspaceDao.class); - factoryDao = injector.getInstance(FactoryDao.class); } @AfterMethod @@ -184,7 +172,6 @@ public void shouldDeleteAllTheEntitiesWhenUserIsDeleted() throws Exception { assertTrue(preferenceDao.getPreferences(user.getId()).isEmpty()); assertTrue(sshDao.get(user.getId()).isEmpty()); assertTrue(workspaceDao.getByNamespace(user.getId()).isEmpty()); - assertTrue(factoryDao.getByAttribute(0, 0, singletonList(Pair.of("creator.userId", user.getId()))).isEmpty()); assertTrue(snapshotDao.findSnapshots(workspace1.getId()).isEmpty()); assertTrue(snapshotDao.findSnapshots(workspace2.getId()).isEmpty()); } @@ -209,7 +196,6 @@ public void shouldRollbackTransactionWhenFailedToRemoveAnyOfEntries( assertFalse(preferenceDao.getPreferences(user.getId()).isEmpty()); assertFalse(sshDao.get(user.getId()).isEmpty()); assertFalse(workspaceDao.getByNamespace(user.getName()).isEmpty()); - assertFalse(factoryDao.getByAttribute(0, 0, singletonList(Pair.of("creator.userId", user.getId()))).isEmpty()); assertFalse(snapshotDao.findSnapshots(workspace1.getId()).isEmpty()); assertFalse(snapshotDao.findSnapshots(workspace2.getId()).isEmpty()); wipeTestData(); @@ -223,8 +209,7 @@ public Object[][] beforeRemoveActions() { {RemoveWorkspaceBeforeAccountRemovedEventSubscriber.class, BeforeAccountRemovedEvent.class}, {RemoveSnapshotsBeforeWorkspaceRemovedEventSubscriber.class, BeforeWorkspaceRemovedEvent.class}, {RemoveSshKeysBeforeUserRemovedEventSubscriber.class, BeforeUserRemovedEvent.class}, - {RemoveFactoriesBeforeUserRemovedEventSubscriber.class, BeforeUserRemovedEvent.class} - }; + }; } private void createTestData() throws ConflictException, ServerException { @@ -240,9 +225,6 @@ private void createTestData() throws ConflictException, ServerException { sshDao.create(sshPair1 = createSshPair(user.getId(), "service", "name1")); sshDao.create(sshPair2 = createSshPair(user.getId(), "service", "name2")); - factoryDao.create(factory1 = createFactory("factory1", user.getId())); - factoryDao.create(factory2 = createFactory("factory2", user.getId())); - snapshotDao.saveSnapshot(snapshot1 = createSnapshot("snapshot1", workspace1.getId())); snapshotDao.saveSnapshot(snapshot2 = createSnapshot("snapshot2", workspace1.getId())); snapshotDao.saveSnapshot(snapshot3 = createSnapshot("snapshot3", workspace2.getId())); @@ -255,9 +237,6 @@ private void wipeTestData() throws ConflictException, ServerException, NotFoundE snapshotDao.removeSnapshot(snapshot3.getId()); snapshotDao.removeSnapshot(snapshot4.getId()); - factoryDao.remove(factory1.getId()); - factoryDao.remove(factory2.getId()); - sshDao.remove(sshPair1.getOwner(), sshPair1.getService(), sshPair1.getName()); sshDao.remove(sshPair2.getOwner(), sshPair2.getService(), sshPair2.getName()); diff --git a/assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/TestObjectsFactory.java b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/TestObjectsFactory.java similarity index 88% rename from assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/TestObjectsFactory.java rename to wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/TestObjectsFactory.java index b743647e274..b5dd6f3f5cb 100644 --- a/assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/TestObjectsFactory.java +++ b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/TestObjectsFactory.java @@ -8,14 +8,11 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api; +package org.eclipse.che.core.db.jpa; import com.google.common.collect.ImmutableMap; import org.eclipse.che.account.shared.model.Account; -import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; -import org.eclipse.che.api.factory.server.model.impl.AuthorImpl; -import org.eclipse.che.api.factory.server.model.impl.FactoryImpl; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl; @@ -77,18 +74,6 @@ public static SshPairImpl createSshPair(String owner, String service, String nam return new SshPairImpl(owner, service, name, "public-key", "private-key"); } - public static FactoryImpl createFactory(String id, String creator) { - return new FactoryImpl(id, - id + "-name", - "4.0", - createWorkspaceConfig(id), - new AuthorImpl(creator, System.currentTimeMillis()), - null, - null, - null, - null); - } - public static SnapshotImpl createSnapshot(String snapshotId, String workspaceId) { return new SnapshotImpl(snapshotId, "type", @@ -131,3 +116,4 @@ public static StackImpl createStack(String id, String name) { private TestObjectsFactory() {} } + diff --git a/wsmaster/che-core-api-factory/src/test/resources/META-INF/persistence.xml b/wsmaster/integration-tests/cascade-removal/src/test/resources/META-INF/persistence.xml similarity index 65% rename from wsmaster/che-core-api-factory/src/test/resources/META-INF/persistence.xml rename to wsmaster/integration-tests/cascade-removal/src/test/resources/META-INF/persistence.xml index 839c2acc49b..e6fb5e584c9 100644 --- a/wsmaster/che-core-api-factory/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/integration-tests/cascade-removal/src/test/resources/META-INF/persistence.xml @@ -13,21 +13,13 @@ - - org.eclipse.che.api.factory.server.model.impl.ActionImpl - org.eclipse.che.api.factory.server.model.impl.AuthorImpl - org.eclipse.che.api.factory.server.model.impl.ButtonAttributesImpl - org.eclipse.che.api.factory.server.model.impl.ButtonImpl - org.eclipse.che.api.factory.server.model.impl.FactoryImpl - org.eclipse.che.api.factory.server.model.impl.IdeImpl - org.eclipse.che.api.factory.server.model.impl.OnAppClosedImpl - org.eclipse.che.api.factory.server.model.impl.OnProjectsLoadedImpl - org.eclipse.che.api.factory.server.model.impl.OnAppLoadedImpl - org.eclipse.che.api.factory.server.model.impl.PoliciesImpl - org.eclipse.che.api.factory.server.FactoryImage + + org.eclipse.persistence.jpa.PersistenceProvider org.eclipse.che.account.spi.AccountImpl org.eclipse.che.api.user.server.model.impl.UserImpl - + org.eclipse.che.api.user.server.model.impl.ProfileImpl + org.eclipse.che.api.user.server.jpa.PreferenceEntity + org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl @@ -37,20 +29,19 @@ org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl org.eclipse.che.api.workspace.server.model.impl.ServerConf2Impl org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl - org.eclipse.che.api.machine.server.model.impl.CommandImpl + org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl + org.eclipse.che.api.machine.server.model.impl.SnapshotImpl org.eclipse.che.api.machine.server.recipe.RecipeImpl + org.eclipse.che.api.ssh.server.model.impl.SshPairImpl true - + - - - - + diff --git a/wsmaster/integration-tests/pom.xml b/wsmaster/integration-tests/pom.xml new file mode 100644 index 00000000000..24aa197970b --- /dev/null +++ b/wsmaster/integration-tests/pom.xml @@ -0,0 +1,29 @@ + + + + 4.0.0 + + che-master-parent + org.eclipse.che.core + 5.0.0-M8-SNAPSHOT + ../pom.xml + + integration-tests-parent + pom + Integration Tests :: Parent + + postgresql-tck + cascade-removal + + diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml new file mode 100644 index 00000000000..0a3718b561f --- /dev/null +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -0,0 +1,295 @@ + + + + 4.0.0 + + integration-tests-parent + org.eclipse.che.core + 5.0.0-M8-SNAPSHOT + + postgresql-tck + jar + Integration Tests :: PostgreSQL + + postgres:9.4 + org.postgresql.Driver + codenvy + jdbc:postgresql://${docker.host.address}:${jdbc.port}/codenvy + codenvy + + + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-api-dto + + + org.eclipse.che.core + che-core-api-user + tests + + + ch.qos.logback + logback-classic + test + + + com.google.inject + guice + test + + + com.google.inject.extensions + guice-persist + test + + + javax.inject + javax.inject + 1 + test + + + org.eclipse.che.core + che-core-api-account + tests + test + + + org.eclipse.che.core + che-core-api-account + test + + + org.eclipse.che.core + che-core-api-machine + tests + test + + + org.eclipse.che.core + che-core-api-ssh + test + + + org.eclipse.che.core + che-core-api-ssh + tests + test + + + org.eclipse.che.core + che-core-api-user + test + + + org.eclipse.che.core + che-core-api-workspace + test + + + org.eclipse.che.core + che-core-api-workspace + tests + test + + + org.eclipse.che.core + che-core-commons-test + test + + + org.eclipse.che.core + che-core-db + test + + + org.eclipse.che.core + che-core-db-vendor-postgresql + test + + + org.eclipse.che.core + che-core-sql-schema + test + + + org.eclipse.persistence + eclipselink + test + + + org.eclipse.persistence + javax.persistence + test + + + org.flywaydb + flyway-core + test + + + org.postgresql + postgresql + test + + + org.testng + testng + test + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/** + + + + + + + + integration + + false + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + unpack-dependencies + + + ${project.build.testOutputDirectory} + che-core-api-account, + che-core-api-user, + che-core-api-ssh, + che-core-api-machine, + che-core-api-workspace + test + tests + + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + ${jdbc.driver} + ${jdbc.url} + ${jdbc.user} + ${jdbc.password} + + + **/tck/** + + + + + io.fabric8 + docker-maven-plugin + 0.15.16 + + + start + pre-integration-test + + stop + start + + + + stop + post-integration-test + + stop + + + + + + + database + ${db.image.name} + + + jdbc.port:5432 + + + database system is ready to accept connections + + + + always + + + ${jdbc.password} + ${jdbc.user} + + + + + + + + + + + diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java new file mode 100644 index 00000000000..fdc3d40b144 --- /dev/null +++ b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ + +import com.google.inject.TypeLiteral; +import com.google.inject.persist.Transactional; +import com.google.inject.persist.jpa.JpaPersistModule; + +import org.eclipse.che.account.spi.AccountDao; +import org.eclipse.che.account.spi.AccountImpl; +import org.eclipse.che.account.spi.jpa.JpaAccountDao; +import org.eclipse.che.api.core.model.workspace.Workspace; +import org.eclipse.che.api.machine.server.jpa.JpaRecipeDao; +import org.eclipse.che.api.machine.server.jpa.JpaSnapshotDao; +import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; +import org.eclipse.che.api.machine.server.recipe.RecipeImpl; +import org.eclipse.che.api.machine.server.spi.RecipeDao; +import org.eclipse.che.api.machine.server.spi.SnapshotDao; +import org.eclipse.che.api.ssh.server.jpa.JpaSshDao; +import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl; +import org.eclipse.che.api.ssh.server.spi.SshDao; +import org.eclipse.che.api.user.server.jpa.JpaPreferenceDao; +import org.eclipse.che.api.user.server.jpa.JpaProfileDao; +import org.eclipse.che.api.user.server.jpa.JpaUserDao; +import org.eclipse.che.api.user.server.jpa.PreferenceEntity; +import org.eclipse.che.api.user.server.model.impl.ProfileImpl; +import org.eclipse.che.api.user.server.model.impl.UserImpl; +import org.eclipse.che.api.user.server.spi.PreferenceDao; +import org.eclipse.che.api.user.server.spi.ProfileDao; +import org.eclipse.che.api.user.server.spi.UserDao; +import org.eclipse.che.api.workspace.server.jpa.JpaStackDao; +import org.eclipse.che.api.workspace.server.jpa.JpaWorkspaceDao; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; +import org.eclipse.che.api.workspace.server.spi.StackDao; +import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; +import org.eclipse.che.commons.lang.Pair; +import org.eclipse.che.commons.test.tck.JpaCleaner; +import org.eclipse.che.commons.test.tck.TckModule; +import org.eclipse.che.commons.test.tck.TckResourcesCleaner; +import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; +import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; +import org.eclipse.che.security.PasswordEncryptor; +import org.eclipse.che.security.SHA512PasswordEncryptor; +import org.postgresql.ds.PGSimpleDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.persistence.EntityManager; +import javax.persistence.spi.PersistenceUnitTransactionType; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static org.eclipse.persistence.config.PersistenceUnitProperties.JDBC_DRIVER; +import static org.eclipse.persistence.config.PersistenceUnitProperties.JDBC_PASSWORD; +import static org.eclipse.persistence.config.PersistenceUnitProperties.JDBC_URL; +import static org.eclipse.persistence.config.PersistenceUnitProperties.JDBC_USER; +import static org.eclipse.persistence.config.PersistenceUnitProperties.TRANSACTION_TYPE; + +/** + * Module for running TCKs based on PostgreSQL. + * + * @author Yevhenii Voevodin + */ +public class PostgreSqlTckModule extends TckModule { + + private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlTckModule.class); + + @Override + protected void configure() { + final String dbUrl = System.getProperty("jdbc.url"); + final String dbUser = System.getProperty("jdbc.user"); + final String dbPassword = System.getProperty("jdbc.password"); + + waitConnectionIsEstablished(dbUrl, dbUser, dbPassword); + + // jpa + final Map properties = new HashMap<>(); + properties.put(TRANSACTION_TYPE, PersistenceUnitTransactionType.RESOURCE_LOCAL.name()); + properties.put(JDBC_URL, dbUrl); + properties.put(JDBC_USER, dbUser); + properties.put(JDBC_PASSWORD, dbPassword); + properties.put(JDBC_DRIVER, System.getProperty("jdbc.driver")); + final JpaPersistModule persistenceModule = new JpaPersistModule("test"); + persistenceModule.properties(properties); + install(persistenceModule); + bind(TckResourcesCleaner.class).to(JpaCleaner.class); + + // db initialization + bind(DBInitializer.class).asEagerSingleton(); + final PGSimpleDataSource dataSource = new PGSimpleDataSource(); + dataSource.setUser(dbUser); + dataSource.setPassword(dbPassword); + dataSource.setUrl(dbUrl); + bind(SchemaInitializer.class).toInstance(new FlywaySchemaInitializer(dataSource, "che-schema")); + + // account + bind(AccountDao.class).to(JpaAccountDao.class); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(AccountImpl.class)); + + // user + bind(UserDao.class).to(JpaUserDao.class); + bind(ProfileDao.class).to(JpaProfileDao.class); + bind(PreferenceDao.class).to(JpaPreferenceDao.class); + bind(new TypeLiteral>() {}).to(UserRepo.class); + bind(new TypeLiteral>>>() {}).to(PreferencesRepo.class); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(ProfileImpl.class)); + bind(PasswordEncryptor.class).to(SHA512PasswordEncryptor.class); + + // machine + bind(RecipeDao.class).to(JpaRecipeDao.class); + bind(SnapshotDao.class).to(JpaSnapshotDao.class); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(RecipeImpl.class)); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(SnapshotImpl.class)); + bind(new TypeLiteral>() {}).toInstance(new WorkspaceRepoForSnapshots()); + + // ssh + bind(SshDao.class).to(JpaSshDao.class); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(SshPairImpl.class)); + + // workspace + bind(WorkspaceDao.class).to(JpaWorkspaceDao.class); + bind(StackDao.class).to(JpaStackDao.class); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(WorkspaceImpl.class)); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(StackImpl.class)); + } + + private static void waitConnectionIsEstablished(String dbUrl, String dbUser, String dbPassword) { + boolean isAvailable = false; + for (int i = 0; i < 60 && !isAvailable; i++) { + try (Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword)) { + isAvailable = true; + } catch (SQLException x) { + LOG.warn("An attempt to connect to the database failed with an error: {}", x.getLocalizedMessage()); + try { + TimeUnit.MILLISECONDS.sleep(500); + } catch (InterruptedException interruptedX) { + throw new RuntimeException(interruptedX.getLocalizedMessage(), interruptedX); + } + } + } + if (!isAvailable) { + throw new IllegalStateException("Couldn't initialize connection with a database"); + } + } + + @Transactional + static class PreferencesRepo implements TckRepository>> { + + @Inject + private Provider managerProvider; + + @Override + public void createAll(Collection>> entities) + throws TckRepositoryException { + final EntityManager manager = managerProvider.get(); + for (Pair> pair : entities) { + manager.persist(new PreferenceEntity(pair.first, pair.second)); + } + } + + @Override + public void removeAll() throws TckRepositoryException { + final EntityManager manager = managerProvider.get(); + manager.createQuery("SELECT preferences FROM Preference preferences", PreferenceEntity.class) + .getResultList() + .forEach(manager::remove); + } + } + + @Transactional + static class UserRepo implements TckRepository { + + @Inject + private Provider managerProvider; + + @Inject + private PasswordEncryptor encryptor; + + @Override + public void createAll(Collection entities) throws TckRepositoryException { + final EntityManager manager = managerProvider.get(); + entities.stream() + .map(user -> new UserImpl(user.getId(), + user.getEmail(), + user.getName(), + encryptor.encrypt(user.getPassword()), + user.getAliases())) + .forEach(manager::persist); + } + + @Override + public void removeAll() throws TckRepositoryException { + managerProvider.get() + .createQuery("SELECT u FROM Usr u", UserImpl.class) + .getResultList() + .forEach(managerProvider.get()::remove); + } + } + + static class WorkspaceRepoForSnapshots extends JpaTckRepository { + public WorkspaceRepoForSnapshots() { super(WorkspaceImpl.class); } + + @Override + public void createAll(Collection entities) throws TckRepositoryException { + super.createAll(entities.stream() + .map(w -> new WorkspaceImpl(w, new AccountImpl(w.getNamespace(), + w.getNamespace(), + "simple"))) + .collect(Collectors.toList())); + } + } +} diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/persistence.xml b/wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/persistence.xml new file mode 100644 index 00000000000..a0f9649fc11 --- /dev/null +++ b/wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,45 @@ + + + + org.eclipse.persistence.jpa.PersistenceProvider + org.eclipse.che.account.spi.AccountImpl + org.eclipse.che.api.user.server.model.impl.UserImpl + org.eclipse.che.api.user.server.model.impl.ProfileImpl + org.eclipse.che.api.user.server.jpa.PreferenceEntity + org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl + org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl + org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl + org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl + org.eclipse.che.api.workspace.server.model.impl.EnvironmentRecipeImpl + org.eclipse.che.api.workspace.server.model.impl.ExtendedMachineImpl + org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute + org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl + org.eclipse.che.api.workspace.server.model.impl.ServerConf2Impl + org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl + org.eclipse.che.api.machine.server.model.impl.CommandImpl + org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl + org.eclipse.che.api.machine.server.model.impl.SnapshotImpl + org.eclipse.che.api.machine.server.recipe.RecipeImpl + org.eclipse.che.api.ssh.server.model.impl.SshPairImpl + true + + + + + + + diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule b/wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule new file mode 100644 index 00000000000..4c1b689a0ef --- /dev/null +++ b/wsmaster/integration-tests/postgresql-tck/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule @@ -0,0 +1 @@ +PostgreSqlTckModule diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/resources/logback-test.xml b/wsmaster/integration-tests/postgresql-tck/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..0d5e22c3c62 --- /dev/null +++ b/wsmaster/integration-tests/postgresql-tck/src/test/resources/logback-test.xml @@ -0,0 +1,25 @@ + + + + + + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + + + diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index c6713872048..01cb27bc711 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -41,5 +41,7 @@ che-core-api-agent che-core-api-agent-shared wsmaster-local + che-core-sql-schema + integration-tests diff --git a/wsmaster/wsmaster-local/pom.xml b/wsmaster/wsmaster-local/pom.xml index 629e0c5d55b..d9e4c4e2b96 100644 --- a/wsmaster/wsmaster-local/pom.xml +++ b/wsmaster/wsmaster-local/pom.xml @@ -107,6 +107,16 @@ logback-classic test + + com.google.inject.extensions + guice-persist + test + + + com.h2database + h2 + test + org.eclipse.che.core che-core-api-machine @@ -136,6 +146,31 @@ che-core-commons-test test + + org.eclipse.che.core + che-core-db + test + + + org.eclipse.che.core + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema + test + + + org.eclipse.persistence + eclipselink + test + + + org.eclipse.persistence + javax.persistence + test + org.everrest everrest-assured @@ -162,4 +197,26 @@ test + + + + org.apache.maven.plugins + maven-dependency-plugin + + + resource-dependencies + process-test-resources + + unpack-dependencies + + + che-core-sql-schema + che-schema/ + ${project.build.directory} + + + + + + diff --git a/assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/local/LocalToJpaDataMigratorTest.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalToJpaDataMigratorTest.java similarity index 64% rename from assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/local/LocalToJpaDataMigratorTest.java rename to wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalToJpaDataMigratorTest.java index fe848328af9..9dc9b012056 100644 --- a/assembly/assembly-wsmaster-war/src/test/java/org/eclipse/che/api/local/LocalToJpaDataMigratorTest.java +++ b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalToJpaDataMigratorTest.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.local; +import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -23,8 +24,7 @@ import com.google.inject.name.Names; import com.google.inject.persist.jpa.JpaPersistModule; -import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer; -import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer; +import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.api.local.storage.LocalStorageFactory; import org.eclipse.che.api.local.storage.stack.StackLocalStorage; import org.eclipse.che.api.machine.server.jpa.MachineJpaModule; @@ -44,12 +44,19 @@ import org.eclipse.che.api.workspace.server.WorkspaceConfigJsonAdapter; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.api.workspace.server.model.impl.stack.StackComponentImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; +import org.eclipse.che.api.workspace.server.model.impl.stack.StackSourceImpl; import org.eclipse.che.api.workspace.server.spi.StackDao; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.eclipse.che.api.workspace.server.stack.StackJsonAdapter; +import org.eclipse.che.api.workspace.server.stack.image.StackIcon; import org.eclipse.che.commons.lang.IoUtil; +import org.eclipse.che.core.db.DBInitializer; +import org.eclipse.che.core.db.schema.SchemaInitializer; +import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; import org.mockito.Mockito; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -61,18 +68,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; import java.util.Map; +import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; -import static org.eclipse.che.api.TestObjectsFactory.createPreferences; -import static org.eclipse.che.api.TestObjectsFactory.createProfile; -import static org.eclipse.che.api.TestObjectsFactory.createRecipe; -import static org.eclipse.che.api.TestObjectsFactory.createSnapshot; -import static org.eclipse.che.api.TestObjectsFactory.createSshPair; -import static org.eclipse.che.api.TestObjectsFactory.createStack; -import static org.eclipse.che.api.TestObjectsFactory.createUser; -import static org.eclipse.che.api.TestObjectsFactory.createWorkspace; +import static org.eclipse.che.commons.test.db.H2TestHelper.inMemoryDefault; /** * Tests migration from local json based storage to jpa. @@ -81,19 +83,17 @@ */ public class LocalToJpaDataMigratorTest { - private Injector injector; - private LocalDataMigrator migrator; - private Path workingDir; - - private UserDao userDao; - private ProfileDao profileDao; - private PreferenceDao preferenceDao; - private WorkspaceDao workspaceDao; - private SnapshotDao snapshotDao; - private SshDao sshDao; - private RecipeDao recipeDao; - private StackDao stackDao; - + private Injector injector; + private LocalDataMigrator migrator; + private Path workingDir; + private UserDao userDao; + private ProfileDao profileDao; + private PreferenceDao preferenceDao; + private WorkspaceDao workspaceDao; + private SnapshotDao snapshotDao; + private SshDao sshDao; + private RecipeDao recipeDao; + private StackDao stackDao; private LocalStorageFactory factory; private StackJsonAdapter stackJsonAdapter; private WorkspaceConfigJsonAdapter workspaceCfgJsonAdapter; @@ -106,9 +106,9 @@ private void setUp() throws Exception { @Override protected void configure() { bindConstant().annotatedWith(Names.named("che.database")).to(workingDir.toString()); - - bind(JpaInitializer.class).asEagerSingleton(); - bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton(); + FlywaySchemaInitializer initializer = new FlywaySchemaInitializer(inMemoryDefault(), "che-schema"); + bind(SchemaInitializer.class).toInstance(initializer); + bind(DBInitializer.class).asEagerSingleton(); install(new JpaPersistModule("test")); install(new UserJpaModule()); install(new SshJpaModule()); @@ -118,7 +118,6 @@ protected void configure() { bind(WorkspaceManager.class).toInstance(Mockito.mock(WorkspaceManager.class)); } }); - userDao = injector.getInstance(UserDao.class); preferenceDao = injector.getInstance(PreferenceDao.class); profileDao = injector.getInstance(ProfileDao.class); @@ -127,10 +126,8 @@ protected void configure() { workspaceDao = injector.getInstance(WorkspaceDao.class); recipeDao = injector.getInstance(RecipeDao.class); stackDao = injector.getInstance(StackDao.class); - stackJsonAdapter = injector.getInstance(StackJsonAdapter.class); workspaceCfgJsonAdapter = injector.getInstance(WorkspaceConfigJsonAdapter.class); - migrator = new LocalDataMigrator(); storeTestData(); } @@ -189,7 +186,6 @@ private void storeTestData() throws Exception { final SnapshotImpl snapshot = createSnapshot("snapshot123", workspace.getId()); final RecipeImpl recipe = createRecipe("recipe123"); final StackImpl stack = createStack("stack123", "stack-name"); - factory.create(LocalUserDaoImpl.FILENAME).store(singletonMap(user.getId(), user)); factory.create(LocalProfileDaoImpl.FILENAME).store(singletonMap(profile.getUserId(), profile)); factory.create(LocalPreferenceDaoImpl.FILENAME).store(singletonMap(user.getId(), preferences)); @@ -213,9 +209,8 @@ public JsonElement serialize(WorkspaceImpl src, Type typeOfSrc, JsonSerializatio } public static class SshSerializer implements JsonSerializer { - @Override - public JsonElement serialize(SshPairImpl sshPair, Type type, JsonSerializationContext jsonSerializationContext) { + public JsonElement serialize(SshPairImpl sshPair, Type type, JsonSerializationContext context) { JsonObject result = new JsonObject(); result.add("service", new JsonPrimitive(sshPair.getService())); result.add("name", new JsonPrimitive(sshPair.getName())); @@ -224,4 +219,82 @@ public JsonElement serialize(SshPairImpl sshPair, Type type, JsonSerializationCo return result; } } + + public static UserImpl createUser(String id) { + return new UserImpl(id, + id + "@eclipse.org", + id + "_name", + "password", + asList(id + "_alias1", id + "_alias2")); + } + + public static ProfileImpl createProfile(String userId) { + return new ProfileImpl(userId, new HashMap<>(ImmutableMap.of("attribute1", "value1", + "attribute2", "value2", + "attribute3", "value3"))); + } + + public static Map createPreferences() { + return new HashMap<>(ImmutableMap.of("preference1", "value1", + "preference2", "value2", + "preference3", "value3")); + } + + public static WorkspaceConfigImpl createWorkspaceConfig(String id) { + return new WorkspaceConfigImpl(id + "_name", + id + "description", + "default-env", + null, + null, + null); + } + + public static WorkspaceImpl createWorkspace(String id, Account account) { + return new WorkspaceImpl(id, account, createWorkspaceConfig(id)); + } + + public static SshPairImpl createSshPair(String owner, String service, String name) { + return new SshPairImpl(owner, service, name, "public-key", "private-key"); + } + + public static SnapshotImpl createSnapshot(String snapshotId, String workspaceId) { + return new SnapshotImpl(snapshotId, + "type", + null, + System.currentTimeMillis(), + workspaceId, + snapshotId + "_description", + true, + "dev-machine", + snapshotId + "env-name"); + } + + public static RecipeImpl createRecipe(String id) { + return new RecipeImpl(id, + "recipe-name-" + id, + "recipe-creator", + "recipe-type", + "recipe-script", + asList("recipe-tag1", "recipe-tag2"), + "recipe-description"); + } + + public static StackImpl createStack(String id, String name) { + return StackImpl.builder() + .setId(id) + .setName(name) + .setCreator("user123") + .setDescription(id + "-description") + .setScope(id + "-scope") + .setWorkspaceConfig(createWorkspaceConfig("test")) + .setTags(asList(id + "-tag1", id + "-tag2")) + .setComponents(asList(new StackComponentImpl(id + "-component1", id + "-component1-version"), + new StackComponentImpl(id + "-component2", id + "-component2-version"))) + .setSource(new StackSourceImpl(id + "-type", id + "-origin")) + .setStackIcon(new StackIcon(id + "-icon", + id + "-media-type", + "0x1234567890abcdef".getBytes())) + .build(); + } + } diff --git a/assembly/assembly-wsmaster-war/src/test/resources/META-INF/persistence.xml b/wsmaster/wsmaster-local/src/test/resources/META-INF/persistence.xml similarity index 72% rename from assembly/assembly-wsmaster-war/src/test/resources/META-INF/persistence.xml rename to wsmaster/wsmaster-local/src/test/resources/META-INF/persistence.xml index f4c4d6bcab7..d8d660d6e7d 100644 --- a/assembly/assembly-wsmaster-war/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/wsmaster-local/src/test/resources/META-INF/persistence.xml @@ -15,9 +15,9 @@ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> org.eclipse.persistence.jpa.PersistenceProvider + org.eclipse.che.account.spi.AccountImpl org.eclipse.che.api.user.server.model.impl.UserImpl org.eclipse.che.api.user.server.model.impl.ProfileImpl - org.eclipse.che.account.spi.AccountImpl org.eclipse.che.api.user.server.jpa.PreferenceEntity org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl @@ -34,28 +34,15 @@ org.eclipse.che.api.machine.server.model.impl.SnapshotImpl org.eclipse.che.api.machine.server.recipe.RecipeImpl org.eclipse.che.api.ssh.server.model.impl.SshPairImpl - org.eclipse.che.api.factory.server.model.impl.ActionImpl - org.eclipse.che.api.factory.server.model.impl.AuthorImpl - org.eclipse.che.api.factory.server.model.impl.ButtonAttributesImpl - org.eclipse.che.api.factory.server.model.impl.ButtonImpl - org.eclipse.che.api.factory.server.model.impl.FactoryImpl - org.eclipse.che.api.factory.server.model.impl.IdeImpl - org.eclipse.che.api.factory.server.model.impl.OnAppClosedImpl - org.eclipse.che.api.factory.server.model.impl.OnProjectsLoadedImpl - org.eclipse.che.api.factory.server.model.impl.OnAppLoadedImpl - org.eclipse.che.api.factory.server.model.impl.PoliciesImpl - org.eclipse.che.api.factory.server.FactoryImage true - + - + - - From 53a28f96dab20d19b25a287c9bb77c2d27ae6200 Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Wed, 23 Nov 2016 13:20:02 +0200 Subject: [PATCH 12/74] Change C# icon in project wizard (#3153) Signed-off-by: Vitalii Parfonov --- .../org/eclipse/che/plugin/csharp/ide/svg/category.svg | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/resources/org/eclipse/che/plugin/csharp/ide/svg/category.svg b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/resources/org/eclipse/che/plugin/csharp/ide/svg/category.svg index d1ac7e02028..730a8d708cb 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/resources/org/eclipse/che/plugin/csharp/ide/svg/category.svg +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/resources/org/eclipse/che/plugin/csharp/ide/svg/category.svg @@ -1,4 +1,4 @@ - + - + - - - + \ No newline at end of file From b071dcc2ee197edfe35141bba79cd3511eb7dd59 Mon Sep 17 00:00:00 2001 From: Mario Loriedo Date: Wed, 23 Nov 2016 16:42:36 +0100 Subject: [PATCH 13/74] Fix HOSTNAME variable in docker.sh Signed-off-by: Mario Loriedo --- assembly/assembly-main/src/assembly/bin/docker.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/assembly/assembly-main/src/assembly/bin/docker.sh b/assembly/assembly-main/src/assembly/bin/docker.sh index 6d7c5e12283..0b6f06fc5c5 100644 --- a/assembly/assembly-main/src/assembly/bin/docker.sh +++ b/assembly/assembly-main/src/assembly/bin/docker.sh @@ -110,7 +110,7 @@ init() { if [ "$CHE_IN_VM" = "true" ]; then # CHE_DOCKER_MACHINE_HOST_EXTERNAL must be set if you are in a VM. - HOSTNAME=$(get_docker_external_hostname) + HOSTNAME=${CHE_DOCKER_MACHINE_HOST_EXTERNAL:-$(get_docker_external_hostname)} if has_external_hostname; then # Internal property used by Che to set hostname. # See: LocalDockerInstanceRuntimeInfo.java#L9 @@ -147,11 +147,16 @@ init() { } get_che_data_from_host() { + DEFAULT_DATA_HOST_PATH=/home/user/che CHE_SERVER_CONTAINER_ID=$(get_che_server_container_id) - echo $(docker inspect --format='{{(index .Volumes "/data")}}' $CHE_SERVER_CONTAINER_ID) + # If `docker inspect` fails $DEFAULT_DATA_HOST_PATH is returned + echo $(docker inspect --format='{{(index .Volumes "/data")}}' $CHE_SERVER_CONTAINER_ID 2>/dev/null || echo $DEFAULT_DATA_HOST_PATH) } get_che_server_container_id() { + # Returning `hostname` doesn't work when running Che on OpenShift/Kubernetes. + # In these cases `hostname` correspond to the pod ID that is different from + # the container ID hostname } From 36d6e6d50d859ce7ad21cff2d31fc0c100702e6c Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Tue, 22 Nov 2016 12:59:24 +0200 Subject: [PATCH 14/74] CUSTOMER-SAAS-68: add UI for managing credit card. make che-select to show validation messages. Signed-off-by: Oleksii Kurinnyi --- .../widget/select/che-select.directive.ts | 60 ++++++++++++++++--- .../components/widget/select/che-select.html | 30 ---------- .../components/widget/select/che-select.styl | 10 ++-- 3 files changed, 57 insertions(+), 43 deletions(-) delete mode 100644 dashboard/src/components/widget/select/che-select.html diff --git a/dashboard/src/components/widget/select/che-select.directive.ts b/dashboard/src/components/widget/select/che-select.directive.ts index 1bafa4b7e78..fd444a69722 100644 --- a/dashboard/src/components/widget/select/che-select.directive.ts +++ b/dashboard/src/components/widget/select/che-select.directive.ts @@ -16,34 +16,76 @@ * @author Oleksii Orel */ export class CheSelect { + restrict: string = 'E'; + replace: boolean = true; + transclude: boolean = true; + + scope: { + [propName: string]: string + }; /** * Default constructor that is using resource * @ngInject for Dependency injection */ constructor() { - this.restrict = 'E'; - - this.replace = true; - this.transclude = true; - this.templateUrl = 'components/widget/select/che-select.html'; - // scope values this.scope = { value: '=cheValue', labelName: '@?cheLabelName', placeHolder: '@chePlaceHolder', - optionValues: '=cheOptionValues' + optionValues: '=cheOptionValues', + myName: '=cheName', + myForm: '=cheForm' }; } - compile(element, attrs) { + template(element: ng.IAugmentedJQuery, attrs: any): string { + return `
+ + + + + {{optionValue.name}} + + + +
+
+ + +
+
+ + +
+ + {{optionValue.name}} + + + +
+
+
+
+
`; + } + + compile(element: ng.IAugmentedJQuery, attrs: any): void { let keys = Object.keys(attrs); // search the select field let selectElements = element.find('md-select'); - keys.forEach((key) => { + keys.forEach((key: string) => { // don't reapply internal properties if (key.indexOf('$') === 0) { return; diff --git a/dashboard/src/components/widget/select/che-select.html b/dashboard/src/components/widget/select/che-select.html deleted file mode 100644 index 4d96523c1bb..00000000000 --- a/dashboard/src/components/widget/select/che-select.html +++ /dev/null @@ -1,30 +0,0 @@ -
- - - - - {{ optionValue.name }} - - - - - -
-
- - -
- - {{ optionValue.name }} - - -
-
-
-
diff --git a/dashboard/src/components/widget/select/che-select.styl b/dashboard/src/components/widget/select/che-select.styl index 5360730644a..81e94e32f12 100644 --- a/dashboard/src/components/widget/select/che-select.styl +++ b/dashboard/src/components/widget/select/che-select.styl @@ -1,21 +1,20 @@ .che-select .che-select-container - border-bottom 1px solid $default-border-color outline none .che-select .che-select-mobile, .che-select .che-select-desktop width 100% -.che-select .che-select-desktop - height 21px - .che-select .che-select-desktop .che-select-container position relative min-height 21px min-width 200px .che-select .che-select-desktop md-select + min-height 22px + height 22px margin 0 + border-bottom 1px solid $default-border-color .che-select .che-select-desktop md-select > * border none !important @@ -47,3 +46,6 @@ .che-custom-dropdown .md-text font-size inherit !important + +.che-select [ng-message] + color $error-color From 53fa5ae6b847ee8317bbc915fe8f2b213123d476 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskii Date: Thu, 24 Nov 2016 13:03:01 +0200 Subject: [PATCH 15/74] Add ability to auto select first node when tree becomes visible and it has at least one node --- .../main/java/org/eclipse/che/ide/ui/smartTree/Tree.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/smartTree/Tree.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/smartTree/Tree.java index 23dcffaf90c..540f7d82a2b 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/smartTree/Tree.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/smartTree/Tree.java @@ -1031,8 +1031,9 @@ protected void update() { @Override public void onExecute() { int count = getVisibleRowCount(); + List rootItems = getRootNodes(); + if (count > 0) { - List rootItems = getRootNodes(); List visible = getAllChildNodes(rootItems, true); int[] vr = getVisibleRows(visible, count); @@ -1054,6 +1055,10 @@ public void onExecute() { } } } + + if (selectionModel.getSelectedNodes().isEmpty() && autoSelect && !rootItems.isEmpty()) { + selectionModel.select(rootItems.get(0), false); + } } }; } From 7b3b42351356a409bc2d841c18d321446a4d7db2 Mon Sep 17 00:00:00 2001 From: Evgen Vidolob Date: Fri, 25 Nov 2016 12:19:04 +0200 Subject: [PATCH 16/74] #3021 store and restore project explorer state (#3164) Signed-off-by: Evgen Vidolob --- .../ProjectExplorerStateComponent.java | 156 ++++++++++++++++++ .../PersistenceApiModule.java | 2 + 2 files changed, 158 insertions(+) create mode 100644 ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java new file mode 100644 index 00000000000..47dd129d0b9 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.part.explorer.project; + +import elemental.json.Json; +import elemental.json.JsonArray; +import elemental.json.JsonObject; +import org.eclipse.che.api.promises.client.*; +import org.eclipse.che.ide.api.component.StateComponent; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.resource.Path; +import org.eclipse.che.ide.resources.tree.ResourceNode; +import org.eclipse.che.ide.ui.loaders.request.LoaderFactory; +import org.eclipse.che.ide.ui.loaders.request.MessageLoader; +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; + +/** + * Persists and restore state of the project explorer presenter, like expanded nodes and showing hidden files + */ +@Singleton +public class ProjectExplorerStateComponent implements StateComponent { + private static final String PATH_PARAM_ID = "revealPath"; + private static final String SHOW_HIDDEN_FILES = "showHiddenFiles"; + + private final ProjectExplorerPresenter projectExplorer; + private final TreeResourceRevealer revealer; + private final LoaderFactory loaderFactory; + + @Inject + public ProjectExplorerStateComponent(ProjectExplorerPresenter projectExplorer, TreeResourceRevealer revealer, LoaderFactory loaderFactory) { + this.projectExplorer = projectExplorer; + this.revealer = revealer; + this.loaderFactory = loaderFactory; + } + + @Override + public JsonObject getState() { + final List paths = new ArrayList<>(); + + /* + The main idea is to look up all expanded nodes in project tree and gather the last one's children. + Then check if child is resource, then we store the path in user preference. + */ + + outer: + for (Node node : projectExplorer.getTree().getNodeStorage().getAll()) { + if (projectExplorer.getTree().isExpanded(node) && node instanceof ResourceNode) { + + final List childrenToStore = projectExplorer.getTree().getNodeStorage().getChildren(node); + + for (Node children : childrenToStore) { + if (children instanceof ResourceNode) { + paths.add(((ResourceNode) children).getData().getLocation()); + continue outer; + } + } + } + } + + JsonObject state = Json.createObject(); + JsonArray array = Json.createArray(); + state.put(PATH_PARAM_ID, array); + int i = 0; + for (Path path : paths) { + array.set(i++, path.toString()); + } + + state.put(SHOW_HIDDEN_FILES, projectExplorer.isShowHiddenFiles()); + + return state; + } + + @Override + public void loadState(@NotNull JsonObject state) { + + if (state.hasKey(SHOW_HIDDEN_FILES)) { + projectExplorer.showHiddenFiles(state.getBoolean(SHOW_HIDDEN_FILES)); + } + + JsonArray paths; + + if (state.hasKey(PATH_PARAM_ID)) { + paths = state.getArray(PATH_PARAM_ID); + } else { + paths = Json.createArray(); + } + + Promise revealPromise = null; + + final MessageLoader loader = loaderFactory.newLoader("Restoring project structure..."); + loader.show(); + + for (int i = 0; i < paths.length(); i++) { + final String path = paths.getString(i); + if (revealPromise == null) { + revealPromise = revealer.reveal(Path.valueOf(path), false).thenPromise(new Function>() { + @Override + public Promise apply(Node node) throws FunctionException { + if (node != null) { + projectExplorer.getTree().setExpanded(node, true, false); + } + + return revealer.reveal(Path.valueOf(path), false); + } + }); + continue; + } + + revealPromise.thenPromise(new Function>() { + @Override + public Promise apply(Node node) throws FunctionException { + if (node != null) { + projectExplorer.getTree().setExpanded(node, true, false); + } + + return revealer.reveal(Path.valueOf(path), false); + } + }).catchError(new Function() { + @Override + public Node apply(PromiseError error) throws FunctionException { + Log.info(getClass(), error.getMessage()); + + return null; + } + }); + } + + if (revealPromise != null) { + revealPromise.then(new Operation() { + @Override + public void apply(Node node) throws OperationException { + loader.hide(); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError error) throws OperationException { + loader.hide(); + } + }); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/PersistenceApiModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/PersistenceApiModule.java index 4856329f8a6..44b90183ae2 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/PersistenceApiModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/PersistenceApiModule.java @@ -17,6 +17,7 @@ import org.eclipse.che.ide.api.component.WsAgentComponent; import org.eclipse.che.ide.client.WorkspaceStateRestorer; import org.eclipse.che.ide.editor.EditorAgentImpl; +import org.eclipse.che.ide.part.explorer.project.ProjectExplorerStateComponent; import org.eclipse.che.ide.workspace.WorkspacePresenter; /** @@ -35,5 +36,6 @@ protected void configure() { GinMapBinder stateComponents = GinMapBinder.newMapBinder(binder(), String.class, StateComponent.class); stateComponents.addBinding("workspace").to(WorkspacePresenter.class); stateComponents.addBinding("editor").to(EditorAgentImpl.class); + stateComponents.addBinding("projectExplorer").to(ProjectExplorerStateComponent.class); } } From 44b060bff816aa510b5cb8e1a1e0fa1471af889e Mon Sep 17 00:00:00 2001 From: Dmitry Kuleshov Date: Fri, 25 Nov 2016 14:43:47 +0200 Subject: [PATCH 17/74] che#1947: reorganized json rpc and websocket (#3143) --- .../wsagent/server/CheWebSocketEndpoint.java | 10 +- .../che/wsagent/server/WsAgentModule.java | 42 +--- .../core/jsonrpc/JsonRpcRequestReceiver.java | 46 ----- .../jsonrpc/JsonRpcRequestTransmitter.java | 39 ---- .../core/jsonrpc/JsonRpcResponseReceiver.java | 47 ----- .../jsonrpc/JsonRpcResponseTransmitter.java | 40 ---- .../che/api/core/jsonrpc/RequestHandler.java | 122 ++++++++++++ .../api/core/jsonrpc/RequestTransmitter.java | 86 ++++++++ .../impl/BasicJsonRpcObjectValidator.java | 106 ---------- .../core/jsonrpc/impl/JsonRpcDispatcher.java | 38 ---- .../jsonrpc/impl/JsonRpcObjectValidator.java | 24 --- .../jsonrpc/impl/JsonRpcRequestRegistry.java | 67 ------- .../jsonrpc/impl/NotificationDispatcher.java | 81 ++++++++ .../core/jsonrpc/impl/RequestDispatcher.java | 115 +++++++++++ .../core/jsonrpc/impl/ResponseDispatcher.java | 95 +++++++++ .../impl/WebSocketJsonRpcDispatcher.java | 66 ------- .../WebSocketJsonRpcRequestDispatcher.java | 59 ------ .../WebSocketJsonRpcRequestTransmitter.java | 66 ------- .../WebSocketJsonRpcResponseDispatcher.java | 60 ------ .../WebSocketJsonRpcResponseTransmitter.java | 57 ------ .../impl/WebSocketJsonRpcTransmitter.java | 61 ------ .../impl/WebSocketToJsonRpcDispatcher.java | 86 ++++++++ .../jsonrpc/impl/WebSocketTransmitter.java | 108 ++++++++++ .../api/core/jsonrpc/shared/JsonRpcError.java | 48 ----- .../core/jsonrpc/shared/JsonRpcObject.java | 32 --- .../core/jsonrpc/shared/JsonRpcRequest.java | 56 ------ .../core/jsonrpc/shared/JsonRpcResponse.java | 61 ------ .../websocket/WebSocketMessageReceiver.java | 25 +-- .../WebSocketMessageTransmitter.java | 33 ++-- .../impl/BasicWebSocketEndpoint.java | 26 +-- .../BasicWebSocketMessageTransmitter.java | 32 +-- .../BasicWebSocketTransmissionValidator.java | 109 ----------- ...gesReSender.java => MessagesReSender.java} | 22 +-- .../impl/WebSocketSessionRegistry.java | 8 +- .../impl/WebSocketTransmissionDispatcher.java | 65 ------- .../impl/WebSocketTransmissionValidator.java | 24 --- .../shared/WebSocketTransmission.java | 29 --- .../impl/BasicJsonRpcObjectValidatorTest.java | 100 ---------- .../impl/JsonRpcRequestRegistryTest.java | 53 ----- .../impl/WebSocketJsonRpcDispatcherTest.java | 88 --------- ...WebSocketJsonRpcRequestDispatcherTest.java | 81 -------- ...ebSocketJsonRpcRequestTransmitterTest.java | 72 ------- ...ebSocketJsonRpcResponseDispatcherTest.java | 81 -------- ...bSocketJsonRpcResponseTransmitterTest.java | 62 ------ .../impl/WebSocketJsonRpcTransmitterTest.java | 78 -------- .../impl/BasicWebSocketEndpointTest.java | 58 +++--- ...BasicWebSocketMessageTransmitterTest.java} | 52 ++--- ...sicWebSocketTransmissionValidatorTest.java | 104 ---------- ...derTest.java => MessagesReSenderTest.java} | 100 +++++----- .../impl/WebSocketSessionRegistryTest.java | 20 +- .../WebSocketTransmissionDispatcherTest.java | 82 -------- .../event/ng/ClientServerEventService.java | 33 ++-- ... EditorFileStatusNotificationHandler.java} | 28 ++- .../JsonRpcWebSocketAgentEventListener.java | 13 +- ...ProjectTreeStatusNotificationHandler.java} | 22 +-- ...torFileStatusNotificationReceiverTest.java | 143 -------------- .../che/ide/core/ClientServerEventModule.java | 16 +- .../eclipse/che/ide/core/CoreGinModule.java | 8 +- .../eclipse/che/ide/core/JsonRpcModule.java | 33 +--- .../eclipse/che/ide/core/WebSocketModule.java | 29 +-- .../notification/NotificationManagerImpl.java | 6 +- ide/commons-gwt/pom.xml | 4 - .../che/ide/jsonrpc/JsonRpcInitializer.java | 42 ++++ .../ide/jsonrpc/JsonRpcRequestReceiver.java | 43 ---- .../jsonrpc/JsonRpcRequestTransmitter.java | 28 --- .../ide/jsonrpc/JsonRpcResponseReceiver.java | 44 ----- .../jsonrpc/JsonRpcResponseTransmitter.java | 28 --- .../che/ide/jsonrpc/RequestHandler.java | 120 ++++++++++++ .../che/ide/jsonrpc/RequestTransmitter.java | 110 +++++++++++ .../impl/AbstractJsonRpcDispatcher.java | 41 ++++ .../impl/BasicJsonRpcObjectValidator.java | 103 ---------- .../ide/jsonrpc/impl/JsonRpcDispatcher.java | 36 ---- .../ide/jsonrpc/impl/JsonRpcInitializer.java | 35 ---- .../jsonrpc/impl/JsonRpcObjectValidator.java | 26 --- .../jsonrpc/impl/JsonRpcRequestRegistry.java | 55 ------ .../jsonrpc/impl/NotificationDispatcher.java | 77 ++++++++ .../ide/jsonrpc/impl/RequestDispatcher.java | 112 +++++++++++ .../ide/jsonrpc/impl/ResponseDispatcher.java | 184 ++++++++++++++++++ .../impl/WebSocketJsonRpcDispatcher.java | 65 ------- .../impl/WebSocketJsonRpcInitializer.java | 20 +- .../WebSocketJsonRpcRequestDispatcher.java | 61 ------ .../WebSocketJsonRpcRequestTransmitter.java | 50 ----- .../WebSocketJsonRpcResponseDispatcher.java | 63 ------ .../WebSocketJsonRpcResponseTransmitter.java | 41 ---- .../impl/WebSocketJsonRpcTransmitter.java | 48 ----- .../impl/WebSocketToJsonRpcDispatcher.java | 77 ++++++++ .../jsonrpc/impl/WebSocketTransmitter.java | 132 +++++++++++++ .../ng/WebSocketMessageReceiver.java | 25 +-- .../ng/WebSocketMessageTransmitter.java | 21 +- .../ng/impl/BasicWebSocketEndpoint.java | 30 ++- .../BasicWebSocketMessageTransmitter.java | 41 ++-- .../BasicWebSocketTransmissionValidator.java | 105 ---------- ...java => DelayableWebSocketConnection.java} | 22 +-- .../websocket/ng/impl/MessagesReSender.java | 86 ++++++++ .../ng/impl/PendingMessagesReSender.java | 62 ------ .../ng/impl/SessionWebSocketInitializer.java | 52 ----- .../ide/websocket/ng/impl/UrlResolver.java | 83 ++++++++ .../che/ide/websocket/ng/impl/WebSocket.java | 65 ------- .../ng/impl/WebSocketConnection.java | 104 +++++----- .../ng/impl/WebSocketConnectionManager.java | 122 ++++++++++++ .../ng/impl/WebSocketConnectionSustainer.java | 58 +++--- .../ng/impl/WebSocketDispatcher.java | 50 +++++ .../websocket/ng/impl/WebSocketEndpoint.java | 24 ++- ...cketCreator.java => WebSocketFactory.java} | 7 +- .../ng/impl/WebSocketInitializer.java | 58 +++++- .../ng/impl/WebSocketJsoWrapper.java | 8 +- .../ng/impl/WebSocketPropertyManager.java | 158 +++++++++++++++ .../impl/WebSocketTransmissionDispatcher.java | 67 ------- .../impl/BasicJsonRpcObjectValidatorTest.java | 103 ---------- .../impl/JsonRpcRequestRegistryTest.java | 49 ----- .../impl/WebSocketJsonRpcDispatcherTest.java | 100 ---------- .../impl/WebSocketJsonRpcInitializerTest.java | 24 +-- ...WebSocketJsonRpcRequestDispatcherTest.java | 78 -------- ...ebSocketJsonRpcRequestTransmitterTest.java | 77 -------- ...ebSocketJsonRpcResponseDispatcherTest.java | 79 -------- ...bSocketJsonRpcResponseTransmitterTest.java | 65 ------- .../impl/WebSocketJsonRpcTransmitterTest.java | 86 -------- .../ng/impl/BasicWebSocketEndpointTest.java | 40 ++-- .../BasicWebSocketMessageTransmitterTest.java | 59 +++--- ...sicWebSocketTransmissionValidatorTest.java | 107 ---------- .../ng/impl/MessagesReSenderTest.java | 65 +++++++ .../ng/impl/PendingMessagesReSenderTest.java | 71 ------- .../impl/SessionWebSocketInitializerTest.java | 83 -------- .../websocket/ng/impl/UrlResolverTest.java} | 30 ++- .../impl/WebSocketConnectionManagerTest.java | 93 +++++++++ .../WebSocketConnectionSustainerTest.java | 122 ++++++++++-- .../ng/impl/WebSocketConnectionTest.java | 114 ----------- .../ng/impl/WebSocketDispatcherTest.java | 65 +++++++ .../ng/impl/WebSocketInitializerTest.java | 105 ++++++++++ .../ng/impl/WebSocketPropertyManagerTest.java | 77 ++++++++ .../WebSocketTransmissionDispatcherTest.java | 96 --------- ...GitCheckoutStatusNotificationHandler.java} | 21 +- .../ext/git/client/inject/GitGinModule.java | 13 +- .../api/git/GitCheckoutHiEventDetector.java | 20 +- .../git/GitCheckoutHiEventDetectorTest.java | 4 +- .../dto/event/VfsFileStatusUpdateDto.java | 2 - .../api/project/server/ProjectApiModule.java | 8 +- .../FileTrackingOperationReceiver.java | 20 +- .../FileTrackingOperationTransmitter.java | 40 ++-- .../event/detectors/FileTrackingRegistry.java | 26 +-- .../detectors/ProjectTreeChangesDetector.java | 27 +-- 141 files changed, 3224 insertions(+), 5091 deletions(-) delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestReceiver.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestTransmitter.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseReceiver.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseTransmitter.java create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestHandler.java create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestTransmitter.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidator.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcDispatcher.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcObjectValidator.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistry.java create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/NotificationDispatcher.java create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/ResponseDispatcher.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcher.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitter.java create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java create mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketTransmitter.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcError.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcObject.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcRequest.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcResponse.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidator.java rename core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/{PendingMessagesReSender.java => MessagesReSender.java} (72%) delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcher.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionValidator.java delete mode 100644 core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/shared/WebSocketTransmission.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistryTest.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java rename core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/{BasicWebSocketTransmissionTransmitterTest.java => BasicWebSocketMessageTransmitterTest.java} (59%) delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidatorTest.java rename core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/{PendingMessagesReSenderTest.java => MessagesReSenderTest.java} (52%) delete mode 100644 core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcherTest.java rename ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/{EditorFileStatusNotificationReceiver.java => EditorFileStatusNotificationHandler.java} (74%) rename ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/{ProjectTreeStatusNotificationReceiver.java => ProjectTreeStatusNotificationHandler.java} (75%) delete mode 100644 ide/che-core-ide-api/src/test/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationReceiverTest.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcInitializer.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestReceiver.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestTransmitter.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseReceiver.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseTransmitter.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestHandler.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestTransmitter.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/AbstractJsonRpcDispatcher.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidator.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcDispatcher.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcInitializer.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcObjectValidator.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistry.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/NotificationDispatcher.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/RequestDispatcher.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/ResponseDispatcher.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcher.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitter.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketTransmitter.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidator.java rename ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/{DelayableWebSocket.java => DelayableWebSocketConnection.java} (81%) create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSender.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSender.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializer.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolver.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocket.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManager.java create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcher.java rename ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/{WebSocketCreator.java => WebSocketFactory.java} (75%) create mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManager.java delete mode 100644 ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcher.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistryTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidatorTest.java create mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSenderTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSenderTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializerTest.java rename ide/commons-gwt/src/{main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionValidator.java => test/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolverTest.java} (52%) create mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManagerTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionTest.java create mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcherTest.java create mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializerTest.java create mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManagerTest.java delete mode 100644 ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcherTest.java rename plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/{GitCheckoutStatusNotificationReceiver.java => GitCheckoutStatusNotificationHandler.java} (76%) diff --git a/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/CheWebSocketEndpoint.java b/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/CheWebSocketEndpoint.java index 3e97c5363b2..05893530da3 100644 --- a/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/CheWebSocketEndpoint.java +++ b/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/CheWebSocketEndpoint.java @@ -10,11 +10,11 @@ *******************************************************************************/ package org.eclipse.che.wsagent.server; +import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; import org.eclipse.che.api.core.websocket.impl.BasicWebSocketEndpoint; import org.eclipse.che.api.core.websocket.impl.GuiceInjectorEndpointConfigurator; -import org.eclipse.che.api.core.websocket.impl.PendingMessagesReSender; +import org.eclipse.che.api.core.websocket.impl.MessagesReSender; import org.eclipse.che.api.core.websocket.impl.WebSocketSessionRegistry; -import org.eclipse.che.api.core.websocket.impl.WebSocketTransmissionDispatcher; import javax.inject.Inject; import javax.websocket.server.ServerEndpoint; @@ -31,8 +31,8 @@ public class CheWebSocketEndpoint extends BasicWebSocketEndpoint { @Inject public CheWebSocketEndpoint(WebSocketSessionRegistry registry, - PendingMessagesReSender reSender, - WebSocketTransmissionDispatcher dispatcher) { - super(registry, reSender, dispatcher); + MessagesReSender reSender, + WebSocketMessageReceiver receiver) { + super(registry, reSender, receiver); } } diff --git a/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentModule.java b/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentModule.java index db6182b6414..4821a64485c 100644 --- a/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentModule.java +++ b/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentModule.java @@ -20,18 +20,10 @@ import org.eclipse.che.UriApiEndpointProvider; import org.eclipse.che.UserTokenProvider; import org.eclipse.che.api.auth.oauth.OAuthTokenProvider; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestReceiver; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestTransmitter; -import org.eclipse.che.api.core.jsonrpc.JsonRpcResponseReceiver; -import org.eclipse.che.api.core.jsonrpc.JsonRpcResponseTransmitter; -import org.eclipse.che.api.core.jsonrpc.impl.BasicJsonRpcObjectValidator; -import org.eclipse.che.api.core.jsonrpc.impl.JsonRpcDispatcher; -import org.eclipse.che.api.core.jsonrpc.impl.JsonRpcObjectValidator; -import org.eclipse.che.api.core.jsonrpc.impl.WebSocketJsonRpcDispatcher; -import org.eclipse.che.api.core.jsonrpc.impl.WebSocketJsonRpcRequestDispatcher; -import org.eclipse.che.api.core.jsonrpc.impl.WebSocketJsonRpcRequestTransmitter; -import org.eclipse.che.api.core.jsonrpc.impl.WebSocketJsonRpcResponseDispatcher; -import org.eclipse.che.api.core.jsonrpc.impl.WebSocketJsonRpcResponseTransmitter; +import org.eclipse.che.api.core.jsonrpc.RequestHandler; +import org.eclipse.che.api.core.jsonrpc.RequestTransmitter; +import org.eclipse.che.api.core.jsonrpc.impl.WebSocketToJsonRpcDispatcher; +import org.eclipse.che.api.core.jsonrpc.impl.WebSocketTransmitter; import org.eclipse.che.api.core.notification.WSocketEventBusClient; import org.eclipse.che.api.core.rest.ApiInfoService; import org.eclipse.che.api.core.rest.CoreRestModule; @@ -39,9 +31,7 @@ import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; import org.eclipse.che.api.core.websocket.WebSocketMessageTransmitter; import org.eclipse.che.api.core.websocket.impl.BasicWebSocketMessageTransmitter; -import org.eclipse.che.api.core.websocket.impl.BasicWebSocketTransmissionValidator; import org.eclipse.che.api.core.websocket.impl.GuiceInjectorEndpointConfigurator; -import org.eclipse.che.api.core.websocket.impl.WebSocketTransmissionValidator; import org.eclipse.che.api.git.GitConnectionFactory; import org.eclipse.che.api.git.GitUserResolver; import org.eclipse.che.api.git.LocalGitUserResolver; @@ -119,31 +109,13 @@ Pair[] propagateEventsProvider(@Named("event.bus.url") String ev private void configureWebSocket() { requestStaticInjection(GuiceInjectorEndpointConfigurator.class); - bind(WebSocketTransmissionValidator.class).to(BasicWebSocketTransmissionValidator.class); - bind(WebSocketMessageTransmitter.class).to(BasicWebSocketMessageTransmitter.class); - - MapBinder receivers = - MapBinder.newMapBinder(binder(), String.class, WebSocketMessageReceiver.class); - - receivers.addBinding("jsonrpc-2.0").to(WebSocketJsonRpcDispatcher.class); + bind(WebSocketMessageReceiver.class).to(WebSocketToJsonRpcDispatcher.class); } private void configureJsonRpc() { - bind(JsonRpcObjectValidator.class).to(BasicJsonRpcObjectValidator.class); - - bind(JsonRpcResponseTransmitter.class).to(WebSocketJsonRpcResponseTransmitter.class); - bind(JsonRpcRequestTransmitter.class).to(WebSocketJsonRpcRequestTransmitter.class); - - MapBinder dispatchers = - MapBinder.newMapBinder(binder(), String.class, JsonRpcDispatcher.class); - - dispatchers.addBinding("request").to(WebSocketJsonRpcRequestDispatcher.class); - dispatchers.addBinding("response").to(WebSocketJsonRpcResponseDispatcher.class); + bind(RequestTransmitter.class).to(WebSocketTransmitter.class); - MapBinder requestReceivers = - MapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class); - MapBinder responseReceivers = - MapBinder.newMapBinder(binder(), String.class, JsonRpcResponseReceiver.class); + MapBinder.newMapBinder(binder(), String.class, RequestHandler.class); } } diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestReceiver.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestReceiver.java deleted file mode 100644 index 6cc1fa909bb..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestReceiver.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc; - - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; - -/** - * The implementation of this interface receives JSON RPC requests according to - * the mapping. The mapping is defined via MapBinder in one of Guice modules that - * are used in the application. Example is simple: - * - *
- *     
- *         MapBinder requestReceivers =
- *         MapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class);
- *         requestReceivers.addBinding("method-name").to(CustomJsonRpcRequestReceiver.class)
- *     
- * 
- * - * All JSON RPC requests that has their method names equal to "method-name" will be - * processed by instance of CustomJsonRpcRequestReceiver. Please note - * that you can use regular expressions for method names in order to be able to map - * single receiver implementation to a several kinds of requests. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcRequestReceiver { - /** - * Receives a JSON RPC request from an endpoint - * - * @param request - * request instance - * @param endpoint - * endpoint identifier - */ - void receive(JsonRpcRequest request, Integer endpoint); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestTransmitter.java deleted file mode 100644 index ca9b0e64bfa..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcRequestTransmitter.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc; - - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; - -/** - * Transmits a JSON RPC request to an endpoint or broadcast it. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcRequestTransmitter { - /** - * Transmits a JSON RPC request to an endpoint - * - * @param request - * JSON RPC request instance - * @param endpoint - * endpoint identifier - */ - void transmit(JsonRpcRequest request, Integer endpoint); - - /** - * Broadcasts a JSON RPC request to all available endpoints - * - * @param request - * JSON RPC request instance - */ - void transmit(JsonRpcRequest request); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseReceiver.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseReceiver.java deleted file mode 100644 index 9003563ac21..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseReceiver.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; - -/** - * The implementation of this interface receives JSON RPC responses according to - * the mapping. The mapping is defined via MapBinder in one of Guice modules that - * are used in the application. Example is simple: - * - *
- *     
- *         MapBinder responseReceivers =
- *         MapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class);
- *         responseReceivers.addBinding("method-name").to(CustomJsonRpcResponseReceiver.class)
- *     
- * 
- * - * In fact JSON RPC responses has no method defined in their body, though it is quite - * possible to bind requests and responses by their identifiers thus we can know which - * response correspond to which method. So responses that has their method names equal - * to "method-name" will be processed by instance of CustomJsonRpcResponseReceiver. - * Please note that you can use regular expressions for method names in order to be able - * to map single receiver implementation to a several kinds of requests. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcResponseReceiver { - /** - * Receive JSON RPC response from an endpoint - * - * @param response - * response instance - * @param endpoint - * endpoint identifier - */ - void receive(JsonRpcResponse response, Integer endpoint); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseTransmitter.java deleted file mode 100644 index a82b79d3709..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/JsonRpcResponseTransmitter.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc; - - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; - -/** - * Transmits a JSON RPC response to an endpoint or broadcast it. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcResponseTransmitter { - - /** - * Transmits a JSON RPC response to an endpoint - * - * @param response - * JSON RPC response instance - * @param endpoint - * endpoint identifier - */ - void transmit(JsonRpcResponse response, Integer endpoint); - - /** - * Broadcasts a JSON RPC response to all endpoints - * - * @param response - * JSON RPC response instance - */ - void transmit(JsonRpcResponse response); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestHandler.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestHandler.java new file mode 100644 index 00000000000..093a65a8518 --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestHandler.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.core.jsonrpc; + + +/** + * Request handlers are the key elements of json rpc request processing + * routines. You must extend this class if you want to handle a request to a + * specific method. In order to apply this handler you must register it inside + * dependency injection infrastructure (e.g. guice) The example: + *

+ * MapBinder.newMapBinder(binder(), String.class, RequestHandler.class) + * .addBinding("event:project-tree-status-changed") + * .to(ProjectTreeStatusHandler.class); + *

+ * where + *
    + *
  • + * event:project-tree-status-changed: corresponding method + *
  • + *
  • + * ProjectTreeStatusHandler: concrete implementation of + * request handler + *
  • + *
+ * Obvious limitation there can be only one handler for a combination of + * endpoint and method. + *

+ * Class has two generic parameters - P and R which + * corresponds to parameters DTO type and result DTO type. If handler is + * designed to process request without parameters you must specify that fact + * explicitly by defining a P parameter as {@link Void}. On the + * other hand handler can process a notification that means that it is not + * planned to send back a response in this situation you must similary define + * R as {@link Void}. + *

+ *

+ * All handling methods are throwing an {@link UnsupportedOperationException} + * so you must override method that mostly correspond the type of you handler. + * For example, if you are going to handle a notification without parameters + * you must override {@link RequestHandler#handleNotification(String)} method, + * while the implementation will independently (analyzing the request) define + * which handler and which method to call. + *

+ * + * @author Dmitry Kuleshov + */ +abstract public class RequestHandler { + + final private Class

paramsClass; + final private Class resultClass; + + protected RequestHandler(Class

paramsClass, Class resultClass) { + this.paramsClass = paramsClass; + this.resultClass = resultClass; + } + + public Class

getParamsClass() { + return paramsClass; + } + + public Class getResultClass() { + return resultClass; + } + + /** + * Handle a notification without parameters + * + * @param endpointId + * endpoint identifier that a notification comes from + */ + public void handleNotification(String endpointId) { + + throw new UnsupportedOperationException(); + } + + /** + * Handle a notification with parameters + * + * @param endpointId + * endpoint identifier that a notification comes from + * @param params + * parameters represented by DTO + */ + public void handleNotification(String endpointId, P params) { + throw new UnsupportedOperationException(); + } + + /** + * Handle a request without parameters + * + * @param endpointId + * endpoint identifier that a notification comes from + * + * @return result of handling of a request + */ + public R handleRequest(String endpointId) { + throw new UnsupportedOperationException(); + } + + /** + * Handle a request with parameters + * + * @param endpointId + * endpoint identifier that a notification comes from + * @param params + * parameters represented by DTO + * + * @return result of handling of a request + */ + public R handleRequest(String endpointId, P params) { + throw new UnsupportedOperationException(); + } +} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestTransmitter.java new file mode 100644 index 00000000000..323709651ed --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/RequestTransmitter.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.core.jsonrpc; + + +import java.util.concurrent.CompletableFuture; + +/** + * Transmits requests to a defined endpoint over json rpc 2.0. protocol. Single + * instance of transmitter is used for all registered endpoints. As json rpc is + * a transport agnostic protocol the way the transmission goes is defined by + * inner implementation. + * + * @author Dmitry Kuleshov + */ +public interface RequestTransmitter { + /** + * Transmit a notification that has no parameters to an endpoint + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + */ + void transmitNotification(String endpointId, String method); + + /** + * Transmit a notification that has parameters to an endpoint + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param params + * dto representing parameters + */ + void transmitNotification(String endpointId, String method, Object params); + + /** + * Transmit a request that has no parameters + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param resultClass + * class of response result section represented by DTO + * + * @return promise that contains response result represented by DTO + */ + CompletableFuture transmitRequest(String endpointId, String method, Class resultClass); + + /** + * Transmit a request that has parameters + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param params + * parameters represented by DTO + * @param resultClass + * class of response result section represented by DTO + * + * @return promise that contains response result represented by DTO + */ + CompletableFuture transmitRequest(String endpointId, String method, Object params, Class resultClass); + + /** + * Broadcasts a message to all registered web socket sessions + * + * @param method + * method name as defined in json rpc 2.0 specification + * @param params + * parameters represented by DTO + */ + void broadcast(String method, Object params); +} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidator.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidator.java deleted file mode 100644 index e879af29596..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidator.java +++ /dev/null @@ -1,106 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Set; - -/** - * Basic implementation of JSON RPC object validator. Validation rules are simple: - * - *

    - *
  • type must not be null
  • - *
  • type must not be empty
  • - *
  • type must be registered (mapped to a corresponding receiver implementation)
  • - *
  • message must not be null
  • - *
  • message must not be empty
  • - *
  • message must be a valid JSON
  • - *
- * - * @author Dmitry Kuleshov - */ -@Singleton -public class BasicJsonRpcObjectValidator implements JsonRpcObjectValidator { - private static final Logger LOG = LoggerFactory.getLogger(BasicJsonRpcObjectValidator.class); - - private final Set registeredTypes; - - @Inject - public BasicJsonRpcObjectValidator(Map dispatchers) { - this.registeredTypes = dispatchers.keySet(); - } - - @Override - public void validate(JsonRpcObject object) { - validateType(object.getType()); - validateMessage(object.getMessage()); - } - - private void validateType(String type) { - if (registeredTypes.contains(type)) { - LOG.trace("Json rpc object type {} is among registered", type); - } else { - logError("Json rpc object is of not registered type"); - } - } - - private void validateMessage(String message) { - validateNull(message); - validateEmpty(message); - validateJson(message); - } - - private void validateNull(String message) { - if (message == null) { - logError("Json rpc object message is null"); - } else { - LOG.trace("Json rpc object message is not null"); - } - } - - private void validateEmpty(String message) { - if (message.isEmpty()) { - logError("Json rpc object message is empty"); - } else { - LOG.trace("Json rpc object message is not empty"); - } - } - - private void validateJson(String message) { - boolean error = false; - - try { - new JsonParser().parse(message); - } catch (JsonSyntaxException e) { - error = true; - } - - if (error) { - logError("Json rpc object message is not a valid json"); - } else { - LOG.trace("Json rpc object message is a valid json"); - } - } - - private void logError(String error) { - LOG.error(error); - throw new IllegalArgumentException(error); - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcDispatcher.java deleted file mode 100644 index 80aec724f9f..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcDispatcher.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; - -/** - * There are two implementations of this interface: - * - *
    - *
  • {@link WebSocketJsonRpcRequestDispatcher}
  • - *
  • {@link WebSocketJsonRpcResponseDispatcher}
  • - *
- * - * Each implementation is used to dispatch messages of {@link JsonRpcObject} - * of corresponding type: requests or response. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcDispatcher { - /** - * Dispatches a message from an endpoint - * - * @param message - * message - * @param endpointId - * endpoint identifier - */ - void dispatch(String message, Integer endpointId); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcObjectValidator.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcObjectValidator.java deleted file mode 100644 index c31ba0d3656..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcObjectValidator.java +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; - -/** - * It is used to make sure that {@link JsonRpcObject} is a valid entity. - * Implementation of this interface must be called before any other operation - * is performed to avoid any kind of inconsistency. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcObjectValidator { - void validate(JsonRpcObject object); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistry.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistry.java deleted file mode 100644 index 3ff6388f5d1..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistry.java +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Binds request identifiers with request methods. Registry is used by response receivers - * to find out what method call is being answered. This is mostly needed because JSON RPC - * specification does not define method section in JSON RPC responses so there is no method - * name that can be directly mapped to a corresponding receiver. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class JsonRpcRequestRegistry { - private static final Logger LOG = LoggerFactory.getLogger(JsonRpcRequestRegistry.class); - - private final Map requests; - - @Inject - public JsonRpcRequestRegistry() { - this.requests = new ConcurrentHashMap<>(); - } - - /** - * Add request identifier - request method binding to the registry. - * - * @param id - * request identifier - * @param method - * request method - */ - public void add(Integer id, String method) { - LOG.debug("Binding ID: {} to method: {}", id, method); - - requests.put(id, method); - } - - /** - * Extracts request method name bound to request identifier - * - * @param id - * request identifier - * - * @return request method name - */ - public String extractFor(Integer id) { - LOG.debug("Extracting method with ID: {}", id); - - return requests.remove(id); - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/NotificationDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/NotificationDispatcher.java new file mode 100644 index 00000000000..db06368c8f9 --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/NotificationDispatcher.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.core.jsonrpc.impl; + +import com.google.gson.JsonObject; + +import org.eclipse.che.api.core.jsonrpc.RequestHandler; +import org.eclipse.che.dto.server.DtoFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Map; + +/** + * Dispatches incoming json rpc notification + * + * @author Dmitry Kuleshov + */ +@Singleton +public class NotificationDispatcher { + private static final Logger LOG = LoggerFactory.getLogger(NotificationDispatcher.class); + + private final Map handlers; + + @Inject + public NotificationDispatcher(Map handlers) { + this.handlers = handlers; + } + + /** + * Dispatches json rpc notification received from endpoint identified by a + * high level identifier and represented as a json object. + * + * @param endpointId + * high level endpoint identifier + * @param incomingJson + * json object + */ + public void dispatch(String endpointId, JsonObject incomingJson) { + LOG.debug("Dispatching incoming notification from: " + endpointId + ", json: " + incomingJson); + + final String method = incomingJson.get("method").getAsString(); + LOG.debug("Extracted notification method: " + method); + + final RequestHandler handler = handlers.get(method); + + if (incomingJson.has("params")) { + final JsonObject params = incomingJson.get("params").getAsJsonObject(); + LOG.debug("Notification is parametrized, processing parameters: " + params); + + final Class paramsClass = handler.getParamsClass(); + LOG.debug("Extracted notification params class: " + paramsClass); + + dispatch(endpointId, handler, params, paramsClass); + } else { + LOG.debug("Notification is not parametrized"); + + + dispatch(endpointId, handler); + } + } + + private void dispatch(String endpointId, RequestHandler handler) { + handler.handleNotification(endpointId); + } + + private

void dispatch(String endpointId, RequestHandler handler, JsonObject params, Class

paramClass) { + final P param = DtoFactory.getInstance().createDtoFromJson(params.toString(), paramClass); + handler.handleNotification(endpointId, param); + } +} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java new file mode 100644 index 00000000000..0c76b240721 --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.core.jsonrpc.impl; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.eclipse.che.api.core.jsonrpc.RequestHandler; +import org.eclipse.che.api.core.websocket.WebSocketMessageTransmitter; +import org.eclipse.che.dto.server.DtoFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Map; + +/** + * Dispatches incoming json rpc requests + * + * @author Dmitry Kuleshov + */ +@Singleton +public class RequestDispatcher { + private static final Logger LOG = LoggerFactory.getLogger(RequestDispatcher.class); + + private final Map handlers; + private final WebSocketMessageTransmitter transmitter; + + @Inject + public RequestDispatcher(Map handlers, WebSocketMessageTransmitter transmitter) { + this.handlers = handlers; + this.transmitter = transmitter; + } + + /** + * Dispatches json rpc request received from endpoint identified by a high + * level identifier and represented as a json object. + * + * @param endpointId + * high level endpoint identifier + * @param incomingJson + * json object + */ + public void dispatch(String endpointId, JsonObject incomingJson) { + LOG.debug("Dispatching incoming request from: " + endpointId + ", json: " + incomingJson); + + final String id = incomingJson.get("id").getAsString(); + LOG.debug("Extracted request id: " + id); + + final String method = incomingJson.get("method").getAsString(); + LOG.debug("Extracted request method: " + method); + + final RequestHandler handler = handlers.get(method); + + final Class resultClass = handler.getResultClass(); + LOG.debug("Extracted request result class: " + resultClass); + + + JsonObject result; + if (incomingJson.has("params")) { + final JsonObject params = incomingJson.get("params").getAsJsonObject(); + LOG.debug("Request is parametrized, processing parameters: " + params); + + final Class paramsClass = handler.getParamsClass(); + LOG.debug("Extracted request params class: " + paramsClass); + + result = dispatch(endpointId, handler, params, paramsClass, resultClass); + } else { + LOG.debug("Request is parametrized."); + + result = dispatch(endpointId, handler, resultClass); + } + + final JsonObject response = prepareResponse(id, result); + LOG.debug("Generated response: " + response); + + transmitter.transmit(endpointId, response.toString()); + } + + private JsonObject dispatch(String endpointId, + RequestHandler handler, + JsonObject params, + Class

paramClass, + Class resultClass) { + final P param = DtoFactory.getInstance().createDtoFromJson(params.toString(), paramClass); + final R result = handler.handleRequest(endpointId, param); + final String resultString = DtoFactory.getInstance().toJson(result); + return new JsonParser().parse(resultString).getAsJsonObject(); + } + + private JsonObject dispatch(String endpointId, RequestHandler handler, Class resultClass) { + final R result = handler.handleRequest(endpointId); + final String resultString = DtoFactory.getInstance().toJson(result); + return new JsonParser().parse(resultString).getAsJsonObject(); + } + + private JsonObject prepareResponse(String id, JsonObject result) { + final JsonObject response = new JsonObject(); + + response.addProperty("jsonrpc", "2.0"); + response.addProperty("id", id); + response.add("result", result); + + return response; + } +} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/ResponseDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/ResponseDispatcher.java new file mode 100644 index 00000000000..55435d4c7ea --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/ResponseDispatcher.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.core.jsonrpc.impl; + +import com.google.gson.JsonObject; + +import org.eclipse.che.dto.server.DtoFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Singleton; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** + * Dispatches incoming json rpc responses + * + * @author Dmitry Kuleshov + */ +@Singleton +public class ResponseDispatcher { + private static final Logger LOG = LoggerFactory.getLogger(ResponseDispatcher.class); + + private final Map futures = new HashMap<>(); + private final Map> resultClasses = new HashMap<>(); + + /** + * Dispatches json rpc response received from endpoint identified by a high + * level identifier and represented as a json object. + * + * @param endpointId + * high level endpoint identifier + * @param incomingJson + * json object + */ + public void dispatch(String endpointId, JsonObject incomingJson) { + LOG.debug("Dispatching incoming response from: " + endpointId + ", json: " + incomingJson); + + final String id = incomingJson.get("id").getAsString(); + LOG.debug("Extracted response id: " + id); + + final String key = endpointId + '@' + id; + LOG.debug("Combined response key: " + key); + + final Class resultClass = resultClasses.get(key); + LOG.debug("Extracted result class: " + resultClass); + + final CompletableFuture completableFuture = futures.get(key); + + if (incomingJson.has("result")) { + LOG.debug("Response contains result field, processing result"); + + final JsonObject result = incomingJson.get("result").getAsJsonObject(); + final Object dto = DtoFactory.getInstance().createDtoFromJson(result.toString(), resultClass); + + completableFuture.complete(dto); + } else { + LOG.debug("Response contains error field, processing error"); + + final String error = "Error processing is not yet supported"; + LOG.error(error); + throw new UnsupportedOperationException(error); + } + + } + + /** + * Register and get a completable future that will be resolved when specified response + * will be dispatched. + * + * @param endpointId + * high level endpoint identifier + * @param requestId + * request identifier + * @param resultClass + * class of request result that is contained within response + * + * @return completable future based on result represented by DTO + */ + public CompletableFuture getCompletableFuture(String endpointId, String requestId, Class resultClass) { + final CompletableFuture future = new CompletableFuture<>(); + futures.put(endpointId + '@' + requestId, future); + resultClasses.put(endpointId + '@' + requestId, resultClass); + return future; + } +} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcher.java deleted file mode 100644 index 8f244fa9c7b..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcher.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.dto.server.DtoFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -/** - * Receives instances of raw {@link JsonRpcObject} extracted from {@link WebSocketTransmission}. - * They are raw because they are presented as {@link String}. Those objects are dispatched among - * more specific dispatchers {@link JsonRpcDispatcher}) according to their type (e.g. JSON RPC - * request/response dispatchers). - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcDispatcher implements WebSocketMessageReceiver { - private static final Logger LOG = LoggerFactory.getLogger(WebSocketJsonRpcDispatcher.class); - - private final Map dispatchers; - private final JsonRpcObjectValidator validator; - - @Inject - public WebSocketJsonRpcDispatcher(Map dispatchers, JsonRpcObjectValidator validator) { - this.dispatchers = dispatchers; - this.validator = validator; - } - - @Override - public void receive(String rawJsonRpcObject, Integer endpointId) { - final JsonRpcObject jsonRpcObject = DtoFactory.getInstance().createDtoFromJson(rawJsonRpcObject, JsonRpcObject.class); - validator.validate(jsonRpcObject); - - final String type = jsonRpcObject.getType(); - final String message = jsonRpcObject.getMessage(); - - for (Entry entry : dispatchers.entrySet()) { - final String typeCandidate = entry.getKey(); - if (Objects.equals(typeCandidate, type)) { - final JsonRpcDispatcher dispatcher = entry.getValue(); - LOG.debug("Matching json rpc message dispatcher: {}", dispatcher.getClass()); - dispatcher.dispatch(message, endpointId); - - return; - } - } - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java deleted file mode 100644 index 5de6d87f3f3..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestReceiver; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.eclipse.che.dto.server.DtoFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Dispatches JSON RPC requests among all registered implementations of {@link JsonRpcRequestReceiver} - * according to their method names. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcRequestDispatcher implements JsonRpcDispatcher { - private static final Logger LOG = LoggerFactory.getLogger(WebSocketJsonRpcRequestDispatcher.class); - - private final Map receivers; - - @Inject - public WebSocketJsonRpcRequestDispatcher(Map receivers) { - this.receivers = receivers; - } - - @Override - public void dispatch(String message, Integer endpointId) { - final JsonRpcRequest request = DtoFactory.getInstance().createDtoFromJson(message, JsonRpcRequest.class); - final String method = request.getMethod(); - - for (Entry entry : receivers.entrySet()) { - final String candidate = entry.getKey(); - if (Objects.equals(candidate, method)) { - final JsonRpcRequestReceiver receiver = entry.getValue(); - LOG.debug("Matching json rpc request receiver: {}", receiver.getClass()); - receiver.receive(request, endpointId); - } - } - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java deleted file mode 100644 index 52b3ef2f06a..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - - -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestTransmitter; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Transmits JSON RPC requests through to {@link WebSocketJsonRpcTransmitter} - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcRequestTransmitter implements JsonRpcRequestTransmitter { - private static final Logger LOG = LoggerFactory.getLogger(WebSocketJsonRpcRequestTransmitter.class); - - private final WebSocketJsonRpcTransmitter transmitter; - private final JsonRpcRequestRegistry registry; - - @Inject - public WebSocketJsonRpcRequestTransmitter(WebSocketJsonRpcTransmitter transmitter, JsonRpcRequestRegistry registry) { - this.transmitter = transmitter; - this.registry = registry; - } - - @Override - public void transmit(JsonRpcRequest request, Integer endpoint) { - internalTransmit(request, endpoint); - } - - @Override - public void transmit(JsonRpcRequest request) { - internalTransmit(request, null); - } - - private void internalTransmit(JsonRpcRequest request, Integer endpointId) { - final Integer id = request.getId(); - final String method = request.getMethod(); - - if (id != null) { - registry.add(id, method); - } - - LOG.debug("Transmitting a request\n {}", request); - - if (endpointId == null) { - transmitter.transmit("request", request.toString()); - } else { - transmitter.transmit("request", request.toString(), endpointId); - } - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java deleted file mode 100644 index cefacc82c88..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.JsonRpcResponseReceiver; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.eclipse.che.dto.server.DtoFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Dispatches JSON RPC responses among all registered implementations of {@link JsonRpcResponseReceiver} - * according to their method names. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcResponseDispatcher implements JsonRpcDispatcher { - private static final Logger LOG = LoggerFactory.getLogger(WebSocketJsonRpcResponseDispatcher.class); - - private final JsonRpcRequestRegistry requestRegistry; - private final Map receivers; - - @Inject - public WebSocketJsonRpcResponseDispatcher(JsonRpcRequestRegistry requestRegistry, Map receivers) { - this.requestRegistry = requestRegistry; - this.receivers = receivers; - } - - @Override - public void dispatch(String message, Integer endpointId) { - final JsonRpcResponse response = DtoFactory.getInstance().createDtoFromJson(message, JsonRpcResponse.class); - final String method = requestRegistry.extractFor(response.getId()); - - for (Entry entry : receivers.entrySet()) { - final String candidate = entry.getKey(); - if (Objects.equals(candidate, method)) { - final JsonRpcResponseReceiver receiver = entry.getValue(); - LOG.debug("Matching json rpc response receiver: {}", receiver.getClass()); - receiver.receive(response, endpointId); - } - } - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java deleted file mode 100644 index e8a3e825e42..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - - -import org.eclipse.che.api.core.jsonrpc.JsonRpcResponseTransmitter; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Transmits JSON RPC responses to {@link WebSocketJsonRpcTransmitter} - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcResponseTransmitter implements JsonRpcResponseTransmitter { - private static final Logger LOG = LoggerFactory.getLogger(WebSocketJsonRpcResponseTransmitter.class); - - private final WebSocketJsonRpcTransmitter transmitter; - - @Inject - public WebSocketJsonRpcResponseTransmitter(WebSocketJsonRpcTransmitter transmitter) { - this.transmitter = transmitter; - } - - @Override - public void transmit(JsonRpcResponse response, Integer endpoint) { - internalTransmit(response, endpoint); - } - - @Override - public void transmit(JsonRpcResponse response) { - internalTransmit(response, null); - } - - private void internalTransmit(JsonRpcResponse response, Integer endpointId) { - LOG.debug("Transmitting a response\n {}", response); - - if (endpointId == null) { - transmitter.transmit("response", response.toString()); - } else { - transmitter.transmit("response", response.toString(), endpointId); - } - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitter.java deleted file mode 100644 index b1d9657acb5..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitter.java +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.api.core.websocket.WebSocketMessageTransmitter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import static org.eclipse.che.dto.server.DtoFactory.newDto; - -/** - * Transmits JSON RPC objects to {@link WebSocketMessageTransmitter} - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcTransmitter { - private static final Logger LOG = LoggerFactory.getLogger(WebSocketJsonRpcTransmitter.class); - - private final WebSocketMessageTransmitter transmitter; - private final JsonRpcObjectValidator validator; - - @Inject - public WebSocketJsonRpcTransmitter(WebSocketMessageTransmitter transmitter, JsonRpcObjectValidator validator) { - this.transmitter = transmitter; - this.validator = validator; - } - - public void transmit(String type, String message, Integer endpointId) { - internalTransmit(message, type, endpointId); - } - - public void transmit(String type, String message) { - internalTransmit(message, type, null); - } - - private void internalTransmit(String message, String type, Integer endpointId) { - LOG.debug("Transmitting a json rpc object. Message: {} of type: {}", message); - final JsonRpcObject jsonRpcObject = newDto(JsonRpcObject.class).withType(type).withMessage(message); - validator.validate(jsonRpcObject); - - if (endpointId == null) { - transmitter.transmit("jsonrpc-2.0", jsonRpcObject.toString()); - } else { - transmitter.transmit("jsonrpc-2.0", jsonRpcObject.toString(), endpointId); - } - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java new file mode 100644 index 00000000000..fe77c505cda --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.core.jsonrpc.impl; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Dispatches messages received from web socket endpoint throughout json rpc + * inner infrastructure. + * + * @author Dmitry Kuleshov + */ +@Singleton +public class WebSocketToJsonRpcDispatcher implements WebSocketMessageReceiver { + private static final Logger LOG = LoggerFactory.getLogger(WebSocketToJsonRpcDispatcher.class); + + private final RequestDispatcher requestDispatcher; + private final NotificationDispatcher notificationDispatcher; + private final ResponseDispatcher responseDispatcher; + + @Inject + public WebSocketToJsonRpcDispatcher(RequestDispatcher requestDispatcher, + NotificationDispatcher notificationDispatcher, + ResponseDispatcher responseDispatcher) { + this.requestDispatcher = requestDispatcher; + this.notificationDispatcher = notificationDispatcher; + this.responseDispatcher = responseDispatcher; + } + + @Override + public void receive(String endpointId, String message) { + LOG.debug("Receiving a message from: " + endpointId + ", message" + message); + final JsonParser jsonParser = new JsonParser(); + final JsonElement jsonElement = jsonParser.parse(message); + + if (!jsonElement.isJsonObject()) { + final String error = "Json is an array, not supported yet"; + LOG.error(error); + throw new UnsupportedOperationException(error); + } + + final JsonObject incomingJson = jsonElement.getAsJsonObject(); + final boolean hasMethod = incomingJson.has("method"); + final boolean hasParams = incomingJson.has("params"); + final boolean hasId = incomingJson.has("id"); + final boolean hasResult = incomingJson.has("result"); + final boolean hasError = incomingJson.has("error"); + + if (hasMethod && hasId && !hasResult && !hasError) { + LOG.debug("It's a request, processing by request dispatcher."); + requestDispatcher.dispatch(endpointId, incomingJson); + return; + } + + if (hasMethod && !hasId && !hasResult && !hasError) { + LOG.debug("It's a notification, processing by notification dispatcher."); + notificationDispatcher.dispatch(endpointId, incomingJson); + return; + } + + if (!hasMethod && !hasParams && hasId && (hasError != hasResult)) { + LOG.debug("It's a response, processing by response dispatcher."); + responseDispatcher.dispatch(endpointId, incomingJson); + return; + } + + throw new IllegalStateException("Improper json rpc message."); + } +} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketTransmitter.java new file mode 100644 index 00000000000..079c3dcc065 --- /dev/null +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketTransmitter.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.core.jsonrpc.impl; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.eclipse.che.api.core.jsonrpc.RequestTransmitter; +import org.eclipse.che.api.core.websocket.WebSocketMessageTransmitter; +import org.eclipse.che.dto.server.DtoFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.util.concurrent.CompletableFuture; + +/** + * Web socket based json rpc transmitter implementation + * + * @author Dmitry Kuleshov + */ +public class WebSocketTransmitter implements RequestTransmitter { + private static final Logger LOG = LoggerFactory.getLogger(WebSocketTransmitter.class); + + private static long idCounter = 0L; + + private final ResponseDispatcher responseDispatcher; + private final WebSocketMessageTransmitter transmitter; + + @Inject + public WebSocketTransmitter(ResponseDispatcher responseDispatcher, WebSocketMessageTransmitter transmitter) { + this.responseDispatcher = responseDispatcher; + this.transmitter = transmitter; + } + + @Override + public void transmitNotification(String endpointId, String method) { + LOG.debug("Transmitting a parametrized notification to endpoint: " + endpointId + ", method: " + method); + + internalTransmit(endpointId, method, null, null); + } + + @Override + public void transmitNotification(String endpointId, String method, Object params) { + LOG.debug("Transmitting a parametrized notification to endpoint: " + endpointId + ", method: " + method + ", params:" + params); + + internalTransmit(endpointId, method, params, null); + } + + @Override + public CompletableFuture transmitRequest(String endpointId, String method, Class resultClass) { + LOG.debug("Transmitting a request to endpoint: " + endpointId + ", method: " + method + ", result class:" + resultClass); + + final String id = Long.toString(++idCounter); + internalTransmit(endpointId, method, null, id); + return responseDispatcher.getCompletableFuture(endpointId, id, resultClass); + } + + @Override + public CompletableFuture transmitRequest(String endpointId, String method, Object params, Class resultClass) { + LOG.debug("Transmitting a parametrized request to endpoint: " + endpointId + + ", method: " + method + + ", params:" + params + + ", result class:" + resultClass); + + final String id = Long.toString(++idCounter); + internalTransmit(endpointId, method, params, id); + return responseDispatcher.getCompletableFuture(endpointId, id, resultClass); + } + + @Override + public void broadcast(String method, Object params) { + final String id = null; + final String endpointId = null; + + internalTransmit(endpointId, method, params, id); + } + + private void internalTransmit(String endpointId, String method, Object dto, String id) { + final JsonObject request = new JsonObject(); + + request.addProperty("jsonrpc", "2.0"); + if (id != null) { + request.addProperty("id", id); + } + request.addProperty("method", method); + if (dto != null) { + final String dtoString = DtoFactory.getInstance().toJson(dto); + final JsonObject jsonParams = new JsonParser().parse(dtoString).getAsJsonObject(); + request.add("params", jsonParams); + } + + if (endpointId == null) { + transmitter.transmit(request.toString()); + } else { + transmitter.transmit(endpointId, request.toString()); + } + } + +} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcError.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcError.java deleted file mode 100644 index 290dbb75f07..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcError.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.shared; - -import org.eclipse.che.dto.shared.DTO; - -/** - * When a rpc call encounters an error, the Response Object MUST contain the error member - * with a value that is a Object with the following members: - * - *

    - *
  • code
  • - * A Number that indicates the error type that occurred. This MUST be an integer. - *
  • message
  • - * A String providing a short description of the error. The message SHOULD be limited to a - * concise single sentence. - *
  • data
  • - * A Primitive or Structured value that contains additional information about the error. - * This may be omitted. The value of this member is defined by the Server (e.g. detailed - * error information, nested errors etc.). - *
- * - * @author Dmitry Kuleshov - * @see Error Object - */ -@DTO -public interface JsonRpcError { - - Integer getCode(); - - String getMessage(); - - String getData(); - - JsonRpcError withCode(Integer code); - - JsonRpcError withMessage(String message); - - JsonRpcError withData(String data); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcObject.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcObject.java deleted file mode 100644 index 0d35474cf29..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcObject.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.shared; - -import org.eclipse.che.dto.shared.DTO; - -/** - * Stores JSON RPC request or JSON RPC response instances. Type of the instance - * is defined by type field, while request/response is stored as a - * {@link String} representation in a message field. - * - * @author Dmitry Kuleshov - */ -@DTO -public interface JsonRpcObject { - - String getType(); - - String getMessage(); - - JsonRpcObject withType(String type); - - JsonRpcObject withMessage(String message); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcRequest.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcRequest.java deleted file mode 100644 index 666da14feb5..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcRequest.java +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.shared; - -import org.eclipse.che.dto.shared.DTO; - -/** - * A rpc call is represented by sending a Request object to a Server. The Request object - * has the following members: - * - *
    - *
  • jsonrpc
  • - * A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0". - *
  • method
  • - * A String containing the name of the method to be invoked. Method names that begin with - * the word rpc followed by a period character (U+002E or ASCII 46) are reserved for rpc- - * internal methods and extensions and MUST NOT be used for anything else. - *
  • params
  • - * A Structured value that holds the parameter values to be used during the invocation of - * the method. This member MAY be omitted. - *
  • id
  • - * An identifier established by the Client that MUST contain a String, Number, or NULL - * value if included. If it is not included it is assumed to be a notification. The value - * SHOULD normally not be null and Numbers SHOULD NOT contain fractional parts - *
- * - * @author Dmitry Kuleshov - * @see Request Object - */ -@DTO -public interface JsonRpcRequest { - - Integer getId(); - - JsonRpcRequest withId(Integer id); - - String getJsonrpc(); - - String getMethod(); - - String getParams(); - - JsonRpcRequest withJsonrpc(String jsonrpc); - - JsonRpcRequest withMethod(String method); - - JsonRpcRequest withParams(String params); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcResponse.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcResponse.java deleted file mode 100644 index bc56808cf5a..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/shared/JsonRpcResponse.java +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.shared; - -import org.eclipse.che.dto.shared.DTO; - -/** - * When a rpc call is made, the Server MUST reply with a Response, except for in the - * case of Notifications. The Response is expressed as a single JSON Object, with the - * following members: - * - *
    - *
  • jsonrpc
  • - * A {@link String} specifying the version of the JSON-RPC protocol. MUST be - * exactly "2.0". - *
  • result
  • - * This member is REQUIRED on success. This member MUST NOT exist if there was - * an error invoking the method. The value of this member is determined by the - * method invoked on the Server. - *
  • error
  • - * This member is REQUIRED on error. This member MUST NOT exist if there was no - * error triggered during invocation. - *
  • id
  • - * This member is REQUIRED. It MUST be the same as the value of the id member in - * the Request Object. If there was an error in detecting the id in the Request - * object (e.g. Parse error/Invalid Request), it MUST be null. - *
- * - * Either the result member or error member MUST be included, but both members MUST NOT - * be included. - * - * @author Dmitry Kuleshov - * @see Response Object - */ -@DTO -public interface JsonRpcResponse { - - String getJsonrpc(); - - String getResult(); - - JsonRpcError getError(); - - Integer getId(); - - JsonRpcResponse withJsonrpc(String jsonrpc); - - JsonRpcResponse withResult(String result); - - JsonRpcResponse withError(JsonRpcError error); - - JsonRpcResponse withId(Integer id); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageReceiver.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageReceiver.java index b27bc516a18..4b01d3964d9 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageReceiver.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageReceiver.java @@ -11,23 +11,18 @@ package org.eclipse.che.api.core.websocket; /** - * The implementation of this interface receives WEB SOCKET messages corresponding - * to the registered protocol according to the defined mapping. The protocol must - * be mapped via MapBinder in an ordinary Guice module, for example: - * - *
- *     
- *         MapBinder receivers =
- *         MapBinder.newMapBinder(binder(), String.class, WebSocketMessageReceiver.class);
- *         receivers.addBinding("protocol-name").to(CustomWebSocketMessageReceiver.class);
- *     
- * 
- * - * All WEB SOCKET transmissions with the protocol field equal to "protocol-name" will - * be processed with the CustomWebSocketMessageReceiver instance. + * Used as entry point for a web socket protocol message consumers. * * @author Dmitry Kuleshov */ public interface WebSocketMessageReceiver { - void receive(String message, Integer endpointId); + /** + * Receives a message by a a web socket protocol. + * + * @param endpointId + * identifier of an endpoint known to an transmitter implementation + * @param message + * plain text message + */ + void receive(String endpointId, String message); } diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageTransmitter.java index 155facf6a92..781e99d8e36 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageTransmitter.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/WebSocketMessageTransmitter.java @@ -11,31 +11,36 @@ package org.eclipse.che.api.core.websocket; /** - * Transmits WEB SOCKET messages to an endpoint or broadcasts them - * to all available endpoints. + * Plain text transmitter over a web socket protocol. In current specification + * it is not required from and the implementor to fulfill strict ordering of + * sequential transmissions along with message delivery notification. The only + * guarantee that is required is to send a text message to predefined endpoint. * * @author Dmitry Kuleshov */ public interface WebSocketMessageTransmitter { /** - * Transmits WEB SOCKET messages to an endpoint + * Transmit a string message to an endpoint over wer socket protocol. The + * connection should be considered to be opened at the moment of calling, + * however the some of implementation may provide ability to cache messages + * until the connection is opened. * - * @param protocol - * message protocol - * @param message - * message body * @param endpointId - * endpoint identifier + * identifier of an endpoint known to an transmitter implementation + * @param message + * plain text message + * */ - void transmit(String protocol, String message, Integer endpointId); + void transmit(String endpointId, String message); /** - * Broadcasts WEB SOCKET messages to all endpoints + * Transmit (broadcast) a string message to all endpoints registered over + * web socket protocol. The connection should be considered to be opened at + * the moment of calling, however the some of implementation may provide + * ability to cache messages until the connection is opened. * - * @param protocol - * message protocol * @param message - * message body + * plain text message */ - void transmit(String protocol, String message); + void transmit(String message); } diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpoint.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpoint.java index 1b1c10db826..689b7e50238 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpoint.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpoint.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.core.websocket.impl; +import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,21 +30,22 @@ public class BasicWebSocketEndpoint { private static final Logger LOG = LoggerFactory.getLogger(BasicWebSocketEndpoint.class); - private final WebSocketSessionRegistry registry; - private final PendingMessagesReSender reSender; - private final WebSocketTransmissionDispatcher dispatcher; + private final WebSocketSessionRegistry registry; + private final MessagesReSender reSender; + private final WebSocketMessageReceiver receiver; - protected BasicWebSocketEndpoint(WebSocketSessionRegistry registry, - PendingMessagesReSender reSender, - WebSocketTransmissionDispatcher dispatcher) { + + public BasicWebSocketEndpoint(WebSocketSessionRegistry registry, + MessagesReSender reSender, + WebSocketMessageReceiver receiver) { this.registry = registry; this.reSender = reSender; - this.dispatcher = dispatcher; + this.receiver = receiver; } @OnOpen - public void onOpen(Session session, @PathParam("endpoint-id") Integer endpointId) { + public void onOpen(Session session, @PathParam("endpoint-id") String endpointId) { LOG.info("Web socket session opened"); LOG.info("Endpoint: {}", endpointId); @@ -54,16 +56,16 @@ public void onOpen(Session session, @PathParam("endpoint-id") Integer endpointId } @OnMessage - public void onMessage(String message, @PathParam("endpoint-id") Integer endpointId) { + public void onMessage(String message, @PathParam("endpoint-id") String endpointId) { LOG.debug("Receiving a web socket message."); LOG.debug("Endpoint: {}", endpointId); LOG.debug("Message: {}", message); - dispatcher.dispatch(message, endpointId); + receiver.receive(endpointId, message); } @OnClose - public void onClose(CloseReason closeReason, @PathParam("endpoint-id") Integer endpointId) { + public void onClose(CloseReason closeReason, @PathParam("endpoint-id") String endpointId) { LOG.info("Web socket session closed"); LOG.debug("Endpoint: {}", endpointId); LOG.debug("Close reason: {}:{}", closeReason.getReasonPhrase(), closeReason.getCloseCode()); @@ -72,7 +74,7 @@ public void onClose(CloseReason closeReason, @PathParam("endpoint-id") Integer e } @OnError - public void onError(Throwable t, @PathParam("endpoint-id") Integer endpointId) { + public void onError(Throwable t, @PathParam("endpoint-id") String endpointId) { LOG.info("Web socket session error"); LOG.debug("Endpoint: {}", endpointId); LOG.debug("Error: {}", t); diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketMessageTransmitter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketMessageTransmitter.java index 09e730ddeaa..70c92886613 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketMessageTransmitter.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketMessageTransmitter.java @@ -11,7 +11,6 @@ package org.eclipse.che.api.core.websocket.impl; import org.eclipse.che.api.core.websocket.WebSocketMessageTransmitter; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; import org.slf4j.Logger; import javax.inject.Inject; @@ -20,7 +19,6 @@ import java.io.IOException; import java.util.Optional; -import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.slf4j.LoggerFactory.getLogger; /** @@ -34,35 +32,28 @@ public class BasicWebSocketMessageTransmitter implements WebSocketMessageTransmitter { private static final Logger LOG = getLogger(BasicWebSocketMessageTransmitter.class); - private final WebSocketSessionRegistry registry; - private final PendingMessagesReSender resender; - private final WebSocketTransmissionValidator validator; + private final WebSocketSessionRegistry registry; + private final MessagesReSender reSender; @Inject - public BasicWebSocketMessageTransmitter(WebSocketSessionRegistry registry, - PendingMessagesReSender resender, - WebSocketTransmissionValidator validator) { + public BasicWebSocketMessageTransmitter(WebSocketSessionRegistry registry, MessagesReSender reSender) { this.registry = registry; - this.resender = resender; - this.validator = validator; + this.reSender = reSender; } @Override - public synchronized void transmit(String protocol, String message, Integer endpointId) { - final WebSocketTransmission transmission = newDto(WebSocketTransmission.class).withProtocol(protocol).withMessage(message); - validator.validate(transmission); - + public synchronized void transmit(String endpointId, String message) { final Optional sessionOptional = registry.get(endpointId); if (!sessionOptional.isPresent() || !sessionOptional.get().isOpen()) { LOG.debug("Session is not registered or closed, adding message to pending"); - resender.add(endpointId, transmission); + reSender.add(endpointId, message); } else { LOG.debug("Session registered and open, sending message"); try { - sessionOptional.get().getBasicRemote().sendText(transmission.toString()); + sessionOptional.get().getBasicRemote().sendText(message); } catch (IOException e) { LOG.error("Error while trying to send a message to a basic websocket remote endpoint", e); } @@ -70,11 +61,8 @@ public synchronized void transmit(String protocol, String message, Integer endpo } @Override - public synchronized void transmit(String protocol, String message) { - final WebSocketTransmission transmission = newDto(WebSocketTransmission.class).withProtocol(protocol).withMessage(message); - validator.validate(transmission); - - LOG.debug("Broadcasting a web socket transmission: ", transmission.toString()); + public synchronized void transmit(String message) { + LOG.debug("Broadcasting a web socket transmission: ", message); registry.getSessions() .stream() @@ -82,7 +70,7 @@ public synchronized void transmit(String protocol, String message) { .map(Session::getBasicRemote) .forEach(it -> { try { - it.sendText(transmission.toString()); + it.sendText(message); } catch (IOException e) { LOG.error("Error while trying to send a message to a basic websocket remote endpoint", e); } diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidator.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidator.java deleted file mode 100644 index 0f765a88fe3..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidator.java +++ /dev/null @@ -1,109 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.websocket.impl; - -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; - -import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.slf4j.Logger; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Set; - -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Basic implementation of WEB SOCKET transmission validator, validation rules are the following: - * - *
    - *
  • protocol must be not null
  • - *
  • protocol must be not empty
  • - *
  • protocol must be registered (mapped to a corresponding receiver implementation
  • - *
  • message must be not null
  • - *
  • message must be not empty
  • - *
  • message must be a valid JSON
  • - *
- * - * @author Dmitry Kuleshov - */ -@Singleton -public class BasicWebSocketTransmissionValidator implements WebSocketTransmissionValidator { - private static final Logger LOG = getLogger(BasicWebSocketTransmissionValidator.class); - - private final Set protocols; - - @Inject - public BasicWebSocketTransmissionValidator(Map receivers) { - this.protocols = receivers.keySet(); - } - - - @Override - public void validate(WebSocketTransmission transmission) { - validateProtocol(transmission.getProtocol()); - validateMessage(transmission.getMessage()); - } - - private void validateProtocol(String protocol) { - if (protocols.contains(protocol)) { - LOG.trace("Web socket transmission protocol {} is among registered", protocol); - } else { - logError("Web socket transmission of not registered protocol"); - } - } - - private void validateMessage(String message) { - validateNull(message); - validateEmpty(message); - validateJson(message); - } - - private void validateNull(String message) { - if (message == null) { - logError("Web socket transmission message is null"); - } else { - LOG.trace("Web socket transmission message is not null"); - } - } - - private void validateEmpty(String message) { - if (message.isEmpty()) { - logError("Web socket transmission message is empty"); - } else { - LOG.trace("Web socket transmission message is not empty"); - } - } - - private void validateJson(String message) { - boolean error = false; - - try { - new JsonParser().parse(message); - } catch (JsonSyntaxException e) { - error = true; - } - - if (error) { - logError("Web socket transmission message is not a valid json"); - } else { - LOG.trace("Web socket transmission message is a valid json"); - } - } - - private void logError(String error) { - LOG.error(error); - throw new IllegalArgumentException(error); - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/PendingMessagesReSender.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/MessagesReSender.java similarity index 72% rename from core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/PendingMessagesReSender.java rename to core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/MessagesReSender.java index a9fd1827640..c421a92543c 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/PendingMessagesReSender.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/MessagesReSender.java @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.che.api.core.websocket.impl; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; - import javax.inject.Inject; import javax.inject.Singleton; import javax.websocket.Session; @@ -30,20 +28,20 @@ * @author Dmitry Kuleshov */ @Singleton -public class PendingMessagesReSender { +public class MessagesReSender { private static final int MAX_MESSAGES = 100; private final WebSocketSessionRegistry registry; - private final Map> messagesMap = new HashMap<>(); + private final Map> messagesMap = new HashMap<>(); @Inject - public PendingMessagesReSender(WebSocketSessionRegistry registry) { + public MessagesReSender(WebSocketSessionRegistry registry) { this.registry = registry; } - public void add(Integer endpointId, WebSocketTransmission message) { - List messages = messagesMap.get(endpointId); + public void add(String endpointId, String message) { + List messages = messagesMap.get(endpointId); if (messages == null) { messages = new LinkedList<>(); @@ -55,8 +53,8 @@ public void add(Integer endpointId, WebSocketTransmission message) { } } - public void resend(Integer endpointId) { - final List messages = messagesMap.remove(endpointId); + public void resend(String endpointId) { + final List messages = messagesMap.remove(endpointId); if (messages == null || messages.isEmpty()) { return; @@ -70,13 +68,13 @@ public void resend(Integer endpointId) { final Session session = sessionOptional.get(); - final List backing = new ArrayList<>(messages); + final List backing = new ArrayList<>(messages); messages.clear(); - for (WebSocketTransmission message : backing) { + for (String message : backing) { if (session.isOpen()) { - session.getAsyncRemote().sendText(message.toString()); + session.getAsyncRemote().sendText(message); } else { messages.add(message); } diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistry.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistry.java index 641661eb6eb..7c5eb71697b 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistry.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistry.java @@ -32,21 +32,21 @@ public class WebSocketSessionRegistry { private static final Logger LOG = getLogger(WebSocketSessionRegistry.class); - private final Map sessionsMap = new ConcurrentHashMap<>(); + private final Map sessionsMap = new ConcurrentHashMap<>(); - public void add(Integer endpointId, Session session) { + public void add(String endpointId, Session session) { LOG.debug("Registering session with endpoint {}", session.getId(), endpointId); sessionsMap.put(endpointId, session); } - public void remove(Integer endpointId) { + public void remove(String endpointId) { LOG.debug("Cancelling registration for session with endpoint {}", endpointId); sessionsMap.remove(endpointId); } - public Optional get(Integer endpointId) { + public Optional get(String endpointId) { return Optional.ofNullable(sessionsMap.get(endpointId)); } diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcher.java deleted file mode 100644 index 99607289b38..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcher.java +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.websocket.impl; - -import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.dto.server.DtoFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -/** - * Dispatches a {@link WebSocketTransmission} messages among registered receivers - * ({@link WebSocketMessageReceiver}) according to WEB SOCKET transmission protocol - * field value. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketTransmissionDispatcher { - private static final Logger LOG = LoggerFactory.getLogger(WebSocketTransmissionDispatcher.class); - - private final Map receivers; - private final WebSocketTransmissionValidator validator; - - @Inject - public WebSocketTransmissionDispatcher(Map receivers, WebSocketTransmissionValidator validator) { - this.receivers = receivers; - this.validator = validator; - } - - public void dispatch(String rawTransmission, Integer endpointId) { - final WebSocketTransmission transmission = DtoFactory.getInstance().createDtoFromJson(rawTransmission, WebSocketTransmission.class); - validator.validate(transmission); - - final String protocol = transmission.getProtocol(); - final String message = transmission.getMessage(); - - LOG.debug("Receiving a web socket transmission. Protocol: " + protocol + " Message: " + message); - - for (Entry entry : receivers.entrySet()) { - final String protocolCandidate = entry.getKey(); - if (Objects.equals(protocolCandidate, protocol)) { - final WebSocketMessageReceiver receiver = entry.getValue(); - LOG.debug("Matching web socket transmission receiver: {}", receiver.getClass()); - receiver.receive(message, endpointId); - - return; - } - } - } -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionValidator.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionValidator.java deleted file mode 100644 index 18b7ebc158c..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionValidator.java +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.websocket.impl; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; - -/** - * It is used to make sure that {@link WebSocketTransmission} is a valid entity. - * Implementation of this interface must be called before any other operation - * is performed to avoid any kind of inconsistency. - * - * @author Dmitry Kuleshov - */ -public interface WebSocketTransmissionValidator { - void validate(WebSocketTransmission transmission); -} diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/shared/WebSocketTransmission.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/shared/WebSocketTransmission.java deleted file mode 100644 index f0667c85c0f..00000000000 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/websocket/shared/WebSocketTransmission.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.websocket.shared; - -import org.eclipse.che.dto.shared.DTO; - -/** - * Stores a WEB SOCKET transmission. Transmission contains the protocol and - * the message. Transmission protocol is defined by protocol field, - * while transmission message body is stored within message field. - */ -@DTO -public interface WebSocketTransmission { - String getProtocol(); - - WebSocketTransmission withProtocol(final String protocol); - - String getMessage(); - - WebSocketTransmission withMessage(final String message); -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java deleted file mode 100644 index b9113c0414f..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import java.util.Map; - -import static java.util.Collections.singleton; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link BasicJsonRpcObjectValidator} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class BasicJsonRpcObjectValidatorTest { - private static final String REGISTERED_TYPE = "registered-type"; - private static final String NOT_REGISTERED_TYPE = "not-registered-type"; - private static final String VALID_JSON = "{ \"name\": \"value\" }"; - private static final String NOT_VALID_JSON = "not a json value"; - @Mock - private Map dispatchers; - - private BasicJsonRpcObjectValidator validator; - - @Mock - private JsonRpcObject jsonRpcObject; - - @BeforeMethod - public void before() { - when(dispatchers.keySet()).thenReturn(singleton(REGISTERED_TYPE)); - - validator = new BasicJsonRpcObjectValidator(dispatchers); - - when(jsonRpcObject.getType()).thenReturn(REGISTERED_TYPE); - when(jsonRpcObject.getMessage()).thenReturn(VALID_JSON); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfTypeIsNull() { - when(jsonRpcObject.getType()).thenReturn(null); - - validator.validate(jsonRpcObject); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfTypeIsEmpty() { - when(jsonRpcObject.getType()).thenReturn(""); - - validator.validate(jsonRpcObject); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfTypeIsNotRegistered() { - when(jsonRpcObject.getType()).thenReturn(NOT_REGISTERED_TYPE); - - validator.validate(jsonRpcObject); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsNull() { - when(jsonRpcObject.getMessage()).thenReturn(null); - - validator.validate(jsonRpcObject); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsEmpty() { - when(jsonRpcObject.getMessage()).thenReturn(""); - - validator.validate(jsonRpcObject); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsNotAJson() { - when(jsonRpcObject.getMessage()).thenReturn(NOT_VALID_JSON); - - validator.validate(jsonRpcObject); - } - - @Test - public void shouldNotThrowExceptionIfObjectIsValid() { - validator.validate(jsonRpcObject); - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistryTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistryTest.java deleted file mode 100644 index 184ac506f07..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/JsonRpcRequestRegistryTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; - -/** - * Tests for {@link JsonRpcRequestRegistry} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class JsonRpcRequestRegistryTest { - private static final String METHOD_NAME = "method-name"; - private static final int REQUEST_ID = 1; - - private JsonRpcRequestRegistry registry; - - @BeforeMethod - public void before() { - registry = new JsonRpcRequestRegistry(); - } - - @Test - public void shouldProperlyRegister() { - registry.add(REQUEST_ID, METHOD_NAME); - - assertEquals(METHOD_NAME, registry.extractFor(1)); - } - - @Test - public void shouldProperlyExtract() { - registry.add(REQUEST_ID, METHOD_NAME); - - assertEquals(METHOD_NAME, registry.extractFor(1)); - assertNull(registry.extractFor(1)); - } - -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java deleted file mode 100644 index c598fb555ea..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import java.util.Map; - -import static java.util.Collections.singletonMap; -import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketJsonRpcDispatcher} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class WebSocketJsonRpcDispatcherTest { - private static final String MESSAGE = "message"; - private static final String REGISTERED_TYPE = "registered-type"; - private static final String NOT_REGISTERED_TYPE = "not-registered-type"; - private static final int ENDPOINT_ID = 0; - - @Mock - private Map dispatchers; - @Mock - private JsonRpcObjectValidator validator; - @InjectMocks - private WebSocketJsonRpcDispatcher dispatcher; - - @Mock - private JsonRpcDispatcher jsonRpcDispatcher; - - private JsonRpcObject object; - - @BeforeMethod - public void before() { - when(dispatchers.entrySet()).thenReturn(singletonMap(REGISTERED_TYPE, jsonRpcDispatcher).entrySet()); - - object = newDto(JsonRpcObject.class).withType(REGISTERED_TYPE).withMessage(MESSAGE); - } - - @Test - public void should() { - dispatcher.receive(object.toString(), ENDPOINT_ID); - } - - @Test - public void shouldValidateOnReceive() { - dispatcher.receive(object.toString(), ENDPOINT_ID); - - verify(validator).validate(eq(object)); - } - - @Test - public void shouldDispatchIfMatchFound() { - dispatcher.receive(object.toString(), ENDPOINT_ID); - - verify(jsonRpcDispatcher).dispatch(MESSAGE, ENDPOINT_ID); - } - - @Test - public void shouldNotDispatchIfMatchNotFound() { - object.withType(NOT_REGISTERED_TYPE); - - dispatcher.receive(object.toString(), ENDPOINT_ID); - - verify(jsonRpcDispatcher, never()).dispatch(MESSAGE, ENDPOINT_ID); - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java deleted file mode 100644 index d7808b404c9..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestReceiver; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; - -/** - * Tests for {@link WebSocketJsonRpcRequestDispatcher} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class WebSocketJsonRpcRequestDispatcherTest { - private static final String METHOD_NAME = "test-method"; - private static final int ENDPOINT_ID = 0; - private static final String PARAMS = "params"; - - @Mock - private Map receivers; - @InjectMocks - private WebSocketJsonRpcRequestDispatcher dispatcher; - - @Mock - private JsonRpcRequestReceiver receiver; - - @BeforeMethod - public void before() { - when(receivers.entrySet()).thenReturn(singletonMap(METHOD_NAME, receiver).entrySet()); - } - - @Test - public void shouldRunMatchingReceiver() { - dispatcher.dispatch(getMessage(METHOD_NAME), ENDPOINT_ID); - - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(JsonRpcRequest.class); - - verify(receiver).receive(requestCaptor.capture(), eq(ENDPOINT_ID)); - - final JsonRpcRequest request = requestCaptor.getValue(); - - assertEquals(request.getMethod(), "test-method"); - assertEquals(request.getParams(), PARAMS); - } - - private String getMessage(String method) { - return "{" + - "\"id\":\"" + "0" + "\"," + - "\"jsonrpc\":\"" + "2.0" + "\"," + - "\"method\":\"" + method + "\"," + - "\"params\":\"" + PARAMS + "\"" + - "}"; - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java deleted file mode 100644 index 5e43acc214e..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketJsonRpcRequestTransmitter} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class WebSocketJsonRpcRequestTransmitterTest { - private static final int ENDPOINT_ID = 0; - private static final int REQUEST_ID = 1; - private static final String MESSAGE = "message"; - private static final String TYPE = "request"; - private static final String METHOD_NAME = "method-name"; - - @Mock - private WebSocketJsonRpcTransmitter transmitter; - @Mock - private JsonRpcRequestRegistry registry; - @InjectMocks - private WebSocketJsonRpcRequestTransmitter requestTransmitter; - - @Mock - private JsonRpcRequest request; - - @BeforeMethod - public void before() { - when(request.toString()).thenReturn(MESSAGE); - when(request.getMethod()).thenReturn(METHOD_NAME); - when(request.getId()).thenReturn(REQUEST_ID); - } - - @Test - public void shouldRunWebSocketTransmitterWithEndpoint() { - requestTransmitter.transmit(request, ENDPOINT_ID); - - - verify(registry).add(eq(REQUEST_ID), eq(METHOD_NAME)); - verify(transmitter).transmit(TYPE, MESSAGE, ENDPOINT_ID); - } - - @Test - public void shouldRunWebSocketTransmitterWithoutEndpoint() { - requestTransmitter.transmit(request); - - - verify(registry).add(REQUEST_ID, METHOD_NAME); - verify(transmitter).transmit(TYPE, MESSAGE); - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java deleted file mode 100644 index 53dfff4c29b..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.JsonRpcResponseReceiver; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import java.util.Map; - -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.AssertJUnit.assertEquals; - -/** - * Tests for {@link WebSocketJsonRpcResponseDispatcher} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class WebSocketJsonRpcResponseDispatcherTest { - private static final Integer REQUEST_ID = 0; - private static final int ENDPOINT_ID = 1; - private static final String RESULT = "result"; - private static final String METHOD_NAME = "test-method"; - - @Mock - private JsonRpcRequestRegistry requestRegistry; - @Mock - private Map receivers; - @InjectMocks - private WebSocketJsonRpcResponseDispatcher dispatcher; - - @Mock - private JsonRpcResponseReceiver receiver; - - @BeforeMethod - public void before() { - when(receivers.entrySet()).thenReturn(singletonMap(METHOD_NAME, receiver).entrySet()); - } - - @Test - public void shouldRunMatchingReceiver() { - when(requestRegistry.extractFor(eq(0))).thenReturn(METHOD_NAME); - - dispatcher.dispatch(getMessage(0), ENDPOINT_ID); - - ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(JsonRpcResponse.class); - - verify(receiver).receive(responseCaptor.capture(), eq(ENDPOINT_ID)); - - final JsonRpcResponse response = responseCaptor.getValue(); - - assertEquals(response.getResult(), RESULT); - assertEquals(response.getId(), REQUEST_ID); - } - - private String getMessage(Integer id) { - return "{" + - "\"id\":\"" + id + "\"," + - "\"jsonrpc\":\"" + "2.0" + "\"," + - "\"result\":\"" + RESULT + "\"" + - "}"; - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java deleted file mode 100644 index 279441ecf7a..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketJsonRpcResponseTransmitter} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class WebSocketJsonRpcResponseTransmitterTest { - private static final int ENDPOINT_ID = 0; - private static final String MESSAGE = "message"; - private static final String TYPE = "response"; - - @Mock - private WebSocketJsonRpcTransmitter transmitter; - @InjectMocks - private WebSocketJsonRpcResponseTransmitter responseTransmitter; - - @Mock - private JsonRpcResponse response; - - @BeforeMethod - public void before() { - when(response.toString()).thenReturn(MESSAGE); - } - - - @Test - public void shouldRunWebSocketTransmitterWithEndpoint() { - responseTransmitter.transmit(response, ENDPOINT_ID); - - verify(transmitter).transmit(TYPE, MESSAGE, ENDPOINT_ID); - } - - @Test - public void shouldRunWebSocketTransmitterWithoutEndpoint() { - responseTransmitter.transmit(response); - - verify(transmitter).transmit(TYPE, MESSAGE); - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java deleted file mode 100644 index 11270143554..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.api.core.websocket.WebSocketMessageTransmitter; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.mockito.Mockito.verify; - -/** - * Tests for {@link WebSocketJsonRpcTransmitter} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class WebSocketJsonRpcTransmitterTest { - private static final String PROTOCOL = "jsonrpc-2.0"; - private static final String MESSAGE = "message"; - private static final String TYPE = "registered-type"; - private static final int ENDPOINT_ID = 0; - - @Mock - private WebSocketMessageTransmitter transmitter; - @Mock - private JsonRpcObjectValidator validator; - @InjectMocks - private WebSocketJsonRpcTransmitter jsonRpcTransmitter; - - private JsonRpcObject object; - - @BeforeMethod - public void before() { - object = newDto(JsonRpcObject.class).withType(TYPE).withMessage(MESSAGE); - } - - @Test - public void shouldValidateJsonRpcObjectWithoutEndpointSet() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE); - - verify(validator).validate(object); - } - - @Test - public void shouldTransmitJsonRpcObjectWithoutEndpointSet() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE); - - verify(transmitter).transmit(PROTOCOL, object.toString()); - } - - @Test - public void shouldValidateJsonRpcObjectWithEndpoint() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE, ENDPOINT_ID); - - verify(validator).validate(object); - } - - @Test - public void shouldTransmitJsonRpcObjectWithEndpoint() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE, ENDPOINT_ID); - - verify(transmitter).transmit(PROTOCOL, object.toString(), ENDPOINT_ID); - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpointTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpointTest.java index 50f1c1f33db..1d183cf962f 100644 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpointTest.java +++ b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketEndpointTest.java @@ -10,9 +10,12 @@ *******************************************************************************/ package org.eclipse.che.api.core.websocket.impl; +import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @@ -21,7 +24,6 @@ import static org.mockito.Mockito.verify; - /** * Tests for {@link BasicWebSocketEndpoint} * @@ -29,61 +31,55 @@ */ @Listeners(MockitoTestNGListener.class) public class BasicWebSocketEndpointTest { - private static final int ENDPOINT_ID = 0; - private static final String MESSAGE = "message"; - private static final int MAX_IDLE_TIMEOUT = 0; - - @Mock - private WebSocketSessionRegistry registry; @Mock - private PendingMessagesReSender reSender; + private WebSocketSessionRegistry registry; @Mock - private WebSocketTransmissionDispatcher dispatcher; + private MessagesReSender reSender; @Mock - private WebSocketTransmissionValidator validator; + private WebSocketMessageReceiver receiver; @InjectMocks - private BasicWebSocketEndpoint endpoint; + private BasicWebSocketEndpoint endpoint; @Mock - private Session session; + private Session session; @Mock private CloseReason closeReason; - @Mock - private Throwable throwable; - @Test - public void shouldSetSessionMaxIdleTimeoutOnOpen() { - endpoint.onOpen(session, ENDPOINT_ID); + @BeforeMethod + public void setUp() throws Exception { - verify(session).setMaxIdleTimeout(MAX_IDLE_TIMEOUT); } - @Test - public void shouldRegisterSessionOnOpen() { - endpoint.onOpen(session, ENDPOINT_ID); + @AfterMethod + public void tearDown() throws Exception { - verify(registry).add(ENDPOINT_ID, session); } @Test - public void shouldSendPendingMessagesSessionOnOpen() { - endpoint.onOpen(session, ENDPOINT_ID); + public void shouldAddToRegistryOnOpen(){ + endpoint.onOpen(session, "id"); - verify(reSender).resend(ENDPOINT_ID); + verify(registry).add("id", session); } @Test - public void shouldRemoveSessionFromRegistryOnClose() { - endpoint.onClose(closeReason, ENDPOINT_ID); + public void shouldResendOnOpen(){ + endpoint.onOpen(session, "id"); - verify(registry).remove(ENDPOINT_ID); + verify(reSender).resend("id"); } @Test - public void shouldRunReceiverOnMessage() { - endpoint.onMessage(MESSAGE, ENDPOINT_ID); + public void shouldRunReceiveOnMessage(){ + endpoint.onMessage("message", "id"); - verify(dispatcher).dispatch(MESSAGE, ENDPOINT_ID); + verify(receiver).receive("id", "message"); } + @Test + public void shouldRunRemoveOnClose(){ + endpoint.onClose(closeReason, "id"); + + verify(registry).remove("id"); + } } diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionTransmitterTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketMessageTransmitterTest.java similarity index 59% rename from core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionTransmitterTest.java rename to core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketMessageTransmitterTest.java index 89ea982a4e6..4873313e207 100644 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionTransmitterTest.java +++ b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketMessageTransmitterTest.java @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.che.api.core.websocket.impl; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.dto.server.DtoFactory; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -21,11 +19,13 @@ import javax.websocket.RemoteEndpoint; import javax.websocket.Session; + import java.io.IOException; import java.util.Optional; import static java.util.Collections.emptySet; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -37,17 +37,14 @@ * @author Dmitry Kuleshov */ @Listeners(MockitoTestNGListener.class) -public class BasicWebSocketTransmissionTransmitterTest { - private static final String PROTOCOL = "protocol"; +public class BasicWebSocketMessageTransmitterTest { private static final String MESSAGE = "message"; - private static final int ENDPOINT_ID = 0; + private static final String ENDPOINT_ID = "id"; @Mock private WebSocketSessionRegistry registry; @Mock - private PendingMessagesReSender reSender; - @Mock - private WebSocketTransmissionValidator validator; + private MessagesReSender reSender; @InjectMocks private BasicWebSocketMessageTransmitter transmitter; @@ -56,50 +53,31 @@ public class BasicWebSocketTransmissionTransmitterTest { @Mock private RemoteEndpoint.Basic remote; - private WebSocketTransmission transmission; - - @BeforeMethod public void setUp() throws Exception { when(session.getBasicRemote()).thenReturn(remote); when(session.isOpen()).thenReturn(true); - when(registry.get(eq(ENDPOINT_ID))).thenReturn(Optional.of(session)); + when(registry.get(ENDPOINT_ID)).thenReturn(Optional.of(session)); when(registry.getSessions()).thenReturn(emptySet()); - - transmission = DtoFactory.newDto(WebSocketTransmission.class).withProtocol(PROTOCOL).withMessage(MESSAGE); - } - - @Test - public void shouldValidateDirectMessage() { - transmitter.transmit(PROTOCOL, MESSAGE, ENDPOINT_ID); - - verify(validator).validate(any(WebSocketTransmission.class)); - } - - @Test - public void shouldValidateBroadcastMessage() { - transmitter.transmit(PROTOCOL, MESSAGE, ENDPOINT_ID); - - verify(validator).validate(any(WebSocketTransmission.class)); } @Test public void shouldSendDirectMessageIfSessionIsOpenAndEndpointIsSet() throws IOException { - transmitter.transmit(PROTOCOL, MESSAGE, ENDPOINT_ID); + transmitter.transmit(ENDPOINT_ID, MESSAGE); verify(session).getBasicRemote(); - verify(remote).sendText(transmission.toString()); - verify(reSender, never()).add(eq(ENDPOINT_ID), any(WebSocketTransmission.class)); + verify(remote).sendText(MESSAGE); + verify(reSender, never()).add(eq(ENDPOINT_ID), anyString()); } @Test public void shouldSendBroadcastingMessageIfSessionIsOpen() throws IOException { - transmitter.transmit(PROTOCOL, MESSAGE); + transmitter.transmit(MESSAGE); verify(session, never()).getBasicRemote(); - verify(remote, never()).sendText(transmission.toString()); - verify(reSender, never()).add(any(), any(WebSocketTransmission.class)); + verify(remote, never()).sendText(MESSAGE); + verify(reSender, never()).add(any(), anyString()); verify(registry).getSessions(); } @@ -108,10 +86,10 @@ public void shouldSendBroadcastingMessageIfSessionIsOpen() throws IOException { public void shouldAddMessageToPendingIfSessionIsNotOpenedAndEndpointIsSet() throws IOException { when(session.isOpen()).thenReturn(false); - transmitter.transmit(PROTOCOL, MESSAGE, ENDPOINT_ID); + transmitter.transmit(ENDPOINT_ID, MESSAGE); verify(session, never()).getBasicRemote(); - verify(remote, never()).sendText(transmission.toString()); - verify(reSender).add(eq(ENDPOINT_ID), any(WebSocketTransmission.class)); + verify(remote, never()).sendText(MESSAGE); + verify(reSender).add(ENDPOINT_ID, MESSAGE); } } diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidatorTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidatorTest.java deleted file mode 100644 index 4d808a1cbf4..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/BasicWebSocketTransmissionValidatorTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.websocket.impl; - -import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import java.util.Collections; -import java.util.Map; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - - -/** - * Tests for {@link BasicWebSocketTransmissionValidator} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class BasicWebSocketTransmissionValidatorTest { - private static final String REGISTERED_PROTOCOL = "registered-protocol"; - private static final String NOT_REGISTERED_PROTOCOL = "not-registered-protocol"; - private static final String VALID_JSON = "{ \"name\": \"value\" }"; - private static final String NOT_VALID_JSON = "not valid json"; - - @Mock - private Map receivers; - - private BasicWebSocketTransmissionValidator validator; - - @Mock - private WebSocketTransmission transmission; - - @BeforeMethod - public void beforeMethod() { - when(transmission.getProtocol()).thenReturn(REGISTERED_PROTOCOL); - when(transmission.getMessage()).thenReturn(VALID_JSON); - - when(receivers.keySet()).thenReturn(Collections.singletonMap(REGISTERED_PROTOCOL, mock(WebSocketMessageReceiver.class)).keySet()); - validator = new BasicWebSocketTransmissionValidator(receivers); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void validateTransmissionShouldThrowExceptionIfProtocolIsNull() { - when(transmission.getProtocol()).thenReturn(null); - - validator.validate(transmission); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfProtocolIsEmpty() { - when(transmission.getProtocol()).thenReturn(""); - - validator.validate(transmission); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsNull() { - when(transmission.getMessage()).thenReturn(null); - - validator.validate(transmission); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsEmpty() { - when(transmission.getMessage()).thenReturn(""); - - validator.validate(transmission); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfProtocolIsNotRegistered() { - when(transmission.getProtocol()).thenReturn(NOT_REGISTERED_PROTOCOL); - - validator.validate(transmission); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsNotValidJson() { - when(transmission.getMessage()).thenReturn(NOT_VALID_JSON); - - validator.validate(transmission); - } - - @Test - public void validateReceptionShouldPassForValidWebSocketTransmission() { - validator.validate(transmission); - } -} diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/PendingMessagesReSenderTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/MessagesReSenderTest.java similarity index 52% rename from core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/PendingMessagesReSenderTest.java rename to core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/MessagesReSenderTest.java index dde9abd202a..b46e00095c6 100644 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/PendingMessagesReSenderTest.java +++ b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/MessagesReSenderTest.java @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.che.api.core.websocket.impl; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -20,139 +19,138 @@ import javax.websocket.RemoteEndpoint; import javax.websocket.Session; + import java.util.Optional; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** - * Tests for {@link PendingMessagesReSender} + * Tests for {@link MessagesReSender} * * @author Dmitry Kuleshov */ @Listeners(MockitoTestNGListener.class) -public class PendingMessagesReSenderTest { +public class MessagesReSenderTest { private static final String MESSAGE = "message"; - private static final int ENDPOINT_ID = 0; + private static final String ENDPOINT_ID = "id"; @Mock private WebSocketSessionRegistry sessionRegistry; @InjectMocks - private PendingMessagesReSender resender; + private MessagesReSender reSender; @Mock private Session session; @Mock private RemoteEndpoint.Async endpoint; - @Mock - private WebSocketTransmission transmission; @BeforeMethod public void beforeMethod() { - when(sessionRegistry.get(any(Integer.class))).thenReturn(Optional.of(session)); + when(sessionRegistry.get(anyString())).thenReturn(Optional.of(session)); when(session.getAsyncRemote()).thenReturn(endpoint); when(session.isOpen()).thenReturn(true); - when(transmission.toString()).thenReturn(MESSAGE); } @BeforeMethod public void before() { - resender = new PendingMessagesReSender(sessionRegistry); + reSender = new MessagesReSender(sessionRegistry); } @Test public void shouldStopIfSessionIsNotRegistered() { - when(sessionRegistry.get(any(Integer.class))).thenReturn(Optional.empty()); + when(sessionRegistry.get(anyString())).thenReturn(Optional.empty()); - resender.add(ENDPOINT_ID, transmission); + reSender.add(ENDPOINT_ID, MESSAGE); - resender.resend(ENDPOINT_ID); + reSender.resend(ENDPOINT_ID); - verify(sessionRegistry).get(eq(ENDPOINT_ID)); + verify(sessionRegistry).get(ENDPOINT_ID); verify(session, never()).getAsyncRemote(); - verify(endpoint, never()).sendText(eq(MESSAGE)); + verify(endpoint, never()).sendText(MESSAGE); } @Test public void shouldKeepMessagesIfSessionIsClosed() { - resender.add(ENDPOINT_ID, transmission); + reSender.add(ENDPOINT_ID, MESSAGE); when(session.isOpen()).thenReturn(false); - resender.resend(ENDPOINT_ID); + reSender.resend(ENDPOINT_ID); verify(session, never()).getAsyncRemote(); - verify(endpoint, never()).sendText(eq(MESSAGE)); + verify(endpoint, never()).sendText(MESSAGE); when(session.isOpen()).thenReturn(true); - resender.resend(ENDPOINT_ID); + reSender.resend(ENDPOINT_ID); verify(session).getAsyncRemote(); - verify(endpoint).sendText(eq(MESSAGE)); + verify(endpoint).sendText(MESSAGE); } @Test public void shouldProperlyAddForSingleEndpoint() { - resender.add(ENDPOINT_ID, transmission); + reSender.add(ENDPOINT_ID, MESSAGE); - resender.resend(ENDPOINT_ID); + reSender.resend(ENDPOINT_ID); - verify(sessionRegistry).get(eq(ENDPOINT_ID)); + verify(sessionRegistry).get(ENDPOINT_ID); verify(session).getAsyncRemote(); - verify(endpoint).sendText(eq(MESSAGE)); + verify(endpoint).sendText(MESSAGE); } @Test public void shouldProperlyAddForSeveralEndpoints() { - resender.add(ENDPOINT_ID, transmission); - resender.add(1, transmission); + reSender.add(ENDPOINT_ID, MESSAGE); + reSender.add("1", MESSAGE); - resender.resend(ENDPOINT_ID); - resender.resend(1); + reSender.resend(ENDPOINT_ID); + reSender.resend("1"); - verify(sessionRegistry).get(eq(ENDPOINT_ID)); - verify(sessionRegistry).get(eq(1)); + verify(sessionRegistry).get(ENDPOINT_ID); + verify(sessionRegistry).get("1"); verify(session, times(2)).getAsyncRemote(); - verify(endpoint, times(2)).sendText(eq(MESSAGE)); + verify(endpoint, times(2)).sendText(MESSAGE); } @Test public void shouldClearOnExtractionForSingleEndpoint() { - resender.add(ENDPOINT_ID, transmission); + reSender.add(ENDPOINT_ID, MESSAGE); - resender.resend(ENDPOINT_ID); - verify(sessionRegistry).get(eq(ENDPOINT_ID)); + reSender.resend(ENDPOINT_ID); + verify(sessionRegistry).get(ENDPOINT_ID); verify(session).getAsyncRemote(); - verify(endpoint).sendText(eq(MESSAGE)); + verify(endpoint).sendText(MESSAGE); - resender.resend(ENDPOINT_ID); - verify(sessionRegistry).get(eq(ENDPOINT_ID)); + reSender.resend(ENDPOINT_ID); + verify(sessionRegistry).get(ENDPOINT_ID); verify(session).getAsyncRemote(); - verify(endpoint).sendText(eq(MESSAGE)); + verify(endpoint).sendText(MESSAGE); } @Test public void shouldClearOnExtractionForSeveralEndpoint() { - resender.add(ENDPOINT_ID, transmission); - resender.add(1, transmission); + reSender.add(ENDPOINT_ID, MESSAGE); + reSender.add("1", MESSAGE); - resender.resend(ENDPOINT_ID); - resender.resend(1); + reSender.resend(ENDPOINT_ID); + reSender.resend("1"); - verify(sessionRegistry).get(eq(ENDPOINT_ID)); - verify(sessionRegistry).get(eq(1)); + verify(sessionRegistry).get(ENDPOINT_ID); + verify(sessionRegistry).get("1"); verify(session, times(2)).getAsyncRemote(); - verify(endpoint, times(2)).sendText(eq(MESSAGE)); + verify(endpoint, times(2)).sendText(MESSAGE); - resender.resend(ENDPOINT_ID); - resender.resend(1); + reSender.resend(ENDPOINT_ID); + reSender.resend("1"); - verify(sessionRegistry).get(eq(ENDPOINT_ID)); - verify(sessionRegistry).get(eq(1)); + verify(sessionRegistry).get(ENDPOINT_ID); + verify(sessionRegistry).get("1"); verify(session, times(2)).getAsyncRemote(); - verify(endpoint, times(2)).sendText(eq(MESSAGE)); + verify(endpoint, times(2)).sendText(MESSAGE); } } diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistryTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistryTest.java index 40268f4c4d0..274664d0fa4 100644 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistryTest.java +++ b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketSessionRegistryTest.java @@ -12,18 +12,16 @@ import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import javax.websocket.Session; + import java.util.Optional; import static org.mockito.Mockito.mock; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; /** * Tests for {@link WebSocketSessionRegistry} @@ -47,16 +45,16 @@ public void setUp() throws Exception { public void shouldAddSession() { assertTrue(registry.getSessions().isEmpty()); - registry.add(0, session); + registry.add("0", session); assertFalse(registry.getSessions().isEmpty()); } @Test public void shouldAddCorrectSession() { - registry.add(0, this.session); + registry.add("0", this.session); - final Optional sessionOptional = registry.get(0); + final Optional sessionOptional = registry.get("0"); assertTrue(sessionOptional.isPresent()); final Session session = sessionOptional.get(); @@ -66,24 +64,24 @@ public void shouldAddCorrectSession() { @Test public void shouldRemoveSession() { - registry.add(0, session); + registry.add("0", session); assertFalse(registry.getSessions().isEmpty()); assertEquals(1, registry.getSessions().size()); - registry.remove(0); + registry.remove("0"); assertTrue(registry.getSessions().isEmpty()); } @Test public void shouldGetAllSessions() { - registry.add(0, session); + registry.add("0", session); assertFalse(registry.getSessions().isEmpty()); assertEquals(1, registry.getSessions().size()); - registry.add(1, mock(Session.class)); + registry.add("1", mock(Session.class)); assertFalse(registry.getSessions().isEmpty()); assertEquals(2, registry.getSessions().size()); diff --git a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcherTest.java b/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcherTest.java deleted file mode 100644 index c80e616cff7..00000000000 --- a/core/che-core-api-core/src/test/java/org/eclipse/che/api/core/websocket/impl/WebSocketTransmissionDispatcherTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.core.websocket.impl; - -import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import java.util.Collections; -import java.util.Map; - -import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketTransmissionDispatcher} - * - * @author Dmitry Kuleshov - */ -@Listeners(MockitoTestNGListener.class) -public class WebSocketTransmissionDispatcherTest { - private static final int ENDPOINT_ID = 0; - private static final String REGISTERED_PROTOCOL = "registered-protocol"; - private static final String NOT_REGISTERED_PROTOCOL = "not-registered-protocol"; - private static final String MESSAGE = "message"; - @Mock - private Map receivers; - @Mock - private WebSocketTransmissionValidator validator; - @InjectMocks - private WebSocketTransmissionDispatcher dispatcher; - - @Mock - private WebSocketMessageReceiver receiver; - - private WebSocketTransmission transmission; - - @BeforeMethod - public void before() { - when(receivers.entrySet()).thenReturn(Collections.singletonMap(REGISTERED_PROTOCOL, receiver).entrySet()); - - transmission = newDto(WebSocketTransmission.class).withProtocol(REGISTERED_PROTOCOL).withMessage(MESSAGE); - } - - @Test - public void shouldValidateWebSocketTransmission() { - dispatcher.dispatch(transmission.toString(), ENDPOINT_ID); - - verify(validator).validate(transmission); - } - - @Test - public void shouldRunReceiverOnMatch() { - dispatcher.dispatch(transmission.toString(), ENDPOINT_ID); - - verify(receiver).receive(MESSAGE, ENDPOINT_ID); - } - - @Test - public void shouldNotRunReceiverOnNoMatch() { - transmission.withProtocol(NOT_REGISTERED_PROTOCOL); - - dispatcher.dispatch(transmission.toString(), ENDPOINT_ID); - - verify(receiver, never()).receive(MESSAGE, ENDPOINT_ID); - } -} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ClientServerEventService.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ClientServerEventService.java index 2e16c169704..a9419ec455c 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ClientServerEventService.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ClientServerEventService.java @@ -10,14 +10,11 @@ *******************************************************************************/ package org.eclipse.che.ide.api.event.ng; -import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; import org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto; -import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestTransmitter; +import org.eclipse.che.ide.jsonrpc.RequestTransmitter; import org.eclipse.che.ide.util.loging.Log; import javax.inject.Inject; @@ -28,13 +25,11 @@ */ @Singleton public class ClientServerEventService { - private final JsonRpcRequestTransmitter transmitter; - private final DtoFactory dtoFactory; + private final RequestTransmitter transmitter; + private final DtoFactory dtoFactory; @Inject - public ClientServerEventService(final JsonRpcRequestTransmitter transmitter, - final EventBus eventBus, - final DtoFactory dtoFactory) { + public ClientServerEventService(RequestTransmitter transmitter, EventBus eventBus, DtoFactory dtoFactory) { this.transmitter = transmitter; this.dtoFactory = dtoFactory; @@ -52,17 +47,13 @@ public void onEvent(FileTrackingEvent event) { } private void transmit(String path, String oldPath, FileTrackingOperationDto.Type type) { - final String params = dtoFactory.createDto(FileTrackingOperationDto.class) - .withPath(path) - .withType(type) - .withOldPath(oldPath) - .toString(); - - final JsonRpcRequest request = dtoFactory.createDto(JsonRpcRequest.class) - .withJsonrpc("2.0") - .withMethod("track:editor-file") - .withParams(params); - - transmitter.transmit(request); + final String endpointId = "ws-agent"; + final String method = "track:editor-file"; + final FileTrackingOperationDto dto = dtoFactory.createDto(FileTrackingOperationDto.class) + .withPath(path) + .withType(type) + .withOldPath(oldPath); + + transmitter.transmitNotification(endpointId, method, dto); } } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationReceiver.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationHandler.java similarity index 74% rename from ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationReceiver.java rename to ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationHandler.java index 46a74494ba6..35dbb18371e 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationReceiver.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationHandler.java @@ -13,15 +13,13 @@ import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType; import org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.event.FileContentUpdateEvent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.ExternalResourceDelta; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; +import org.eclipse.che.ide.jsonrpc.RequestHandler; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.util.loging.Log; @@ -41,8 +39,8 @@ * @author Dmitry Kuleshov */ @Singleton -public class EditorFileStatusNotificationReceiver implements JsonRpcRequestReceiver { - private final DtoFactory dtoFactory; +public class EditorFileStatusNotificationHandler extends RequestHandler { + private final EventBus eventBus; private final DeletedFilesController deletedFilesController; private final AppContext appContext; @@ -50,11 +48,10 @@ public class EditorFileStatusNotificationReceiver implements JsonRpcRequestRecei private NotificationManager notificationManager; @Inject - public EditorFileStatusNotificationReceiver(DtoFactory dtoFactory, - EventBus eventBus, - DeletedFilesController deletedFilesController, - AppContext appContext) { - this.dtoFactory = dtoFactory; + public EditorFileStatusNotificationHandler(EventBus eventBus, + DeletedFilesController deletedFilesController, + AppContext appContext) { + super(VfsFileStatusUpdateDto.class, Void.class); this.eventBus = eventBus; this.deletedFilesController = deletedFilesController; this.appContext = appContext; @@ -66,19 +63,16 @@ public void inject(NotificationManager notificationManager) { } @Override - public void receive(JsonRpcRequest request) { - final String params = request.getParams(); - final VfsFileStatusUpdateDto vfsFileStatusUpdateDto = dtoFactory.createDtoFromJson(params, VfsFileStatusUpdateDto.class); - - final FileWatcherEventType status = vfsFileStatusUpdateDto.getType(); - final String stringPath = vfsFileStatusUpdateDto.getPath(); + public void handleNotification(String endpointId, VfsFileStatusUpdateDto params) { + final FileWatcherEventType status = params.getType(); + final String stringPath = params.getPath(); final String name = stringPath.substring(stringPath.lastIndexOf("/") + 1); switch (status) { case MODIFIED: { Log.debug(getClass(), "Received updated file event status: " + stringPath); - eventBus.fireEvent(new FileContentUpdateEvent(stringPath, vfsFileStatusUpdateDto.getHashCode())); + eventBus.fireEvent(new FileContentUpdateEvent(stringPath, params.getHashCode())); break; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/JsonRpcWebSocketAgentEventListener.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/JsonRpcWebSocketAgentEventListener.java index 7149b5fe199..da7ebeb4b8f 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/JsonRpcWebSocketAgentEventListener.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/JsonRpcWebSocketAgentEventListener.java @@ -19,7 +19,7 @@ import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; -import org.eclipse.che.ide.jsonrpc.impl.JsonRpcInitializer; +import org.eclipse.che.ide.jsonrpc.JsonRpcInitializer; import org.eclipse.che.ide.util.loging.Log; import javax.inject.Singleton; @@ -61,17 +61,18 @@ public void run() { } private void internalInitialize() { - final DevMachine devMachine = appContext.getDevMachine(); - final String wsAgentWebSocketUrl = devMachine.getWsAgentWebSocketUrl(); - final String url = wsAgentWebSocketUrl.replaceFirst("(api)(/)(ws)", "websocket" + "$2" + ENDPOINT_ID); + DevMachine devMachine = appContext.getDevMachine(); + String wsAgentWebSocketUrl = devMachine.getWsAgentWebSocketUrl(); - initializer.initialize(singletonMap("url", url)); + String wsAgentUrl = wsAgentWebSocketUrl.replaceFirst("(api)(/)(ws)", "websocket" + "$2" + ENDPOINT_ID); + + initializer.initialize("ws-agent", singletonMap("url", wsAgentUrl)); } @Override public void onWsAgentStopped(WsAgentStateEvent event) { Log.debug(JsonRpcWebSocketAgentEventListener.class, "Web socket agent stopped event caught."); - initializer.terminate(); + initializer.terminate("ws-agent"); } } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ProjectTreeStatusNotificationReceiver.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ProjectTreeStatusNotificationHandler.java similarity index 75% rename from ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ProjectTreeStatusNotificationReceiver.java rename to ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ProjectTreeStatusNotificationHandler.java index 9f56771f8ff..2cfc477454a 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ProjectTreeStatusNotificationReceiver.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/ng/ProjectTreeStatusNotificationHandler.java @@ -11,20 +11,17 @@ package org.eclipse.che.ide.api.event.ng; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType; import org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.ExternalResourceDelta; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; +import org.eclipse.che.ide.jsonrpc.RequestHandler; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.util.loging.Log; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.Objects; import static org.eclipse.che.ide.api.resources.ResourceDelta.ADDED; import static org.eclipse.che.ide.api.resources.ResourceDelta.REMOVED; @@ -38,23 +35,20 @@ * @author Dmitry Kuleshov */ @Singleton -public class ProjectTreeStatusNotificationReceiver implements JsonRpcRequestReceiver { - private final DtoFactory dtoFactory; +public class ProjectTreeStatusNotificationHandler extends RequestHandler { private final AppContext appContext; @Inject - public ProjectTreeStatusNotificationReceiver(DtoFactory dtoFactory, AppContext appContext) { - this.dtoFactory = dtoFactory; + public ProjectTreeStatusNotificationHandler(AppContext appContext) { + super(ProjectTreeStatusUpdateDto.class, Void.class); this.appContext = appContext; } - @Override - public void receive(JsonRpcRequest request) { - final String params = request.getParams(); - final ProjectTreeStatusUpdateDto vfsFileStatusUpdateDto = dtoFactory.createDtoFromJson(params, ProjectTreeStatusUpdateDto.class); - final String path = vfsFileStatusUpdateDto.getPath(); - final FileWatcherEventType type = vfsFileStatusUpdateDto.getType(); + @Override + public void handleNotification(String endpointId, ProjectTreeStatusUpdateDto params) { + final String path = params.getPath(); + final FileWatcherEventType type = params.getType(); final int status; diff --git a/ide/che-core-ide-api/src/test/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationReceiverTest.java b/ide/che-core-ide-api/src/test/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationReceiverTest.java deleted file mode 100644 index 460ed51667d..00000000000 --- a/ide/che-core-ide-api/src/test/java/org/eclipse/che/ide/api/event/ng/EditorFileStatusNotificationReceiverTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.api.event.ng; - -import com.google.web.bindery.event.shared.EventBus; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto; -import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.event.FileContentUpdateEvent; -import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.api.resources.Container; -import org.eclipse.che.ide.dto.DtoFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.DELETED; -import static org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType.MODIFIED; -import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.EMERGE_MODE; -import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link EditorFileStatusNotificationReceiver} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class EditorFileStatusNotificationReceiverTest { - private static final String FILE_PATH = "/folder/file"; - - @Mock - private DtoFactory dtoFactory; - @Mock - private EventBus eventBus; - @Mock - private DeletedFilesController deletedFilesController; - @Mock - private AppContext appContext; - @InjectMocks - private EditorFileStatusNotificationReceiver receiver; - - @Mock - private NotificationManager notificationManager; - - @Mock - private VfsFileStatusUpdateDto dto; - @Mock - private JsonRpcRequest request; - @Mock - private Container container; - - @Before - public void setUp() throws Exception { - receiver.inject(notificationManager); - - when(dtoFactory.createDtoFromJson(any(), eq(VfsFileStatusUpdateDto.class))).thenReturn(dto); - - when(dto.getPath()).thenReturn(FILE_PATH); - when(dto.getType()).thenReturn(MODIFIED); - - when(appContext.getWorkspaceRoot()).thenReturn(container); - } - - @After - public void tearDown() throws Exception { - - } - - @Test - public void shouldRunDtoFactory() { - receiver.receive(request); - - verify(dtoFactory).createDtoFromJson(any(), eq(VfsFileStatusUpdateDto.class)); - } - - @Test - public void shouldNotifyAboutUpdate() { - when(dto.getType()).thenReturn(MODIFIED); - - receiver.receive(request); - - ArgumentCaptor captor = ArgumentCaptor.forClass(FileContentUpdateEvent.class); - - verify(eventBus).fireEvent(captor.capture()); - assertEquals(captor.getValue().getFilePath(), FILE_PATH); - - verify(appContext, never()).getWorkspaceRoot(); - verify(container, never()).synchronize(any()); - } - - @Test - public void shouldNotifyAboutRemove() { - when(dto.getType()).thenReturn(DELETED); - - receiver.receive(request); - - verify(eventBus, never()).fireEvent(any()); - - verify(appContext).getWorkspaceRoot(); - verify(container).synchronize(any()); - - verify(deletedFilesController).remove(anyString()); - verify(notificationManager).notify(eq("External operation"), eq("File '" + "file" + "' is removed"), eq(SUCCESS), eq(EMERGE_MODE)); - } - - @Test - public void shouldNotNotifyAboutRemove() { - when(dto.getType()).thenReturn(DELETED); - when(deletedFilesController.remove(anyString())).thenReturn(true); - - - receiver.receive(request); - - verify(eventBus, never()).fireEvent(any()); - - verify(appContext).getWorkspaceRoot(); - verify(container).synchronize(any()); - - verify(deletedFilesController).remove(anyString()); - verify(notificationManager, never()).notify(eq("External operation"), eq("File '" + "file" + "' is removed"), eq(SUCCESS), eq(EMERGE_MODE)); - } -} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/ClientServerEventModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/ClientServerEventModule.java index ce1f13222e6..52cadf3bbcd 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/ClientServerEventModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/ClientServerEventModule.java @@ -14,10 +14,10 @@ import com.google.gwt.inject.client.multibindings.GinMapBinder; import org.eclipse.che.ide.api.event.ng.ClientServerEventService; -import org.eclipse.che.ide.api.event.ng.EditorFileStatusNotificationReceiver; +import org.eclipse.che.ide.api.event.ng.EditorFileStatusNotificationHandler; import org.eclipse.che.ide.api.event.ng.FileOpenCloseEventListener; -import org.eclipse.che.ide.api.event.ng.ProjectTreeStatusNotificationReceiver; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; +import org.eclipse.che.ide.api.event.ng.ProjectTreeStatusNotificationHandler; +import org.eclipse.che.ide.jsonrpc.RequestHandler; /** * GIN module for configuring client server events. @@ -31,10 +31,12 @@ protected void configure() { bind(FileOpenCloseEventListener.class).asEagerSingleton(); bind(ClientServerEventService.class).asEagerSingleton(); - GinMapBinder requestReceivers = - GinMapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class); + GinMapBinder.newMapBinder(binder(), String.class, RequestHandler.class) + .addBinding("event:file-in-vfs-status-changed") + .to(EditorFileStatusNotificationHandler.class); - requestReceivers.addBinding("event:file-in-vfs-status-changed").to(EditorFileStatusNotificationReceiver.class); - requestReceivers.addBinding("event:project-tree-status-changed").to(ProjectTreeStatusNotificationReceiver.class); + GinMapBinder.newMapBinder(binder(), String.class, RequestHandler.class) + .addBinding("event:project-tree-status-changed") + .to(ProjectTreeStatusNotificationHandler.class); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java index be1f136fe71..bace8e44d7f 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java @@ -39,21 +39,20 @@ import org.eclipse.che.ide.api.ssh.SshServiceClient; import org.eclipse.che.ide.api.ssh.SshServiceClientImpl; import org.eclipse.che.ide.clipboard.ClipboardModule; -import org.eclipse.che.ide.context.AppContextImpl; import org.eclipse.che.ide.command.CommandApiModule; -import org.eclipse.che.ide.macro.MacroApiModule; -import org.eclipse.che.ide.project.ProjectApiModule; -import org.eclipse.che.ide.workspace.WorkspaceApiModule; +import org.eclipse.che.ide.context.AppContextImpl; import org.eclipse.che.ide.debug.DebugApiModule; import org.eclipse.che.ide.editor.EditorApiModule; import org.eclipse.che.ide.editor.preferences.EditorPreferencesModule; import org.eclipse.che.ide.factory.FactoryApiModule; import org.eclipse.che.ide.filetypes.FileTypeApiModule; import org.eclipse.che.ide.keybinding.KeyBindingManager; +import org.eclipse.che.ide.macro.MacroApiModule; import org.eclipse.che.ide.notification.NotificationApiModule; import org.eclipse.che.ide.oauth.OAuthApiModule; import org.eclipse.che.ide.part.PartApiModule; import org.eclipse.che.ide.preferences.PreferencesApiModule; +import org.eclipse.che.ide.project.ProjectApiModule; import org.eclipse.che.ide.projectimport.ProjectImportModule; import org.eclipse.che.ide.resources.ResourceApiModule; import org.eclipse.che.ide.rest.RestContext; @@ -65,6 +64,7 @@ import org.eclipse.che.ide.ui.loaders.PopupLoaderFactory; import org.eclipse.che.ide.ui.loaders.request.LoaderFactory; import org.eclipse.che.ide.user.UserApiModule; +import org.eclipse.che.ide.workspace.WorkspaceApiModule; import org.eclipse.che.ide.workspace.WorkspacePresenter; import org.eclipse.che.providers.DynaProvider; import org.eclipse.che.providers.DynaProviderImpl; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/JsonRpcModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/JsonRpcModule.java index 7ea37ddaf61..8127fc57d34 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/JsonRpcModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/JsonRpcModule.java @@ -14,19 +14,11 @@ import com.google.gwt.inject.client.multibindings.GinMapBinder; import org.eclipse.che.ide.api.event.ng.JsonRpcWebSocketAgentEventListener; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestTransmitter; -import org.eclipse.che.ide.jsonrpc.JsonRpcResponseReceiver; -import org.eclipse.che.ide.jsonrpc.JsonRpcResponseTransmitter; -import org.eclipse.che.ide.jsonrpc.impl.BasicJsonRpcObjectValidator; -import org.eclipse.che.ide.jsonrpc.impl.JsonRpcDispatcher; -import org.eclipse.che.ide.jsonrpc.impl.JsonRpcInitializer; -import org.eclipse.che.ide.jsonrpc.impl.JsonRpcObjectValidator; +import org.eclipse.che.ide.jsonrpc.JsonRpcInitializer; +import org.eclipse.che.ide.jsonrpc.RequestHandler; +import org.eclipse.che.ide.jsonrpc.RequestTransmitter; import org.eclipse.che.ide.jsonrpc.impl.WebSocketJsonRpcInitializer; -import org.eclipse.che.ide.jsonrpc.impl.WebSocketJsonRpcRequestDispatcher; -import org.eclipse.che.ide.jsonrpc.impl.WebSocketJsonRpcRequestTransmitter; -import org.eclipse.che.ide.jsonrpc.impl.WebSocketJsonRpcResponseDispatcher; -import org.eclipse.che.ide.jsonrpc.impl.WebSocketJsonRpcResponseTransmitter; +import org.eclipse.che.ide.jsonrpc.impl.WebSocketTransmitter; /** * GIN module for configuring Json RPC protocol implementation components. @@ -38,22 +30,9 @@ public class JsonRpcModule extends AbstractGinModule { @Override protected void configure() { bind(JsonRpcWebSocketAgentEventListener.class).asEagerSingleton(); - bind(JsonRpcInitializer.class).to(WebSocketJsonRpcInitializer.class); + bind(RequestTransmitter.class).to(WebSocketTransmitter.class); - bind(JsonRpcRequestTransmitter.class).to(WebSocketJsonRpcRequestTransmitter.class); - bind(JsonRpcResponseTransmitter.class).to(WebSocketJsonRpcResponseTransmitter.class); - - bind(JsonRpcObjectValidator.class).to(BasicJsonRpcObjectValidator.class); - - GinMapBinder dispatchers = GinMapBinder.newMapBinder(binder(), String.class, JsonRpcDispatcher.class); - dispatchers.addBinding("request").to(WebSocketJsonRpcRequestDispatcher.class); - dispatchers.addBinding("response").to(WebSocketJsonRpcResponseDispatcher.class); - - GinMapBinder requestReceivers = - GinMapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class); - - GinMapBinder responseReceivers = - GinMapBinder.newMapBinder(binder(), String.class, JsonRpcResponseReceiver.class); + GinMapBinder.newMapBinder(binder(), String.class, RequestHandler.class); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/WebSocketModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/WebSocketModule.java index b6829b1a1fc..c63a65f3d3f 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/WebSocketModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/WebSocketModule.java @@ -12,21 +12,16 @@ import com.google.gwt.inject.client.AbstractGinModule; import com.google.gwt.inject.client.assistedinject.GinFactoryModuleBuilder; -import com.google.gwt.inject.client.multibindings.GinMapBinder; -import org.eclipse.che.ide.jsonrpc.impl.WebSocketJsonRpcDispatcher; +import org.eclipse.che.ide.jsonrpc.impl.WebSocketToJsonRpcDispatcher; import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; import org.eclipse.che.ide.websocket.ng.WebSocketMessageTransmitter; import org.eclipse.che.ide.websocket.ng.impl.BasicWebSocketEndpoint; import org.eclipse.che.ide.websocket.ng.impl.BasicWebSocketMessageTransmitter; -import org.eclipse.che.ide.websocket.ng.impl.BasicWebSocketTransmissionValidator; -import org.eclipse.che.ide.websocket.ng.impl.DelayableWebSocket; -import org.eclipse.che.ide.websocket.ng.impl.SessionWebSocketInitializer; -import org.eclipse.che.ide.websocket.ng.impl.WebSocket; -import org.eclipse.che.ide.websocket.ng.impl.WebSocketCreator; +import org.eclipse.che.ide.websocket.ng.impl.DelayableWebSocketConnection; +import org.eclipse.che.ide.websocket.ng.impl.WebSocketConnection; import org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint; -import org.eclipse.che.ide.websocket.ng.impl.WebSocketInitializer; -import org.eclipse.che.ide.websocket.ng.impl.WebSocketTransmissionValidator; +import org.eclipse.che.ide.websocket.ng.impl.WebSocketFactory; /** * GIN module for configuring WebSocket components. @@ -37,21 +32,11 @@ public class WebSocketModule extends AbstractGinModule { @Override protected void configure() { - bind(WebSocketInitializer.class).to(SessionWebSocketInitializer.class); - bind(WebSocketEndpoint.class).to(BasicWebSocketEndpoint.class); - - bind(WebSocketTransmissionValidator.class).to(BasicWebSocketTransmissionValidator.class); - bind(WebSocketMessageTransmitter.class).to(BasicWebSocketMessageTransmitter.class); + bind(WebSocketMessageReceiver.class).to(WebSocketToJsonRpcDispatcher.class); - install(new GinFactoryModuleBuilder() - .implement(WebSocket.class, DelayableWebSocket.class) - .build(WebSocketCreator.class)); - - GinMapBinder receivers = - GinMapBinder.newMapBinder(binder(), String.class, WebSocketMessageReceiver.class); - - receivers.addBinding("jsonrpc-2.0").to(WebSocketJsonRpcDispatcher.class); + install(new GinFactoryModuleBuilder().implement(WebSocketConnection.class, DelayableWebSocketConnection.class) + .build(WebSocketFactory.class)); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java index feb76dff153..7ef78ee57ec 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java @@ -17,7 +17,7 @@ import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.ide.Resources; -import org.eclipse.che.ide.api.event.ng.EditorFileStatusNotificationReceiver; +import org.eclipse.che.ide.api.event.ng.EditorFileStatusNotificationHandler; import org.eclipse.che.ide.api.mvp.View; import org.eclipse.che.ide.api.notification.Notification; import org.eclipse.che.ide.api.notification.NotificationListener; @@ -100,8 +100,8 @@ public NotificationManagerImpl(NotificationManagerView view, @Inject @PostConstruct - public void inject(EditorFileStatusNotificationReceiver editorFileStatusNotificationReceiver) { - editorFileStatusNotificationReceiver.inject(this); + public void inject(EditorFileStatusNotificationHandler editorFileStatusNotificationHandler) { + editorFileStatusNotificationHandler.inject(this); } /** {@inheritDoc} */ diff --git a/ide/commons-gwt/pom.xml b/ide/commons-gwt/pom.xml index c26d92db923..c5f0d6178b5 100644 --- a/ide/commons-gwt/pom.xml +++ b/ide/commons-gwt/pom.xml @@ -33,10 +33,6 @@ com.google.gwt gwt-elemental - - org.eclipse.che.core - che-core-api-core - org.eclipse.che.core che-core-commons-annotations diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcInitializer.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcInitializer.java new file mode 100644 index 00000000000..56642326dee --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcInitializer.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc; + +import javax.inject.Singleton; +import java.util.Map; + +/** + * Performs all needed preparations to initialize and terminate the json rpc + * service. + * + * @author Dmitry Kuleshov + */ +@Singleton +public interface JsonRpcInitializer { + /** + * Initialize json rpc service for an endpoint defined by a high level + * identifier with implementation defined properties. + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param properties + * map of implementation dependent properties (e.g. URL, etc.) + */ + void initialize(String endpointId, Map properties); + + /** + * Terminate json rpc service defined by high level identifier + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + */ + void terminate(String endpointId); +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestReceiver.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestReceiver.java deleted file mode 100644 index fdf0c8a84da..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestReceiver.java +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc; - - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; - -/** - * The implementation of this interface receives JSON RPC requests according to - * the mapping. The mapping is defined via MapBinder in one of Gin modules that - * are used in the application. Example is simple: - * - *
- *     
- *         GinMapBinder requestReceivers =
- *         GinMapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class);
- *         requestReceivers.addBinding("method-name").to(CustomJsonRpcRequestReceiver.class)
- *     
- * 
- * - * All JSON RPC requests that has their method names equal to "method-name" will be - * processed by instance of CustomJsonRpcRequestReceiver. Please note - * that you can use regular expressions for method names in order to be able to map - * single receiver implementation to a several kinds of requests. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcRequestReceiver { - /** - * Receives a JSON RPC request - * - * @param request request instance - */ - void receive(JsonRpcRequest request); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestTransmitter.java deleted file mode 100644 index c07c51ec907..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcRequestTransmitter.java +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc; - - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; - -/** - * Transmits a JSON RPC request. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcRequestTransmitter { - /** - * Transmits a JSON RPC request. - * - * @param request JSON RPC request instance - */ - void transmit(JsonRpcRequest request); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseReceiver.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseReceiver.java deleted file mode 100644 index 0e0d1fd9311..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseReceiver.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; - -/** - * The implementation of this interface receives JSON RPC responses according to - * the mapping. The mapping is defined via MapBinder in one of Gin modules that - * are used in the application. Example is simple: - * - *
- *     
- *         GinMapBinder responseReceivers =
- *         GinMapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class);
- *         responseReceivers.addBinding("method-name").to(CustomJsonRpcResponseReceiver.class)
- *     
- * 
- * - * In fact JSON RPC responses has no method defined in their body, though it is quite - * possible to bind requests and responses by their identifiers thus we can know which - * response correspond to which method. So responses that has their method names equal - * to "method-name" will be processed by instance of CustomJsonRpcResponseReceiver. - * Please note that you can use regular expressions for method names in order to be able - * to map single receiver implementation to a several kinds of requests. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcResponseReceiver { - /** - * Receive JSON RPC response - * - * @param response response instance - */ - void receive(JsonRpcResponse response); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseTransmitter.java deleted file mode 100644 index 530da5ab97c..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/JsonRpcResponseTransmitter.java +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc; - - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; - -/** - * Transmits a JSON RPC response to an endpoint or broadcast it. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcResponseTransmitter { - /** - * Transmits a JSON RPC response - * - * @param response JSON RPC response instance - */ - void transmit(JsonRpcResponse response); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestHandler.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestHandler.java new file mode 100644 index 00000000000..20e632b642b --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestHandler.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc; + + +/** + * Request handlers are the key elements of json rpc request processing + * routines. You must extend this class if you want to handle a request to a + * specific method. In order to apply this handler you must register it inside + * dependency injection infrastructure (e.g. gin) The example: + *

+ * GinMapBinder.newMapBinder(binder(), String.class, RequestHandler.class) + * .addBinding("process_died") + * .to(ProcessDiedEventHandler.class); + *

+ * where + *
    + *
  • + * process_died: corresponding method + *
  • + *
  • + * ProcessDiedEventHandler: concrete implementation of request + * handler + *
  • + *
+ * Obvious limitation there can be only one handler for a combination of + * endpoint and method. + *

+ * Class has two generic parameters - P and R which + * corresponds to parameters DTO type and result DTO type. If handler is + * designed to process request without parameters you must specify that fact + * explicitly by defining a P parameter as {@link Void}. On the + * other hand handler can process a notification that means that it is not + * planned to send back a response in this situation you must similary define + * R as {@link Void}. + *

+ *

+ * All handling methods are throwing an {@link UnsupportedOperationException} + * so you must override method that mostly correspond the type of you handler. + * For example, if you are going to handle a notification without parameters + * you must override {@link RequestHandler#handleNotification(String)} method, while + * the implementation will independently (analyzing the request) define which + * handler and which method to call. + *

+ * + * @author Dmitry Kuleshov + */ +public abstract class RequestHandler { + private final Class

paramsClass; + private final Class resultClass; + + protected RequestHandler(Class

paramsClass, Class resultClass) { + this.paramsClass = paramsClass; + this.resultClass = resultClass; + } + + final public Class

getParamsClass() { + return paramsClass; + } + + final public Class getResultClass() { + return resultClass; + } + + /** + * Handle a notification without parameters + * + * @param endpointId + * endpoint identifier + */ + public void handleNotification(String endpointId) { + throw new UnsupportedOperationException(); + } + + /** + * Handle a notification with parameters + * + * @param endpointId + * endpoint identifier + * @param params + * parameters represented by DTO + */ + public void handleNotification(String endpointId, P params) { + throw new UnsupportedOperationException(); + } + + /** + * Handle a request without parameters + * + * @param endpointId + * endpoint identifier + * + * @return result of handling of a request + */ + public R handleRequest(String endpointId) { + throw new UnsupportedOperationException(); + } + + /** + * Handle a request with parameters + * + * @param endpointId + * endpoint identifier + * @param params + * parameters represented by DTO + * + * @return result of handling of a request + */ + public R handleRequest(String endpointId, P params) { + throw new UnsupportedOperationException(); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestTransmitter.java new file mode 100644 index 00000000000..03596d7d2a4 --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/RequestTransmitter.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc; + + +import org.eclipse.che.api.promises.client.Promise; + +import java.util.List; + +/** + * Transmits requests to a defined endpoint over json rpc 2.0. protocol. Single + * instance of transmitter is used for all registered endpoints. As json rpc is + * a transport agnostic protocol the way the transmission goes is defined by + * inner implementation. + * + * @author Dmitry Kuleshov + */ +public interface RequestTransmitter { + /** + * Transmit a notification that has no parameters to an endpoint + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + */ + void transmitNotification(String endpointId, String method); + + /** + * Transmit a notification that has parameters to an endpoint + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param params + * dto representing parameters + */ + void transmitNotification(String endpointId, String method, Object params); + + /** + * Transmit a request that has no parameters + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param resultClass + * class of response result section represented by DTO + * + * @return promise that contains response result represented by DTO + */ + Promise transmitRequest(String endpointId, String method, Class resultClass); + + /** + * Transmit a request that has parameters + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param params + * parameters represented by DTO + * @param resultClass + * class of response result section represented by DTO + * + * @return promise that contains response result represented by DTO + */ + Promise transmitRequest(String endpointId, String method, Object params, Class resultClass); + + /** + * Transmit a request that has no parameters and the result is a list of + * objects represented by a corresponding DTO class. + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param resultClass + * class of response result section represented by DTO + * + * @return promise that contains response result represented by DTO + */ + Promise> transmitRequestForList(String endpointId, String method, Class resultClass); + + /** + * Transmit a request that has parameters and the result is a list of + * objects represented by a corresponding DTO class. + * + * @param endpointId + * high level endpoint identifier (e.g. "exec-agent") + * @param method + * method name as defined in json rpc 2.0 specification + * @param params + * parameters represented by DTO + * @param resultClass + * class of response result section represented by DTO + * + * @return promise that contains response result represented by DTO + */ + Promise> transmitRequestForList(String endpointId, String method, Object params, Class resultClass); +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/AbstractJsonRpcDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/AbstractJsonRpcDispatcher.java new file mode 100644 index 00000000000..d3c06a09eca --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/AbstractJsonRpcDispatcher.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc.impl; + +import com.google.gwt.json.client.JSONObject; + +import org.eclipse.che.ide.jsonrpc.RequestHandler; +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Inject; +import java.util.Map; + +/** + * @author Dmitry Kuleshov + */ +public abstract class AbstractJsonRpcDispatcher { + private final Map handlers; + + @Inject + public AbstractJsonRpcDispatcher(Map handlers) { + this.handlers = handlers; + } + + RequestHandler getRequestHandler(String endpointId, String method) { + if (handlers.containsKey(method)) { + return handlers.get(method); + } + + final String error = "No handler registered for method: " + method + ", and endpoint: " + endpointId; + Log.error(getClass(), error); + throw new IllegalStateException(error); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidator.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidator.java deleted file mode 100644 index 60626bad7e4..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidator.java +++ /dev/null @@ -1,103 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import com.google.gwt.json.client.JSONParser; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Set; - -/** - * Basic implementation of JSON RPC object validator. Validation rules are simple: - * - *

    - *
  • type must not be null
  • - *
  • type must not be empty
  • - *
  • type must be registered (mapped to a corresponding receiver implementation)
  • - *
  • message must not be null
  • - *
  • message must not be empty
  • - *
  • message must be a valid JSON
  • - *
- * - * @author Dmitry Kuleshov - */ -@Singleton -public class BasicJsonRpcObjectValidator implements JsonRpcObjectValidator { - private final Set registeredTypes; - - @Inject - public BasicJsonRpcObjectValidator(Map dispatchers) { - this.registeredTypes = dispatchers.keySet(); - } - - - @Override - public void validate(JsonRpcObject object) { - validateType(object.getType()); - validateMessage(object.getMessage()); - } - - private void validateType(String type) { - if (registeredTypes.contains(type)) { - Log.debug(getClass(), "Json rpc object type {} is among registered", type); - } else { - logError("Json rpc object is of not registered type"); - } - } - - private void validateMessage(String message) { - validateNull(message); - validateEmpty(message); - validateJson(message); - } - - private void validateNull(String message) { - if (message == null) { - logError("Json rpc object message is null"); - } else { - Log.debug(getClass(), "Json rpc object message is not null"); - } - } - - private void validateEmpty(String message) { - if (message.isEmpty()) { - logError("Json rpc object message is empty"); - } else { - Log.debug(getClass(), "Json rpc object message is not empty"); - } - } - - private void validateJson(String message) { - boolean error = false; - - try { - JSONParser.parseStrict(message); - } catch (Throwable e) { - error = true; - } - - if (error) { - logError("Json rpc object message is not a valid json"); - } else { - Log.debug(getClass(), "Json rpc object message is a valid json"); - } - } - - private void logError(String error) { - Log.error(getClass(), error); - throw new IllegalArgumentException(error); - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcDispatcher.java deleted file mode 100644 index ded1472031c..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcDispatcher.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; - -/** - * There are two implementations of this interface: - * - *
    - *
  • {@link WebSocketJsonRpcRequestDispatcher}
  • - *
  • {@link WebSocketJsonRpcResponseDispatcher}
  • - *
- * - * Each implementation is used to dispatch messages of {@link JsonRpcObject} - * of corresponding type: requests or response. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcDispatcher { - /** - * Dispatches a message - * - * @param message - * message - */ - void dispatch(String message); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcInitializer.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcInitializer.java deleted file mode 100644 index 9a0c895877d..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcInitializer.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import javax.inject.Singleton; -import java.util.Map; - -/** - * Initializes and terminates JSON RPC services. - * - * @author Dmitry Kuleshov - */ -@Singleton -public interface JsonRpcInitializer { - /** - * Initialize JSON RPC services with properties contained - * in a map as simple key->value pairs. - * - * @param properties properties map - */ - void initialize(Map properties); - - /** - * Terminates JSON RPC services - */ - void terminate(); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcObjectValidator.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcObjectValidator.java deleted file mode 100644 index bb8bd40c287..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcObjectValidator.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; - -import javax.inject.Singleton; - -/** - * It is used to make sure that {@link JsonRpcObject} is a valid entity. - * Implementation of this interface must be called before any other operation - * is performed to avoid any kind of inconsistency. - * - * @author Dmitry Kuleshov - */ -public interface JsonRpcObjectValidator { - void validate(JsonRpcObject object); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistry.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistry.java deleted file mode 100644 index f16f2c1f6c2..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistry.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Singleton; -import java.util.HashMap; -import java.util.Map; - -/** - * Binds request identifiers with request methods. Registry is used by response receivers - * to find out what method call is being answered. This is mostly needed because JSON RPC - * specification does not define method section in JSON RPC responses so there is no method - * name that can be directly mapped to a corresponding receiver. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class JsonRpcRequestRegistry { - private final Map requests = new HashMap<>(); - - /** - * Add request identifier - request method binding to the registry. - * - * @param id request identifier - * @param method request method - */ - public void add(Integer id, String method) { - Log.debug(getClass(), "Binding ID: ", id, " to method: ", method); - - requests.put(id, method); - } - - /** - * Extracts request method name bound to request identifier - * - * @param id request identifier - * - * @return request method name - */ - public String extractFor(Integer id) { - Log.debug(getClass(), "Extracting method with ID: ", id); - - return requests.remove(id); - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/NotificationDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/NotificationDispatcher.java new file mode 100644 index 00000000000..05512b2b827 --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/NotificationDispatcher.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc.impl; + +import com.google.gwt.json.client.JSONObject; + +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.jsonrpc.RequestHandler; +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Map; + +/** + * Dispatches incoming json rpc notification + * + * @author Dmitry Kuleshov + */ +@Singleton +public class NotificationDispatcher extends AbstractJsonRpcDispatcher { + private final DtoFactory dtoFactory; + + @Inject + public NotificationDispatcher(Map handlers, DtoFactory dtoFactory) { + super(handlers); + this.dtoFactory = dtoFactory; + } + + /** + * Dispatches json rpc notification received from endpoint identified by a + * high level identifier and represented as a json object. + * + * @param endpointId + * high level endpoint identifier + * @param incomingJson + * json object + */ + public void dispatch(String endpointId, JSONObject incomingJson) { + Log.debug(getClass(), "Dispatching a notification from endpoint: " + endpointId + ", json: " + incomingJson); + + final String method = incomingJson.get("method").isString().stringValue(); + Log.debug(getClass(), "Extracted notification method: " + method); + + final RequestHandler handler = getRequestHandler(endpointId, method); + + if (incomingJson.containsKey("params")) { + final JSONObject params = incomingJson.get("params").isObject(); + Log.debug(getClass(), "Notification is parametrized, processing parameters: " + params); + + final Class paramsClass = handler.getParamsClass(); + Log.debug(getClass(), "Extracted notification params class: " + paramsClass); + + dispatch(endpointId, handler, params, paramsClass); + } else { + dispatch(endpointId, handler); + } + + } + + private

void dispatch(String endpointId, RequestHandler handler, JSONObject params, Class

paramsClass) { + final P param = dtoFactory.createDtoFromJson(params.toString(), paramsClass); + handler.handleNotification(endpointId, param); + } + + private void dispatch(String endpointId, RequestHandler handler) { + handler.handleNotification(endpointId); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/RequestDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/RequestDispatcher.java new file mode 100644 index 00000000000..b6090d879fb --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/RequestDispatcher.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc.impl; + +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONParser; +import com.google.gwt.json.client.JSONString; + +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.jsonrpc.RequestHandler; +import org.eclipse.che.ide.util.loging.Log; +import org.eclipse.che.ide.websocket.ng.WebSocketMessageTransmitter; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Map; + +/** + * Dispatches incoming json rpc requests + * + * @author Dmitry Kuleshov + */ +@Singleton +public class RequestDispatcher extends AbstractJsonRpcDispatcher { + private final WebSocketMessageTransmitter transmitter; + private final DtoFactory dtoFactory; + + @Inject + public RequestDispatcher(Map handlers, WebSocketMessageTransmitter transmitter, DtoFactory dtoFactory) { + super(handlers); + this.transmitter = transmitter; + this.dtoFactory = dtoFactory; + } + + /** + * Dispatches json rpc request received from endpoint identified by a high + * level identifier and represented as a json object. + * + * @param endpointId + * high level endpoint identifier + * @param incomingJson + * json object + */ + public void dispatch(String endpointId, JSONObject incomingJson) { + Log.debug(getClass(), "Dispatching a request from endpoint: " + endpointId + ", jso: " + incomingJson); + + final String method = incomingJson.get("method").isString().stringValue(); + Log.debug(getClass(), "Extracted request method: " + method); + + final RequestHandler handler = getRequestHandler(endpointId, method); + + final String id = incomingJson.get("id").toString(); + Log.debug(getClass(), "Extracted request id: " + id); + + final Class resultClass = handler.getResultClass(); + Log.debug(getClass(), "Extracted request result class: " + resultClass); + + + JSONObject result; + if (incomingJson.containsKey("params")) { + final JSONObject params = incomingJson.get("params").isObject(); + Log.debug(getClass(), "Request is parametrized, processing parameters: " + params); + + final Class paramsClass = handler.getParamsClass(); + Log.debug(getClass(), "Extracted request params class: " + paramsClass); + + result = dispatch(endpointId, handler, params, paramsClass); + } else { + + Log.debug(getClass(), "Request is not parametrized"); + result = dispatch(endpointId, handler); + } + + final JSONObject response = prepareResponse(id, result); + Log.debug(getClass(), "Prepared a response: " + response); + + transmitter.transmit(endpointId, response.toString()); + } + + private JSONObject prepareResponse(String id, JSONObject result) { + final JSONObject response = new JSONObject(); + + response.put("jsonrpc", new JSONString("2.0")); + response.put("id", new JSONString(id)); + response.put("result", result); + + return response; + } + + private JSONObject dispatch(String endpointId, RequestHandler handler, JSONObject params, Class

paramClass) { + final P param = dtoFactory.createDtoFromJson(params.toString(), paramClass); + final R result = handler.handleRequest(endpointId, param); + + final String resultString = dtoFactory.toJson(result); + return JSONParser.parseStrict(resultString).isObject(); + } + + private JSONObject dispatch(String endpointId, RequestHandler handler) { + final R result = handler.handleRequest(endpointId); + + final String resultString = dtoFactory.toJson(result); + return JSONParser.parseStrict(resultString).isObject(); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/ResponseDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/ResponseDispatcher.java new file mode 100644 index 00000000000..0387120ad6b --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/ResponseDispatcher.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc.impl; + +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONString; +import com.google.gwt.json.client.JSONValue; + +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.api.promises.client.js.Executor; +import org.eclipse.che.api.promises.client.js.Promises; +import org.eclipse.che.api.promises.client.js.RejectFunction; +import org.eclipse.che.api.promises.client.js.ResolveFunction; +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Dispatches incoming json rpc responses + * + * @author Dmitry Kuleshov + */ +@Singleton +public class ResponseDispatcher { + private final Map promises = new HashMap<>(); + private final Map rejectFunctions = new HashMap<>(); + private final Map> resultClasses = new HashMap<>(); + + private final DtoFactory dtoFactory; + + @Inject + public ResponseDispatcher(DtoFactory dtoFactory) { + this.dtoFactory = dtoFactory; + } + + /** + * Dispatches json rpc response received from endpoint identified by a high + * level identifier and represented as a json object. + * + * @param endpointId + * high level endpoint identifier + * @param incomingJson + * json object + */ + public void dispatch(String endpointId, JSONObject incomingJson) { + Log.debug(getClass(), "Dispatching a response from: " + endpointId + ", json: " + incomingJson); + + final String id = getId(incomingJson); + Log.debug(getClass(), "Extracted response id: " + id); + + final String key = endpointId + '@' + id; + Log.debug(getClass(), "Combined response key: " + key); + + if (incomingJson.containsKey("result")) { + Log.debug(getClass(), "It's a response with result field, processing result"); + + final Class resultClass = resultClasses.get(key); + Log.debug(getClass(), "Extracted response result class: " + resultClass); + + processResult(endpointId, id, resultClass, incomingJson.get("result")); + } else { + Log.debug(getClass(), "It's a response with error field, processing error"); + + processError(endpointId, id, incomingJson.get("error")); + } + } + + /** + * Register and get a promise that will be resolved when specified response + * will be dispatched. + * + * @param endpointId + * high level endpoint identifier + * @param id + * request identifier + * @param resultClass + * class of request result that is contained within response + * + * @return promise with result dto + */ + public Promise getPromise(final String endpointId, final String id, final Class resultClass) { + Log.debug(getClass(), "Registering single promise for: " + endpointId + ", request id: " + id + "result class: " + resultClass); + + return Promises.create(new Executor.ExecutorBody() { + @Override + public void apply(ResolveFunction resolve, RejectFunction reject) { + promises.put(endpointId + '@' + id, resolve); + resultClasses.put(endpointId + '@' + id, resultClass); + rejectFunctions.put(endpointId + '@' + id, reject); + } + }); + } + + /** + * Register and get a promise that will be resolved when specified response + * will be dispatched. The response result is represented as list of objects + * that has a type defined in a corresponding parameter. + * + * @param endpointId + * high level endpoint identifier + * @param id + * request identifier + * @param resultClass + * class of request result that is contained within response + * + * @return promise with result dto + */ + public Promise> getListPromise(final String endpointId, final String id, final Class resultClass) { + Log.debug(getClass(), "Registering list of promises for: " + endpointId + ", request id: " + id + "result class: " + resultClass); + + return Promises.create(new Executor.ExecutorBody>() { + @Override + public void apply(ResolveFunction> resolve, RejectFunction reject) { + promises.put(endpointId + '@' + id, resolve); + resultClasses.put(endpointId + '@' + id, resultClass); + rejectFunctions.put(endpointId + '@' + id, reject); + } + }); + } + + private void applyObject(String combinedId, JSONObject result, Class resultClass) { + ResolveFunction resolveFunction = promises.get(combinedId); + final R dto = dtoFactory.createDtoFromJson(result.toString(), resultClass); + resolveFunction.apply(dto); + } + + private void applyArray(String combinedId, JSONArray result, Class resultClass) { + ResolveFunction> resolveFunction = promises.get(combinedId); + final List dto = dtoFactory.createListDtoFromJson(result.toString(), resultClass); + resolveFunction.apply(dto); + } + + private void processResult(String endpointId, String id, Class resultClass, JSONValue result) { + final String combinedId = endpointId + '@' + id; + final JSONObject resultObject = result.isObject(); + + if (resultObject != null) { + applyObject(combinedId, resultObject, resultClass); + } else { + final JSONArray resultArray = result.isArray(); + applyArray(combinedId, resultArray, resultClass); + } + } + + private void processError(final String endpointId, final String id, final JSONValue error) { + rejectFunctions.get(endpointId + '@' + id) + .apply(new PromiseError() { + @Override + public String getMessage() { + return error.toString(); + } + + @Override + public Throwable getCause() { + return null; + } + }); + } + + private String getId(JSONObject incomingJson) { + final JSONValue idValue = incomingJson.get("id"); + final JSONString idString = idValue.isString(); + if (idString == null) { + return Long.toString((long)idValue.isNumber().doubleValue()); + } else { + return idString.stringValue(); + } + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcher.java deleted file mode 100644 index 5244ee9918c..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcher.java +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -/** - * Receives raw JSON RPC objects ({@link JsonRpcObject}) extracted from WEB SOCKET - * transmissions ({@link WebSocketTransmission}) and dispatches them among more specific - * dispatchers {@link JsonRpcDispatcher}) according to their type (e.g. JSON RPC - * request/response dispatchers). - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcDispatcher implements WebSocketMessageReceiver { - private final Map dispatchers; - private final JsonRpcObjectValidator validator; - private final DtoFactory dtoFactory; - - @Inject - public WebSocketJsonRpcDispatcher(Map dispatchers, JsonRpcObjectValidator validator, DtoFactory dtoFactory) { - this.dispatchers = dispatchers; - this.validator = validator; - this.dtoFactory = dtoFactory; - } - - @Override - public void receive(String rawJsonRpcObject) { - final JsonRpcObject jsonRpcObject = dtoFactory.createDtoFromJson(rawJsonRpcObject, JsonRpcObject.class); - validator.validate(jsonRpcObject); - - final String type = jsonRpcObject.getType(); - final String message = jsonRpcObject.getMessage(); - - for (Entry entry : dispatchers.entrySet()) { - final String typeCandidate = entry.getKey(); - if (Objects.equals(typeCandidate, type)) { - final JsonRpcDispatcher dispatcher = entry.getValue(); - Log.debug(getClass(), "Matching json rpc message dispatcher: " + dispatcher.getClass()); - dispatcher.dispatch(message); - - return; - } - } - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializer.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializer.java index f80458f5fbe..f7911e76167 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializer.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializer.java @@ -10,36 +10,38 @@ *******************************************************************************/ package org.eclipse.che.ide.jsonrpc.impl; +import org.eclipse.che.ide.jsonrpc.JsonRpcInitializer; import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.ng.impl.SessionWebSocketInitializer; +import org.eclipse.che.ide.websocket.ng.impl.WebSocketInitializer; import javax.inject.Inject; import javax.inject.Singleton; import java.util.Map; /** + * Web socket based json rpc initializer. + * * @author Dmitry Kuleshov */ @Singleton public class WebSocketJsonRpcInitializer implements JsonRpcInitializer { - private final SessionWebSocketInitializer webSocketInitializer; + private final WebSocketInitializer webSocketInitializer; @Inject - public WebSocketJsonRpcInitializer(SessionWebSocketInitializer webSocketInitializer) { + public WebSocketJsonRpcInitializer(WebSocketInitializer webSocketInitializer) { this.webSocketInitializer = webSocketInitializer; } @Override - public void initialize(Map properties) { + public void initialize(String endpointId, Map properties) { Log.debug(getClass(), "Initializing with properties: " + properties); - - webSocketInitializer.initialize(properties); + final String url = properties.get("url"); + webSocketInitializer.initialize(endpointId, url); } @Override - public void terminate() { + public void terminate(String endpointId) { Log.debug(getClass(), "Terminating"); - - webSocketInitializer.terminate(); + webSocketInitializer.terminate(endpointId); } } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java deleted file mode 100644 index 752246c0ed9..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcher.java +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import com.google.gwt.regexp.shared.RegExp; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -import static com.google.gwt.regexp.shared.RegExp.compile; - -/** - * Dispatches JSON RPC requests among all registered implementations of {@link JsonRpcRequestReceiver} - * according to their mappings. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcRequestDispatcher implements JsonRpcDispatcher { - private final Map receivers; - - private final DtoFactory dtoFactory; - - @Inject - public WebSocketJsonRpcRequestDispatcher(Map receivers, DtoFactory dtoFactory) { - this.receivers = receivers; - this.dtoFactory = dtoFactory; - } - - @Override - public void dispatch(String message) { - final JsonRpcRequest request = dtoFactory.createDtoFromJson(message, JsonRpcRequest.class); - final String method = request.getMethod(); - - for (Entry entry : receivers.entrySet()) { - final String candidate = entry.getKey(); - if (Objects.equals(candidate, method)) { - final JsonRpcRequestReceiver receiver = entry.getValue(); - Log.debug(getClass(), "Matching request receiver: ", receiver.getClass()); - receiver.receive(request); - } - } - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java deleted file mode 100644 index af1ac35a779..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitter.java +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestTransmitter; -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Inject; -import javax.inject.Singleton; - - -/** - * Transmits JSON RPC requests through to {@link WebSocketJsonRpcTransmitter} - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcRequestTransmitter implements JsonRpcRequestTransmitter { - private final WebSocketJsonRpcTransmitter transmitter; - private final JsonRpcRequestRegistry requestRegistry; - - @Inject - public WebSocketJsonRpcRequestTransmitter(WebSocketJsonRpcTransmitter transmitter, - JsonRpcRequestRegistry requestRegistry) { - this.transmitter = transmitter; - this.requestRegistry = requestRegistry; - } - - @Override - public void transmit(JsonRpcRequest request) { - final Integer id = request.getId(); - final String method = request.getMethod(); - - if (id != null) { - requestRegistry.add(id, method); - } - - Log.debug(getClass(), "Transmitting a request " + request.toString()); - transmitter.transmit("request", request.toString()); - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java deleted file mode 100644 index 08d444fa161..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcher.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import com.google.gwt.regexp.shared.RegExp; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcResponseReceiver; -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -/** - * Dispatches JSON RPC responses among all registered implementations of {@link JsonRpcResponseReceiver} - * according to their mappings. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcResponseDispatcher implements JsonRpcDispatcher { - private final Map receivers; - - private final JsonRpcRequestRegistry registry; - private final DtoFactory dtoFactory; - - @Inject - public WebSocketJsonRpcResponseDispatcher(Map receivers, - JsonRpcRequestRegistry registry, - DtoFactory dtoFactory) { - this.receivers = receivers; - this.registry = registry; - this.dtoFactory = dtoFactory; - } - - @Override - public void dispatch(String message) { - final JsonRpcResponse response = dtoFactory.createDtoFromJson(message, JsonRpcResponse.class); - final String method = registry.extractFor(response.getId()); - - for (Entry entry : receivers.entrySet()) { - final String candidate = entry.getKey(); - if (Objects.equals(candidate, method)) { - final JsonRpcResponseReceiver receiver = entry.getValue(); - Log.debug(getClass(), "Matching response receiver: ", receiver.getClass()); - receiver.receive(response); - } - } - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java deleted file mode 100644 index 224b61d415c..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitter.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.eclipse.che.ide.jsonrpc.JsonRpcResponseTransmitter; -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Inject; -import javax.inject.Singleton; - - -/** - * Transmits JSON RPC responses to {@link WebSocketJsonRpcTransmitter} - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcResponseTransmitter implements JsonRpcResponseTransmitter { - private final WebSocketJsonRpcTransmitter transmitter; - - @Inject - public WebSocketJsonRpcResponseTransmitter(WebSocketJsonRpcTransmitter transmitter) { - this.transmitter = transmitter; - } - - @Override - public void transmit(JsonRpcResponse response) { - Log.debug(getClass(), "Transmitting a response " + response.toString()); - transmitter.transmit("response", response.toString()); - } - -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitter.java deleted file mode 100644 index dc34560517c..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitter.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.ng.WebSocketMessageTransmitter; - -import javax.inject.Inject; -import javax.inject.Singleton; - - -/** - * Transmits JSON RPC objects to {@link WebSocketMessageTransmitter} - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketJsonRpcTransmitter { - private final WebSocketMessageTransmitter transmitter; - private final DtoFactory dtoFactory; - private final JsonRpcObjectValidator validator; - - @Inject - public WebSocketJsonRpcTransmitter(WebSocketMessageTransmitter transmitter, DtoFactory dtoFactory, JsonRpcObjectValidator validator) { - this.transmitter = transmitter; - this.dtoFactory = dtoFactory; - this.validator = validator; - } - - public void transmit(String type, String message) { - Log.debug(getClass(), "Transmitting a json rpc object. Message: " + message + "of type: " + message); - - final JsonRpcObject jsonRpcObject = dtoFactory.createDto(JsonRpcObject.class).withType(type).withMessage(message); - validator.validate(jsonRpcObject); - - transmitter.transmit("jsonrpc-2.0", jsonRpcObject.toString()); - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java new file mode 100644 index 00000000000..74e078cd5f3 --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketToJsonRpcDispatcher.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc.impl; + +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONParser; + +import org.eclipse.che.ide.util.loging.Log; +import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Dispatches messages received from web socket endpoint throughout json rpc + * inner infrastructure. + * + * @author Dmitry Kuleshov + */ +@Singleton +public class WebSocketToJsonRpcDispatcher implements WebSocketMessageReceiver { + private final RequestDispatcher requestDispatcher; + private final NotificationDispatcher notificationDispatcher; + private final ResponseDispatcher responseDispatcher; + + @Inject + public WebSocketToJsonRpcDispatcher(RequestDispatcher requestDispatcher, + NotificationDispatcher notificationDispatcher, + ResponseDispatcher responseDispatcher) { + this.requestDispatcher = requestDispatcher; + this.notificationDispatcher = notificationDispatcher; + this.responseDispatcher = responseDispatcher; + } + + @Override + public void receive(String endpointId, String message) { + Log.debug(getClass(), "Dispatching message: " + message + " form endpoint: " + endpointId); + + final JSONObject incomingJson = JSONParser.parseStrict(message).isObject(); + + final boolean hasMethod = incomingJson.containsKey("method"); + final boolean hasParams = incomingJson.containsKey("params"); + final boolean hasId = incomingJson.containsKey("id"); + final boolean hasResult = incomingJson.containsKey("result"); + final boolean hasError = incomingJson.containsKey("error"); + + if (hasMethod && hasId && !hasResult && !hasError) { + Log.debug(getClass(), "It is a request, calling request dispatcher."); + requestDispatcher.dispatch(endpointId, incomingJson); + return; + } + + if (hasMethod && !hasId && !hasResult && !hasError) { + Log.debug(getClass(), "It is a notification, calling notification dispatcher."); + notificationDispatcher.dispatch(endpointId, incomingJson); + return; + } + + if (!hasMethod && !hasParams && hasId && (hasError != hasResult)) { + Log.debug(getClass(), "It is a response, calling response dispatcher."); + responseDispatcher.dispatch(endpointId, incomingJson); + return; + } + + final String error = "Malformed Json RPC message, could not define message type or parse it properly."; + Log.error(getClass(), error); + throw new IllegalStateException(error); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketTransmitter.java new file mode 100644 index 00000000000..1d91c931493 --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketTransmitter.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.jsonrpc.impl; + +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONParser; +import com.google.gwt.json.client.JSONString; +import com.google.gwt.json.client.JSONValue; +import com.google.inject.Singleton; + +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.jsonrpc.RequestTransmitter; +import org.eclipse.che.ide.util.loging.Log; +import org.eclipse.che.ide.websocket.ng.WebSocketMessageTransmitter; + +import javax.inject.Inject; +import java.util.List; + +/** + * Web socket based json rpc transmitter implementation + * + * @author Dmitry Kuleshov + */ +@Singleton +public class WebSocketTransmitter implements RequestTransmitter { + private static long idCounter = 0L; + + private final ResponseDispatcher responseDispatcher; + private final WebSocketMessageTransmitter transmitter; + private final DtoFactory dtoFactory; + + @Inject + public WebSocketTransmitter(ResponseDispatcher responseDispatcher, + WebSocketMessageTransmitter transmitter, + DtoFactory dtoFactory) { + this.responseDispatcher = responseDispatcher; + this.transmitter = transmitter; + this.dtoFactory = dtoFactory; + } + + @Override + public void transmitNotification(String endpointId, String method) { + Log.debug(getClass(), "Transmitting a notification to: " + endpointId + ", method: " + method); + internalTransmit(endpointId, method, null, null); + } + + @Override + public void transmitNotification(String endpointId, String method, Object params) { + Log.debug(getClass(), "Transmitting a parametrized notification to: " + endpointId + ", method: " + method + ", params: " + params); + internalTransmit(endpointId, method, params, null); + } + + @Override + public Promise transmitRequest(String endpointId, String method, Class resultClass) { + Log.debug(getClass(), "Transmitting a request to: " + endpointId + ", method: " + method + ", result class: " + resultClass); + + final String id = Long.toString(++idCounter); + final Promise promise = responseDispatcher.getPromise(endpointId, id, resultClass); + + internalTransmit(endpointId, method, null, id); + return promise; + } + + @Override + public Promise transmitRequest(String endpointId, String method, Object params, Class resultClass) { + Log.debug(getClass(), "Transmitting a parametrized request to: " + endpointId + + ", method: " + method + + ", params: " + params + + ", result class: " + resultClass); + + final String id = Long.toString(++idCounter); + final Promise promise = responseDispatcher.getPromise(endpointId, id, resultClass); + + internalTransmit(endpointId, method, params, id); + return promise; + } + + @Override + public Promise> transmitRequestForList(String endpointId, String method, Class resultClass) { + Log.debug(getClass(), "Transmitting a request for a list to: " + endpointId + + ", method: " + method + + ", result class: " + resultClass); + + final String id = Long.toString(++idCounter); + final Promise> promise = responseDispatcher.getListPromise(endpointId, id, resultClass); + + internalTransmit(endpointId, method, null, id); + return promise; + } + + @Override + public Promise> transmitRequestForList(String endpointId, String method, Object params, Class resultClass) { + Log.debug(getClass(), "Transmitting a parametrized request for a list to: " + endpointId + + ", method: " + method + + ", params: " + params + + ", result class: " + resultClass); + + final String id = Long.toString(++idCounter); + final Promise> promise = responseDispatcher.getListPromise(endpointId, id, resultClass); + + internalTransmit(endpointId, method, params, id); + return promise; + } + + private void internalTransmit(String endpointId, String method, Object dto, String id) { + final JSONObject request = new JSONObject(); + + request.put("jsonrpc", new JSONString("2.0")); + request.put("method", new JSONString(method)); + + if (id != null) { + request.put("id", new JSONString(id)); + } + + if (dto != null) { + final String dtoString = dtoFactory.toJson(dto); + final JSONValue jsonParams = JSONParser.parseStrict(dtoString); + request.put("params", jsonParams); + } + + transmitter.transmit(endpointId, request.toString()); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageReceiver.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageReceiver.java index 71542602870..82d695428e3 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageReceiver.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageReceiver.java @@ -11,23 +11,18 @@ package org.eclipse.che.ide.websocket.ng; /** - * The implementation of this interface receives WEB SOCKET messages corresponding - * to the registered protocol according to the defined mapping. The protocol must - * be mapped via MapBinder in an ordinary Gin module, for example: - * - *

- *     
- *         GinMapBinder receivers =
- *         GinMapBinder.newMapBinder(binder(), String.class, WebSocketMessageReceiver.class);
- *         receivers.addBinding("protocol-name").to(CustomWebSocketMessageReceiver.class);
- *     
- * 
- * - * All WEB SOCKET transmissions with the protocol field equal to "protocol-name" will - * be processed with the CustomWebSocketMessageReceiver instance. + * Used as entry point for a web socket protocol message consumers. * * @author Dmitry Kuleshov */ public interface WebSocketMessageReceiver { - void receive(String message); + /** + * Receives a message by a a web socket protocol. + * + * @param endpointId + * identifier of an endpoint known to an transmitter implementation + * @param message + * plain text message + */ + void receive(String endpointId, String message); } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageTransmitter.java index b0e95afc910..886fd4f66b1 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageTransmitter.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/WebSocketMessageTransmitter.java @@ -11,18 +11,27 @@ package org.eclipse.che.ide.websocket.ng; /** - * Transmits WEB SOCKET messages + * Plain text transmitter over a web socket protocol. In current specification + * it is not required from and the implementor to fulfill strict ordering of + * sequential transmissions along with message delivery notification. The only + * guarantee that is required is to send a text message to predefined endpoint. * * @author Dmitry Kuleshov */ public interface WebSocketMessageTransmitter { /** - * Transmits WEB SOCKET messages + * Transmit a string message to an endpoint over wer socket protocol. The + * connection should be considered to be opened at the moment of calling, + * however the some of implementation may provide ability to cache messages + * until the connection is opened. * - * @param protocol - * message protocol + * @param endpointId + * identifier of an endpoint known to an transmitter implementation * @param message - * message body + * plain text message + * + * @see org.eclipse.che.ide.websocket.ng.impl.UrlResolver + * @see org.eclipse.che.ide.websocket.ng.impl.MessagesReSender */ - void transmit(String protocol, String message); + void transmit(String endpointId, String message); } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpoint.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpoint.java index 423231ce620..2ccecd5a5d3 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpoint.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpoint.java @@ -22,43 +22,41 @@ */ @Singleton public class BasicWebSocketEndpoint implements WebSocketEndpoint { - private final WebSocketConnectionSustainer sustainer; - private final PendingMessagesReSender reSender; - private final WebSocketTransmissionDispatcher dispatcher; + private final WebSocketConnectionSustainer sustainer; + private final MessagesReSender reSender; + private final WebSocketDispatcher dispatcher; @Inject - public BasicWebSocketEndpoint(WebSocketConnectionSustainer sustainer, - PendingMessagesReSender pending, - WebSocketTransmissionDispatcher dispatcher) { + public BasicWebSocketEndpoint(WebSocketConnectionSustainer sustainer, MessagesReSender reSender, WebSocketDispatcher dispatcher) { this.sustainer = sustainer; - this.reSender = pending; + this.reSender = reSender; this.dispatcher = dispatcher; } @Override - public void onOpen() { + public void onOpen(String url) { Log.debug(getClass(), "Session opened."); - sustainer.reset(); - reSender.resend(); + sustainer.reset(url); + reSender.reSend(url); } @Override - public void onClose() { + public void onClose(String url) { Log.debug(getClass(), "Session closed."); - sustainer.sustain(); + sustainer.sustain(url); } @Override - public void onError() { - Log.warn(getClass(), "Error occurred."); + public void onError(String url) { + Log.warn(getClass(), "Error occurred for endpoint " + url); } @Override - public void onMessage(String message) { + public void onMessage(String url, String message) { Log.debug(getClass(), "Message received: " + message); - dispatcher.dispatch(message); + dispatcher.dispatch(url, message); } } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitter.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitter.java index 135b9e6e477..0fa5c8015aa 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitter.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitter.java @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.che.ide.websocket.ng.impl; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.ide.websocket.ng.WebSocketMessageTransmitter; @@ -19,44 +17,35 @@ import javax.inject.Singleton; /** - * Transmits messages over WEB SOCKET to a specific endpoint or broadcasts them. - * If WEB SOCKET session is not opened adds messages to re-sender to try to send - * them when session will be opened again. + * Web socket transmitter implementation that can transmit a message into opened connection + * or send a message to pending message re-sender so it could be possible to send it later * * @author Dmitry Kuleshov */ @Singleton public class BasicWebSocketMessageTransmitter implements WebSocketMessageTransmitter { - private final WebSocketConnection connection; - private final PendingMessagesReSender reSender; - private final WebSocketTransmissionValidator validator; - private final DtoFactory dtoFactory; + private final WebSocketConnectionManager connectionManager; + private final MessagesReSender reSender; + private final UrlResolver urlResolver; @Inject - public BasicWebSocketMessageTransmitter(WebSocketConnection connection, - PendingMessagesReSender reSender, - WebSocketTransmissionValidator validator, - DtoFactory dtoFactory) { - this.connection = connection; + public BasicWebSocketMessageTransmitter(WebSocketConnectionManager connectionManager, MessagesReSender reSender, UrlResolver resolver) { + this.connectionManager = connectionManager; this.reSender = reSender; - this.validator = validator; - this.dtoFactory = dtoFactory; + this.urlResolver = resolver; } @Override - public void transmit(String protocol, String message) { - final WebSocketTransmission transmission = dtoFactory.createDto(WebSocketTransmission.class).withProtocol(protocol).withMessage(message); - validator.validate(transmission); + public void transmit(String endpointId, String message) { + final String url = urlResolver.getUrl(endpointId); - if (connection.isOpen()) { - Log.debug(getClass(), "Connection is opened, transmitting"); - - connection.send(transmission); + if (connectionManager.isConnectionOpen(url)) { + Log.debug(getClass(), "Connection is opened, transmitting: " + message); + connectionManager.sendMessage(url, message); } else { - Log.debug(getClass(), "Connection is closed, adding to pending"); - - reSender.add(transmission); + Log.debug(getClass(), "Connection is closed, adding to pending: " + message); + reSender.add(url, message); } } } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidator.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidator.java deleted file mode 100644 index 7cba96aa5a2..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidator.java +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import com.google.gwt.json.client.JSONParser; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Set; - -/** - * Basic implementation of WEB SOCKET transmission validator, validation rules are the following: - * - *
    - *
  • protocol must be not null
  • - *
  • protocol must be not empty
  • - *
  • protocol must be registered (mapped to a corresponding receiver implementation
  • - *
  • message must be not null
  • - *
  • message must be not empty
  • - *
  • message must be a valid JSON
  • - *
- * - * @author Dmitry Kuleshov - */ -@Singleton -public class BasicWebSocketTransmissionValidator implements WebSocketTransmissionValidator { - - private final Set protocols; - - @Inject - public BasicWebSocketTransmissionValidator(Map receivers) { - this.protocols = receivers.keySet(); - } - - - @Override - public void validate(WebSocketTransmission transmission) { - validateProtocol(transmission.getProtocol()); - validateMessage(transmission.getMessage()); - } - - private void validateProtocol(String protocol) { - if (protocols.contains(protocol)) { - Log.debug(getClass(), "Web socket transmission protocol {} is among registered", protocol); - } else { - logError("Web socket transmission of not registered protocol"); - } - } - - private void validateMessage(String message) { - validateNull(message); - validateEmpty(message); - validateJson(message); - } - - private void validateNull(String message) { - if (message == null) { - logError("Web socket transmission message is null"); - } else { - Log.debug(getClass(), "Web socket transmission message is not null"); - } - } - - private void validateEmpty(String message) { - if (message.isEmpty()) { - logError("Web socket transmission message is empty"); - } else { - Log.debug(getClass(), "Web socket transmission message is not empty"); - } - } - - private void validateJson(String message) { - boolean error = false; - - try { - JSONParser.parseStrict(message); - } catch (Exception e) { - error = true; - } - - if (error) { - logError("Web socket transmission message is not a valid json"); - } else { - Log.debug(getClass(), "Web socket transmission message is a valid json"); - } - } - - private void logError(String error) { - Log.error(getClass(), error); - throw new IllegalArgumentException(error); - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/DelayableWebSocket.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/DelayableWebSocketConnection.java similarity index 81% rename from ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/DelayableWebSocket.java rename to ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/DelayableWebSocketConnection.java index fa0541186c8..54af3636a58 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/DelayableWebSocket.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/DelayableWebSocketConnection.java @@ -18,29 +18,29 @@ import javax.inject.Inject; /** - * Yet another {@link WebSocketJsoWrapper} wrapper to benefit from - * dependency injection provided by Gin. This implementation allows - * setting a delay for opening a connection. It is convenient when - * you are reconnecting. + * Web socket connection that can be established or reestablished with a delay * * @author Dmitry Kuleshov */ -public class DelayableWebSocket implements WebSocket { - private final String url; - private final Integer delay; - private final WebSocketEndpoint endpoint; +public class DelayableWebSocketConnection implements WebSocketConnection { + private final WebSocketPropertyManager propertyManager; + private final WebSocketEndpoint endpoint; + private final String url; private WebSocketJsoWrapper webSocketJsoWrapper; + @Inject - public DelayableWebSocket(@Assisted String url, @Assisted Integer delay, WebSocketEndpoint endpoint) { - this.url = url; - this.delay = delay; + public DelayableWebSocketConnection(WebSocketPropertyManager propertyManager, WebSocketEndpoint endpoint, @Assisted String url) { + this.propertyManager = propertyManager; this.endpoint = endpoint; + this.url = url; } @Override public void open() { + final int delay = propertyManager.getConnectionDelay(url); + if (isClosed() || isClosing()) { if (delay == 0) { webSocketJsoWrapper = WebSocketJsoWrapper.connect(url, endpoint); diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSender.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSender.java new file mode 100644 index 00000000000..6fafcc3cd42 --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSender.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Caches messages that was transmitted when a web socket connection + * was not opened and resends them when the connection is opened again. + * + * @author Dmitry Kuleshov + */ +@Singleton +public class MessagesReSender { + private static final int MAX_MESSAGES = 100; + + private final Map> messageRegistry = new HashMap<>(); + + private final WebSocketConnectionManager connectionManager; + + @Inject + public MessagesReSender(WebSocketConnectionManager connectionManager) { + this.connectionManager = connectionManager; + } + + /** + * Add message that is to be sent when a connection defined be the URL + * is opened again. + * + * @param url + * url of a web socket connection + * @param message + * plain text message + */ + public void add(String url, String message) { + if (!messageRegistry.containsKey(url)) { + final LinkedList newList = new LinkedList<>(); + messageRegistry.put(url, newList); + } + + final List webSocketTransmissions = messageRegistry.get(url); + if (webSocketTransmissions.size() <= MAX_MESSAGES) { + webSocketTransmissions.add(message); + } + } + + public void reSend(String url) { + if (!messageRegistry.containsKey(url)) { + return; + } + + final List messages = messageRegistry.get(url); + if (messages.isEmpty()) { + return; + } + + Log.info(getClass(), "Going to resend websocket messaged: " + messages); + + final List backing = new ArrayList<>(messages); + messages.clear(); + + for (String message : backing) { + if (connectionManager.isConnectionOpen(url)) { + connectionManager.sendMessage(url, message); + } else { + messages.add(message); + } + } + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSender.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSender.java deleted file mode 100644 index c3a91cb14dc..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSender.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -/** - * Instance is responsible for resending messages that were sent during the period - * when web socket session was closed. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class PendingMessagesReSender { - private static final int MAX_MESSAGES = 100; - - private final List messages = new LinkedList<>(); - - private final WebSocketConnection connection; - - @Inject - public PendingMessagesReSender(WebSocketConnection connection) { - this.connection = connection; - } - - public void add(WebSocketTransmission message) { - if (messages.size() <= MAX_MESSAGES) { - messages.add(message); - } - } - - public void resend() { - if (messages.isEmpty()) { - return; - } - - final List backing = new ArrayList<>(messages); - messages.clear(); - - for (WebSocketTransmission message : backing) { - if (connection.isOpen()) { - connection.send(message); - } else { - messages.add(message); - } - } - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializer.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializer.java deleted file mode 100644 index 430ff799245..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializer.java +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; - -import static org.eclipse.che.ide.websocket.ng.impl.WebSocketConnection.IMMEDIATELY; - -/** - * @author Dmitry Kuleshov - */ -@Singleton -public class SessionWebSocketInitializer implements WebSocketInitializer { - private final WebSocketConnection connection; - private final WebSocketConnectionSustainer sustainer; - - @Inject - public SessionWebSocketInitializer(WebSocketConnection connection, WebSocketConnectionSustainer sustainer) { - this.connection = connection; - this.sustainer = sustainer; - } - - @Override - public void initialize(Map properties) { - Log.debug(getClass(), "Initializing with properties: " + properties); - - final String url = properties.get("url"); - - sustainer.enable(); - connection.initialize(url).open(IMMEDIATELY); - } - - @Override - public void terminate() { - Log.debug(getClass(), "Stopping"); - - sustainer.disable(); - connection.close(); - } -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolver.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolver.java new file mode 100644 index 00000000000..14975e784bc --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolver.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import javax.inject.Singleton; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +/** + * Defines the mepping between high level identifiers that are used be + * upper services (e.g. json rpc) and low level identifier (which is a + * URL) for internal web socket components. + * + * @author Dmitry Kuleshov + */ +@Singleton +public class UrlResolver { + private final Map idMapping = new HashMap<>(); + + /** + * Sets a mapping for a specified id + * + * @param id + * id to be mapped + * @param url + * url mapping + */ + public void setMapping(String id, String url) { + idMapping.put(id, url); + } + + /** + * Resolve URL, provide identifier that is mapped to specified URL. + * + * @param url + * low leve identifier + * + * @return high level identifier + */ + public String resolve(String url) { + for (Entry entry : idMapping.entrySet()) { + if (Objects.equals(entry.getValue(), url)) { + return entry.getKey(); + } + } + + return null; + } + + /** + * Gets a URL by high level identifier + * + * @param id + * identifier + * + * @return URL + */ + public String getUrl(String id) { + return idMapping.get(id); + } + + /** + * Remove a mepping from resolver's registry + * + * @param id + * identifier of the mapping + * + * @return removed URL mapped to specified id + */ + public String removeMapping(String id) { + return idMapping.remove(id); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocket.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocket.java deleted file mode 100644 index 40a3797a1f1..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocket.java +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -/** - * This interface is purposed to split WEB SOCKET API and implementations, - * that is needed because here we are wrapping native implementations which - * potentially may require switching to some javascript library. - * - * @author Dmitry Kuleshov - */ -public interface WebSocket { - /** - * Open a WEB SOCKET connection - */ - void open(); - - /** - * Close a WEB SOCKET connection - */ - void close(); - - /** - * Send a text message over WEB SOCKET - * - * @param message text message to send - */ - void send(final String message); - - /** - * Checks if WEB SOCKET connection is closed - * - * @return true if closed - */ - boolean isClosed(); - - /** - * Checks if WEB SOCKET connection is closing - * - * @return true if closing - */ - boolean isClosing(); - - /** - * Checks if WEB SOCKET connection is open - * - * @return true if open - */ - boolean isOpen(); - - /** - * Checks if WEB SOCKET connection is connecting - * - * @return true if connecting - */ - boolean isConnecting(); -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnection.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnection.java index 84311c15ad2..b231f190658 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnection.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnection.java @@ -10,63 +10,59 @@ *******************************************************************************/ package org.eclipse.che.ide.websocket.ng.impl; -import com.google.inject.Inject; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.util.loging.Log; - -import javax.inject.Singleton; - /** - * Entry point for high level WEB SOCKET connection operations. + * This interface is purposed to split WEB SOCKET API and implementations, + * that is needed because here we are wrapping native implementations which + * potentially may require switching to some javascript library. * * @author Dmitry Kuleshov */ -@Singleton -public class WebSocketConnection { - public static final int IMMEDIATELY = 0; - - private final WebSocketCreator webSocketCreator; - - private WebSocket webSocket; - private String url; - - @Inject - public WebSocketConnection(WebSocketCreator webSocketCreator) { - this.webSocketCreator = webSocketCreator; - } - - public WebSocketConnection initialize(String url){ - this.url = url; - return this; - } - - public void open(int delay) { - if (url == null){ - Log.error(WebSocketConnection.class, "Cannot open connection because no URL is set"); - - throw new IllegalStateException("No URL is set"); - } - - webSocket = webSocketCreator.create(url, delay); - webSocket.open(); - - Log.debug(getClass(), "Opening connection. Url: " + url); - } - - public void close() { - webSocket.close(); - - Log.debug(WebSocketConnection.class, "Closing connection."); - } - - public void send(WebSocketTransmission message) { - webSocket.send(message.toString()); - - Log.debug(getClass(), "Sending message: " + message); - } +public interface WebSocketConnection { + + /** + * Open a WEB SOCKET connection + */ + void open(); + + /** + * Close a WEB SOCKET connection + */ + void close(); + + /** + * Send a text message over WEB SOCKET + * + * @param message + * text message to send + */ + void send(final String message); + + /** + * Checks if WEB SOCKET connection is closed + * + * @return true if closed + */ + boolean isClosed(); + + /** + * Checks if WEB SOCKET connection is closing + * + * @return true if closing + */ + boolean isClosing(); + + /** + * Checks if WEB SOCKET connection is open + * + * @return true if open + */ + boolean isOpen(); + + /** + * Checks if WEB SOCKET connection is connecting + * + * @return true if connecting + */ + boolean isConnecting(); - public boolean isOpen() { - return webSocket != null && webSocket.isOpen(); - } } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManager.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManager.java new file mode 100644 index 00000000000..ff1175c5bca --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManager.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Singleton; +import java.util.HashMap; +import java.util.Map; + +/** + * Manages all connection related high level processes. Acts as a facade to low level web socket + * components. + * + * @author Dmitry Kuleshov + */ +@Singleton +public class WebSocketConnectionManager { + private final WebSocketFactory webSocketFactory; + + private final Map connectionsRegistry = new HashMap<>(); + + @Inject + public WebSocketConnectionManager(WebSocketFactory webSocketFactory) { + this.webSocketFactory = webSocketFactory; + } + + /** + * Initialize a connection. Performs all necessary preparations except for properties management. Must be called before + * any interactions with a web socket connection. + * + * @param url + * url of a web socket connection that is to be initialized + */ + public void initializeConnection(String url) { + connectionsRegistry.put(url, webSocketFactory.create(url)); + } + + /** + * Establishes a web socket connection to an endpoint defined by a URL parameter + * + * @param url + * url of a web socket connection that is to be established + */ + public void establishConnection(String url) { + final WebSocketConnection webSocketConnection = connectionsRegistry.get(url); + + if (webSocketConnection == null) { + final String error = "No connection with url: " + url + "is initialized. Run 'initializedConnection' first."; + Log.error(getClass(), error); + throw new IllegalStateException(error); + } + + webSocketConnection.open(); + + Log.debug(getClass(), "Opening connection. Url: " + url); + } + + /** + * Close a web socket connection to an endpoint defined by a URL parameter + * + * @param url + * url of a connection to be closed + */ + public void closeConnection(String url) { + final WebSocketConnection webSocketConnection = connectionsRegistry.get(url); + + if (webSocketConnection == null) { + final String warning = "Closing connection that is not registered and seem like does not exist"; + Log.warn(getClass(), warning); + throw new IllegalStateException(warning); + } + + webSocketConnection.close(); + Log.debug(WebSocketConnectionManager.class, "Closing connection."); + } + + /** + * Sends a message to a specified endpoint over web socket connection. + * + * @param url + * url of an endpoint the message is adressed to + * @param message + * plain text message + */ + public void sendMessage(String url, String message) { + final WebSocketConnection webSocketConnection = connectionsRegistry.get(url); + + if (webSocketConnection == null) { + final String error = "No connection with url: " + url + "is initialized. Run 'initializedConnection' first."; + Log.error(getClass(), error); + throw new IllegalStateException(error); + } + + webSocketConnection.send(message); + Log.debug(getClass(), "Sending message: " + message); + } + + /** + * Checks if a connection is opened at the moment + * + * @param url + * url of a web socket connection to be checked + * + * @return connection status: true if opened, false if else + */ + public boolean isConnectionOpen(String url) { + final WebSocketConnection webSocketConnection = connectionsRegistry.get(url); + + return webSocketConnection != null && webSocketConnection.isOpen(); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainer.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainer.java index 10e3c10202b..03d53c47543 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainer.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainer.java @@ -18,58 +18,52 @@ /** * Responsible for keeping connection alive and reconnecting if needed. * If connection is closed and sustainer is active it tries to reconnect - * according to its properties: - * + * according to its properties. Default values are: *
    - *
  • reconnection delay - 500 milliseconds
  • - *
  • reconnection limit - 5 attempts
  • + *
  • reconnection delay: 500 milliseconds
  • + *
  • reconnection limit: 5 attempts
  • *
* * @author Dmitry Kuleshov */ @Singleton public class WebSocketConnectionSustainer { - private static final int RECONNECTION_DELAY = 500; + private static final int RECONNECTION_DELAY = 1_000; private static final int RECONNECTION_LIMIT = 5; - private final WebSocketConnection connection; - - private boolean active; - private int attempt; + private final WebSocketConnectionManager connectionManager; + private final WebSocketPropertyManager propertyManager; @Inject - public WebSocketConnectionSustainer(WebSocketConnection connection) { - this.connection = connection; + public WebSocketConnectionSustainer(WebSocketConnectionManager connectionManager, WebSocketPropertyManager propertyManager) { + this.connectionManager = connectionManager; + this.propertyManager = propertyManager; } - public void reset() { - Log.debug(getClass(), "Resetting number of reconnection attempt number. Previous was: " + attempt); - attempt = 0; + public void reset(String url) { + final int attempts = propertyManager.getReConnectionAttempts(url); + + Log.debug(getClass(), "Resetting number of reconnection attempt number. Previous was: " + attempts); + + propertyManager.setReConnectionAttempts(url, 0); } - public void sustain() { - if (++attempt > RECONNECTION_LIMIT) { + public void sustain(String url) { + final int reConnectionAttempts = propertyManager.getReConnectionAttempts(url); + + if (reConnectionAttempts + 1 > RECONNECTION_LIMIT) { Log.debug(getClass(), "Exceeding reconnection limit."); - disable(); - } - if (active) { - Log.debug(getClass(), "Sustaining connection. Current attempt number: " + attempt); - connection.open(RECONNECTION_DELAY); + propertyManager.disableSustainer(url); } - } - public void enable() { - if (!active) { - Log.debug(getClass(), "Sustainer enabled."); - active = true; - } - } + if (propertyManager.sustainerEnabled(url)) { + Log.debug(getClass(), "Sustaining connection. Current attempt number: " + reConnectionAttempts); + + propertyManager.setReConnectionAttempts(url, reConnectionAttempts + 1); + propertyManager.setConnectionDelay(url, RECONNECTION_DELAY); - public void disable() { - if (active) { - Log.debug(getClass(), "Sustainer disabled"); - active = false; + connectionManager.establishConnection(url); } } } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcher.java new file mode 100644 index 00000000000..cc49dc9b621 --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcher.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.eclipse.che.ide.util.loging.Log; +import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Dispatches messages received from web socket endpoint. + * + * @author Dmitry Kuleshov + */ +@Singleton +public class WebSocketDispatcher { + private final WebSocketMessageReceiver receiver; + private final UrlResolver urlResolver; + + @Inject + public WebSocketDispatcher(WebSocketMessageReceiver receiver, UrlResolver urlResolver) { + this.receiver = receiver; + this.urlResolver = urlResolver; + } + + /** + * Dispatch a specific message among receiver implementations, currently implementd only + * JsonRPC receiver. + * + * @param url + * url of a web socket endpoint that passed a message + * @param message + * plain text message + */ + public void dispatch(String url, String message) { + Log.debug(getClass(), "Receiving a web socket message: " + message); + + final String id = urlResolver.resolve(url); + receiver.receive(id, message); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketEndpoint.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketEndpoint.java index 9e2cc9e4714..1ae60884f15 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketEndpoint.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketEndpoint.java @@ -18,21 +18,37 @@ public interface WebSocketEndpoint { /** * Is called when connection is opened + * + * @param url + * url of a web socket where event happened, used as a low level identifier inside + * web socket infrastructure */ - void onOpen(); + void onOpen(String url); /** * Is called when connection is closed + * + * @param url + * url of a web socket where event happened, used as a low level identifier inside + * web socket infrastructure */ - void onClose(); + void onClose(String url); /** * Is called when connection has errors + * + * @param url + * url of a web socket where event happened, used as a low level identifier inside + * web socket infrastructure */ - void onError(); + void onError(String url); /** * Is called when connection receives a text message + * + * @param url + * url of a web socket where event happened, used as a low level identifier inside + * web socket infrastructure */ - void onMessage(String message); + void onMessage(String url, String message); } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketCreator.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketFactory.java similarity index 75% rename from ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketCreator.java rename to ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketFactory.java index e33e75242f7..a02abe95d3b 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketCreator.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketFactory.java @@ -11,8 +11,11 @@ package org.eclipse.che.ide.websocket.ng.impl; /** + * Guice factory interface to create a web socket connection based on an URL + * with all related dependencies injected + * * @author Dmitry Kuleshov */ -public interface WebSocketCreator { - WebSocket create(String url, Integer delay); +public interface WebSocketFactory { + WebSocketConnection create(String url); } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializer.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializer.java index 7e03cca49a6..913194cea56 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializer.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializer.java @@ -10,26 +10,66 @@ *******************************************************************************/ package org.eclipse.che.ide.websocket.ng.impl; +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Inject; import javax.inject.Singleton; -import java.util.Map; /** - * Initializes and terminates WEB SOCKET services. + * Contain all routines related to a web socket connection initialization * * @author Dmitry Kuleshov */ @Singleton -public interface WebSocketInitializer { +public class WebSocketInitializer { + private final WebSocketConnectionManager connectionManager; + private final WebSocketPropertyManager propertyManager; + private final UrlResolver urlResolver; + + @Inject + public WebSocketInitializer(WebSocketConnectionManager connectionManager, + WebSocketPropertyManager propertyManager, + UrlResolver urlResolver) { + this.connectionManager = connectionManager; + this.propertyManager = propertyManager; + this.urlResolver = urlResolver; + } + /** - * Initialize WEB SOCKET services with properties contained - * in a map as simple key->value pairs. + * Initializes a web socket connection, set default values, perform + * mandatory preparation work. * - * @param properties properties map + * @param endpointId + * high level identifier of a web socket connection, used by + * high level service (e.g. json rpc infrastructure) + * @param url + * url of a web socket endpoint */ - void initialize(Map properties); + public void initialize(String endpointId, String url) { + Log.debug(getClass(), "Initializing with url: " + url); + + urlResolver.setMapping(endpointId, url); + + propertyManager.initializeConnection(url); + connectionManager.initializeConnection(url); + + connectionManager.establishConnection(url); + } /** - * Terminates WEB SOCKET services + * Terminate web socket connection and clean up resources + * + * @param endpointId + * high level identifier of a web socket connection, used by + * high level service (e.g. json rpc infrastructure) */ - void terminate(); + public void terminate(String endpointId) { + Log.debug(getClass(), "Stopping"); + + final String url = urlResolver.removeMapping(endpointId); + + propertyManager.disableSustainer(url); + + connectionManager.closeConnection(url); + } } diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketJsoWrapper.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketJsoWrapper.java index f7fc222ea0e..e788bcadd9b 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketJsoWrapper.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketJsoWrapper.java @@ -24,19 +24,19 @@ protected WebSocketJsoWrapper() { public static native WebSocketJsoWrapper connect(String url, WebSocketEndpoint endpoint) /*-{ var webSocket = new WebSocket(url); webSocket.onopen = function () { - endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onOpen()(); + endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onOpen(Ljava/lang/String;)(url); }; webSocket.onclose = function () { - endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onClose()(); + endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onClose(Ljava/lang/String;)(url); }; webSocket.onerror = function () { - endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onError()(); + endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onError(Ljava/lang/String;)(url); }; webSocket.onmessage = function (event) { - endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onMessage(Ljava/lang/String;)(event.data); + endpoint.@org.eclipse.che.ide.websocket.ng.impl.WebSocketEndpoint::onMessage(Ljava/lang/String;Ljava/lang/String;)(url, event.data); }; return webSocket; }-*/; diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManager.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManager.java new file mode 100644 index 00000000000..f44de251506 --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManager.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.eclipse.che.ide.util.loging.Log; + +import javax.inject.Singleton; +import java.util.HashMap; +import java.util.Map; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static org.eclipse.che.ide.websocket.ng.impl.WebSocketPropertyManager.Properties.ATTEMPTS; +import static org.eclipse.che.ide.websocket.ng.impl.WebSocketPropertyManager.Properties.DELAY; +import static org.eclipse.che.ide.websocket.ng.impl.WebSocketPropertyManager.Properties.SUSTAINER_ENABLED; +import static org.eclipse.che.ide.websocket.ng.impl.WebSocketPropertyManager.Properties.URL; + +/** + * Singleton implementation of properties manager to keep all web socket + * connections properties in a one handy place. Basically is a wrapper with + * some additional functionality around a map. Each entry is represented by a + * key - web socket connection url and a value - a map of properties related + * to a connection. + * + * @author Dmitry Kuleshov + */ +@Singleton +public class WebSocketPropertyManager { + /** + * Map to store properties. + * Key - web socket url identifying a connection + * Value - map of connection properties + */ + private final Map> properties = new HashMap<>(); + + /** + * Initialized default properties for a connection. The implementation of + * web socket infrastructure is implemented in such way that this method + * must be necessarily called before any interactions with a connection. + * Default values are: + *
    + *
  • URL - url of this connection
  • + *
  • Reconnection delay: 0
  • + *
  • Reconnection attempts: 0
  • + *
  • Sustainer status: enabled
  • + *
+ * + * @param url + * identifier of a web socket connection + */ + public void initializeConnection(String url) { + final HashMap properties = new HashMap<>(); + properties.put(URL, url); + properties.put(DELAY, "0"); + properties.put(ATTEMPTS, "0"); + properties.put(SUSTAINER_ENABLED, TRUE.toString()); + + this.properties.put(url, properties); + } + + /** + * Sets a string value of a property + * + * @param url + * identifier that corresponds to a connection + * @param key + * key + * @param value + * value + */ + public void setProperty(String url, String key, String value) { + getPropertiesMap(url).put(key, value); + } + + /** + * Gets a value of a property + * + * @param url + * identifier that corresponds to a connection + * @param key + * key + * + * @return value of a propery + */ + public String getProperty(String url, String key) { + return getPropertiesMap(url).get(key); + } + + public String getUrl(String url) { + return getProperty(url, URL); + } + + public void setReConnectionAttempts(String url, int attempts) { + setProperty(url, ATTEMPTS, Integer.toString(attempts)); + } + + public int getReConnectionAttempts(String url) { + return Integer.valueOf(getProperty(url, ATTEMPTS)); + } + + public void setConnectionDelay(String url, int delay) { + setProperty(url, DELAY, Integer.toString(delay)); + } + + public int getConnectionDelay(String url) { + return Integer.valueOf(getProperty(url, DELAY)); + } + + public void enableSustainer(String url) { + setProperty(url, SUSTAINER_ENABLED, TRUE.toString()); + } + + public void disableSustainer(String url) { + setProperty(url, SUSTAINER_ENABLED, FALSE.toString()); + } + + public boolean sustainerEnabled(String url) { + return Boolean.valueOf(getProperty(url, SUSTAINER_ENABLED)); + } + + private Map getPropertiesMap(String url) { + if (properties.containsKey(url)) { + return properties.get(url); + } + + final String error = "Connection is not properly initialized, no properties set. Call 'initializedConnection' first"; + Log.error(getClass(), error); + throw new IllegalStateException(error); + } + + interface Properties { + + /** + * Defines a delay in milliseconds for connection/reconnection + */ + String DELAY = "delay"; + /** + * Defines current number of reconnection attempts + */ + String ATTEMPTS = "attempts"; + /** + * Url of the connection + */ + String URL = "url"; + /** + * Current connection sustainer status + */ + String SUSTAINER_ENABLED = "sustainer-status"; + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcher.java deleted file mode 100644 index 29255694380..00000000000 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcher.java +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -/** - * Dispatches a {@link WebSocketTransmission} messages among registered receivers - * ({@link WebSocketMessageReceiver}) according to WEB SOCKET transmission protocol - * field value. - * - * @author Dmitry Kuleshov - */ -@Singleton -public class WebSocketTransmissionDispatcher { - private final Map receivers; - private final WebSocketTransmissionValidator validator; - private final DtoFactory dtoFactory; - - - @Inject - public WebSocketTransmissionDispatcher(Map receivers, - WebSocketTransmissionValidator validator, - DtoFactory dtoFactory) { - this.receivers = receivers; - this.dtoFactory = dtoFactory; - this.validator = validator; - } - - public void dispatch(String rawTransmission) { - final WebSocketTransmission transmission = dtoFactory.createDtoFromJson(rawTransmission, WebSocketTransmission.class); - validator.validate(transmission); - - final String protocol = transmission.getProtocol(); - final String message = transmission.getMessage(); - - Log.debug(getClass(), "Receiving a web socket transmission. Type: " + protocol + " Message: " + message); - - for (Entry entry : receivers.entrySet()) { - final String protocolCandidate = entry.getKey(); - if (Objects.equals(protocol, protocolCandidate)) { - final WebSocketMessageReceiver receiver = entry.getValue(); - Log.debug(getClass(), "Matching web socket transmission receiver: " + receiver.getClass()); - receiver.receive(message); - - return; - } - } - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java deleted file mode 100644 index a60ef30cafa..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/BasicJsonRpcObjectValidatorTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.util.Map; - -import static java.util.Collections.singleton; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link BasicJsonRpcObjectValidator} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class BasicJsonRpcObjectValidatorTest { - private static final String REGISTERED_TYPE = "registered-type"; - private static final String NOT_REGISTERED_TYPE = "not-registered-type"; - private static final String VALID_JSON = "{ \"name\": \"value\" }"; - private static final String NOT_VALID_JSON = "not a json value"; - @Mock - private Map dispatchers; - - private BasicJsonRpcObjectValidator validator; - - @Mock - private JsonRpcObject object; - - @Before - public void before() { - when(dispatchers.keySet()).thenReturn(singleton(REGISTERED_TYPE)); - - validator = new BasicJsonRpcObjectValidator(dispatchers); - - when(object.getType()).thenReturn(REGISTERED_TYPE); - when(object.getMessage()).thenReturn(VALID_JSON); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionIfTypeIsNull() { - when(object.getType()).thenReturn(null); - - validator.validate(object); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionIfTypeIsEmpty() { - when(object.getType()).thenReturn(""); - - validator.validate(object); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionIfTypeIsNotRegistered() { - when(object.getType()).thenReturn(NOT_REGISTERED_TYPE); - - validator.validate(object); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsNull() { - when(object.getMessage()).thenReturn(null); - - validator.validate(object); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsEmpty() { - when(object.getMessage()).thenReturn(""); - - validator.validate(object); - } - - @Test(expected = IllegalArgumentException.class) - @Ignore - public void shouldThrowExceptionIfMessageIsNotAJson() { - when(object.getMessage()).thenReturn(NOT_VALID_JSON); - - validator.validate(object); - } - - @Test - @Ignore - public void shouldNotThrowExceptionIfObjectIsValid() { - validator.validate(object); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistryTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistryTest.java deleted file mode 100644 index 40c50ee8dcb..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/JsonRpcRequestRegistryTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -/** - * Test for {@link JsonRpcRequestRegistry} - * - * @author Dmitry Kuleshov - */ -public class JsonRpcRequestRegistryTest { - private static final String METHOD_NAME = "method-name"; - private static final int REQUEST_ID = 1; - - private JsonRpcRequestRegistry registry; - - @Before - public void before() { - registry = new JsonRpcRequestRegistry(); - } - - @Test - public void shouldProperlyRegister() { - registry.add(REQUEST_ID, METHOD_NAME); - - assertEquals(METHOD_NAME, registry.extractFor(1)); - } - - @Test - public void shouldProperlyExtract() { - registry.add(REQUEST_ID, METHOD_NAME); - - assertEquals(METHOD_NAME, registry.extractFor(1)); - assertNull(registry.extractFor(1)); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java deleted file mode 100644 index 1d66f113a7e..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcDispatcherTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.ide.dto.DtoFactory; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.util.Map; - -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketJsonRpcDispatcher} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketJsonRpcDispatcherTest { - private static final String MESSAGE = "message"; - private static final String REGISTERED_TYPE = "registered-type"; - private static final String RAW_JSON_RPC_OBJECT_SUBB = "raw-json-rpc-object-subb"; - - @Mock - private Map dispatchers; - @Mock - private JsonRpcObjectValidator validator; - @Mock - private DtoFactory dtoFactory; - @InjectMocks - private WebSocketJsonRpcDispatcher dispatcher; - - @Mock - private JsonRpcObject object; - @Mock - private JsonRpcDispatcher jsonRpcDispatcher; - - @Before - public void before() { - when(dtoFactory.createDtoFromJson(anyString(), any())).thenReturn(object); - when(object.getType()).thenReturn(REGISTERED_TYPE); - when(object.getMessage()).thenReturn(MESSAGE); - - when(dispatchers.entrySet()).thenReturn(singletonMap(REGISTERED_TYPE, jsonRpcDispatcher).entrySet()); - } - - @Test - public void should() { - dispatcher.receive(""); - } - - @Test - public void shouldCreateDtoOnReceive() { - dispatcher.receive(RAW_JSON_RPC_OBJECT_SUBB); - - verify(dtoFactory).createDtoFromJson(eq(RAW_JSON_RPC_OBJECT_SUBB), eq(JsonRpcObject.class)); - } - - @Test - public void shouldValidateOnReceive() { - dispatcher.receive(RAW_JSON_RPC_OBJECT_SUBB); - - verify(validator).validate(eq(object)); - } - - @Test - public void shouldDispatchIfMatchFound() { - dispatcher.receive(RAW_JSON_RPC_OBJECT_SUBB); - - verify(jsonRpcDispatcher).dispatch(MESSAGE); - } - - @Test - public void shouldNotDispatchIfMatchNotFound() { - when(object.getType()).thenReturn("not-"+REGISTERED_TYPE); - - dispatcher.receive(RAW_JSON_RPC_OBJECT_SUBB); - - verify(jsonRpcDispatcher, never()).dispatch(MESSAGE); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializerTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializerTest.java index 8f6eb8fefd8..dd83af6a4a9 100644 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializerTest.java +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcInitializerTest.java @@ -10,46 +10,40 @@ *******************************************************************************/ package org.eclipse.che.ide.jsonrpc.impl; -import org.eclipse.che.ide.websocket.ng.impl.SessionWebSocketInitializer; +import org.eclipse.che.ide.websocket.ng.impl.WebSocketInitializer; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.util.Map; +import java.util.Collections; -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; - /** * Tests for {@link WebSocketJsonRpcInitializer} * * @author Dmitry Kuleshov */ - @RunWith(MockitoJUnitRunner.class) public class WebSocketJsonRpcInitializerTest { @Mock - private SessionWebSocketInitializer webSocketInitializer; + private WebSocketInitializer webSocketInitializer; @InjectMocks private WebSocketJsonRpcInitializer jsonRpcInitializer; @Test - public void shouldRunWebSocketInitializeWithCorrectProperties(){ - final Map map = singletonMap("test-key", "test-value"); - - jsonRpcInitializer.initialize(map); + public void shouldRunInitializeOnInitialize() { + jsonRpcInitializer.initialize("id", Collections.singletonMap("url", "url")); - verify(webSocketInitializer).initialize(eq(map)); + verify(webSocketInitializer).initialize("id", "url"); } @Test - public void shouldRunWebSocketTerminate(){ - jsonRpcInitializer.terminate(); + public void shouldRunTerminateOnTerminate() { + jsonRpcInitializer.terminate("id"); - verify(webSocketInitializer).terminate(); + verify(webSocketInitializer).terminate("id"); } } diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java deleted file mode 100644 index 3e1e9a290a5..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestDispatcherTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static java.util.Collections.emptySet; -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Test for {@link WebSocketJsonRpcRequestDispatcher} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketJsonRpcRequestDispatcherTest { - private static final String MESSAGE = "message"; - - @Mock - private Map receivers; - @Mock - private DtoFactory dtoFactory; - @InjectMocks - private WebSocketJsonRpcRequestDispatcher dispatcher; - - @Mock - private JsonRpcRequest request; - @Mock - private JsonRpcRequestReceiver receiver; - - @Before - public void before() { - when(request.getMethod()).thenReturn(""); - when(dtoFactory.createDtoFromJson(anyString(), any())).thenReturn(request); - when(receivers.entrySet()).thenReturn(emptySet()); - } - - @Test - public void shouldRunDtoFactoryToCreateRequest() { - dispatcher.dispatch(MESSAGE); - } - - @Test - public void shouldRunMatchingReceiver() { - when(request.getMethod()).thenReturn("test-method"); - when(receivers.entrySet()).thenReturn(singletonMap("test-method", receiver).entrySet()); - dispatcher = new WebSocketJsonRpcRequestDispatcher(receivers, dtoFactory); - - dispatcher.dispatch(MESSAGE); - - verify(receiver).receive(request); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java deleted file mode 100644 index cb7a1704aaf..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcRequestTransmitterTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.dto.DtoFactory; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketJsonRpcRequestTransmitter} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketJsonRpcRequestTransmitterTest { - private static final String TYPE = "request"; - private static final int ID = 0; - private static final String METHOD_NAME = "method-name"; - private static final String MESSAGE = "message"; - @Mock - private WebSocketJsonRpcTransmitter transmitter; - @Mock - private DtoFactory dtoFactory; - @Mock - private JsonRpcRequestRegistry requestRegistry; - @InjectMocks - private WebSocketJsonRpcRequestTransmitter jsonRpcTransmitter; - - @Mock - private WebSocketTransmission transmission; - @Mock - private JsonRpcRequest request; - - @Before - public void before() { - when(request.getId()).thenReturn(ID); - when(request.getMethod()).thenReturn(METHOD_NAME); - when(request.toString()).thenReturn(MESSAGE); - - when(transmission.withProtocol(anyString())).thenReturn(transmission); - when(transmission.withMessage(anyString())).thenReturn(transmission); - - when(dtoFactory.createDto(WebSocketTransmission.class)).thenReturn(transmission); - } - - @Test - public void shouldAddMethodToRequestRegistry() { - jsonRpcTransmitter.transmit(request); - - verify(requestRegistry).add(ID, METHOD_NAME); - } - - @Test - public void shouldRunWebSocketTransmitter() { - jsonRpcTransmitter.transmit(request); - - verify(transmitter).transmit(TYPE, MESSAGE); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java deleted file mode 100644 index f8314b05dad..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseDispatcherTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcResponseReceiver; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.util.Map; - -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Test for {@link WebSocketJsonRpcResponseDispatcher} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketJsonRpcResponseDispatcherTest { - private static final String METHOD_NAME = "test-method"; - private static final String MESSAGE = "message"; - private static final int RESPONSE_ID = 0; - - @Mock - private Map receivers; - @Mock - private DtoFactory dtoFactory; - @Mock - private JsonRpcRequestRegistry registry; - @InjectMocks - private WebSocketJsonRpcResponseDispatcher dispatcher; - - @Mock - private JsonRpcResponse response; - @Mock - private JsonRpcResponseReceiver receiver; - - @Before - public void before() { - when(response.getId()).thenReturn(RESPONSE_ID); - - when(dtoFactory.createDtoFromJson(anyString(), any())).thenReturn(response); - - when(registry.extractFor(RESPONSE_ID)).thenReturn(METHOD_NAME); - - when(receivers.entrySet()).thenReturn(singletonMap(METHOD_NAME, receiver).entrySet()); - - } - - @Test - public void shouldRunDtoFactoryToCreateRequest() { - dispatcher.dispatch(MESSAGE); - } - - @Test - public void shouldRunMatchingReceiver() { - dispatcher.dispatch(MESSAGE); - - verify(receiver).receive(response); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java deleted file mode 100644 index a0cf2e1f720..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcResponseTransmitterTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.dto.DtoFactory; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketJsonRpcResponseTransmitter} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketJsonRpcResponseTransmitterTest { - private static final String MESSAGE = "message"; - private static final String TYPE = "response"; - - @Mock - private WebSocketJsonRpcTransmitter transmitter; - @Mock - private DtoFactory dtoFactory; - @InjectMocks - private WebSocketJsonRpcResponseTransmitter jsonRpcTransmitter; - - @Mock - private WebSocketTransmission transmission; - @Mock - private JsonRpcResponse response; - - @Before - public void before() { - when(response.toString()).thenReturn(MESSAGE); - - when(transmission.withProtocol(anyString())).thenReturn(transmission); - when(transmission.withMessage(anyString())).thenReturn(transmission); - - when(dtoFactory.createDto(WebSocketTransmission.class)).thenReturn(transmission); - } - - @Test - public void shouldRunWebSocketTransmitter() { - jsonRpcTransmitter.transmit(response); - - verify(transmitter).transmit(TYPE, MESSAGE); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java deleted file mode 100644 index 93b8c27c23f..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/jsonrpc/impl/WebSocketJsonRpcTransmitterTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.jsonrpc.impl; - -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.websocket.ng.WebSocketMessageTransmitter; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketJsonRpcTransmitter} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketJsonRpcTransmitterTest { - private static final String PROTOCOL = "jsonrpc-2.0"; - private static final String MESSAGE = "message"; - private static final String TYPE = "registered-type"; - @Mock - private WebSocketMessageTransmitter transmitter; - @Mock - private DtoFactory dtoFactory; - @Mock - private JsonRpcObjectValidator validator; - @InjectMocks - private WebSocketJsonRpcTransmitter jsonRpcTransmitter; - - @Mock - private JsonRpcObject object; - - @Before - public void before() { - when(dtoFactory.createDto(eq(JsonRpcObject.class))).thenReturn(object); - when(object.toString()).thenReturn(MESSAGE); - when(object.withMessage(anyString())).thenReturn(object); - when(object.withType(anyString())).thenReturn(object); - } - - @Test - public void shouldCreateJsonRpcObject() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE); - - verify(dtoFactory).createDto(JsonRpcObject.class); - } - - @Test - public void shouldProperlySetJsonRpcObjectProperties() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE); - - verify(object).withType(TYPE); - verify(object).withMessage(MESSAGE); - } - - @Test - public void shouldValidateJsonRpcObject() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE); - - verify(validator).validate(object); - } - - @Test - public void shouldTransmitJsonRpcObject() { - jsonRpcTransmitter.transmit(TYPE, MESSAGE); - - verify(transmitter).transmit(PROTOCOL, MESSAGE); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpointTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpointTest.java index d1925f9a3a9..07660c2d017 100644 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpointTest.java +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketEndpointTest.java @@ -10,13 +10,16 @@ *******************************************************************************/ package org.eclipse.che.ide.websocket.ng.impl; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; -import static org.mockito.Matchers.eq; +import static org.junit.Assert.*; import static org.mockito.Mockito.verify; /** @@ -26,42 +29,41 @@ */ @RunWith(MockitoJUnitRunner.class) public class BasicWebSocketEndpointTest { - private static final String MESSAGE = "message"; - @Mock - private WebSocketConnectionSustainer sustainer; + private WebSocketConnectionSustainer sustainer; @Mock - private WebSocketTransmissionDispatcher dispatcher; + private MessagesReSender reSender; @Mock - private PendingMessagesReSender reSender; + private WebSocketDispatcher dispatcher; @InjectMocks - private BasicWebSocketEndpoint endpoint; + private BasicWebSocketEndpoint endpoint; @Test - public void shouldResetSustainerOnOpen() { - endpoint.onOpen(); + public void shouldResetSustainerOnOpen(){ + endpoint.onOpen("url"); - verify(sustainer).reset(); + verify(sustainer).reset("url"); } @Test - public void shouldResendMessagesOnOpen() { - endpoint.onOpen(); + public void shouldReSendMessagesOnOpen(){ + endpoint.onOpen("url"); - verify(reSender).resend(); + verify(reSender).reSend("url"); } @Test - public void shouldSustainSessionOnClose() { - endpoint.onClose(); + public void shouldSustainOnClose(){ + endpoint.onClose("url"); - verify(sustainer).sustain(); + verify(sustainer).sustain("url"); } @Test - public void shouldRunReceiverOnMessage() { - endpoint.onMessage(MESSAGE); + public void shouldDispatchOnMessage(){ + endpoint.onMessage("url", "message"); - verify(dispatcher).dispatch(eq(MESSAGE)); + verify(dispatcher).dispatch("url", "message"); } + } diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitterTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitterTest.java index 8ea594d375e..9b555286c55 100644 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitterTest.java +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketMessageTransmitterTest.java @@ -10,8 +10,7 @@ *******************************************************************************/ package org.eclipse.che.ide.websocket.ng.impl; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.dto.DtoFactory; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -19,7 +18,6 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; @@ -33,58 +31,51 @@ */ @RunWith(MockitoJUnitRunner.class) public class BasicWebSocketMessageTransmitterTest { - private static final String MESSAGE = "message"; - private static final String PROTOCOL = "protocol"; - - @Mock - private WebSocketConnection session; @Mock - private PendingMessagesReSender reSender; + private WebSocketConnectionManager connectionManager; @Mock - private WebSocketTransmissionValidator validator; + private MessagesReSender reSender; @Mock - private DtoFactory dtoFactory; + private UrlResolver urlResolver; @InjectMocks private BasicWebSocketMessageTransmitter transmitter; - @Mock - private WebSocketTransmission transmission; - @Before - public void before() { - when(dtoFactory.createDto(eq(WebSocketTransmission.class))).thenReturn(transmission); - - when(transmission.getMessage()).thenReturn(MESSAGE); - when(transmission.withMessage(anyString())).thenReturn(transmission); - when(transmission.withProtocol(anyString())).thenReturn(transmission); + public void setUp() throws Exception { + when(urlResolver.getUrl("endpointId")).thenReturn("url"); } @Test - public void shouldValidateTransmission() { - when(session.isOpen()).thenReturn(true); + public void shouldResolveUrlOnTransmit() { + transmitter.transmit("endpointId", "message"); + + verify(urlResolver).getUrl("endpointId"); + } - transmitter.transmit(PROTOCOL, MESSAGE); + @Test + public void shouldCheckIfConnectionIsOpenOnTransmit() { + transmitter.transmit("endpointId", "message"); - verify(validator).validate(transmission); + verify(connectionManager).isConnectionOpen(anyString()); } @Test - public void shouldSendMessageIfSessionIsOpen() { - when(session.isOpen()).thenReturn(true); + public void shouldSendMessageIfConnectionIsOpenOnTransmit() { + when(connectionManager.isConnectionOpen(anyString())).thenReturn(true); - transmitter.transmit(PROTOCOL, MESSAGE); + transmitter.transmit("endpointId", "message"); - verify(session).send(transmission); - verify(reSender, never()).add(any(WebSocketTransmission.class)); + verify(connectionManager).sendMessage("url", "message"); + verify(reSender, never()).add("url", "message"); } @Test - public void shouldAddMessageToPendingIfSessionIsNotOpened() { - when(session.isOpen()).thenReturn(false); + public void shouldAddMessageToReSenderIfConnectionIsNotOpenOnTransmit() { + when(connectionManager.isConnectionOpen(anyString())).thenReturn(false); - transmitter.transmit(PROTOCOL, MESSAGE); + transmitter.transmit("endpointId", "message"); - verify(session, never()).send(any(WebSocketTransmission.class)); - verify(reSender).add(transmission); + verify(connectionManager, never()).sendMessage("url", "message"); + verify(reSender).add("url", "message"); } } diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidatorTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidatorTest.java deleted file mode 100644 index 330f527b7a2..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/BasicWebSocketTransmissionValidatorTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.eclipse.che.api.core.websocket.WebSocketMessageReceiver; -import org.eclipse.che.api.core.websocket.impl.BasicWebSocketTransmissionValidator; -import org.eclipse.che.api.core.websocket.impl.WebSocketTransmissionValidator; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.testng.annotations.Test; - -import java.util.Collections; -import java.util.Map; - -import static org.mockito.Mockito.when; - - -/** - * Tests for {@link BasicWebSocketTransmissionValidator} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -class BasicWebSocketTransmissionValidatorTest { - private static final String VALID_JSON = "{ \"name\": \"value\" }"; - private static final String NOT_VALID_JSON = "not valid json"; - private static final String REGISTERED_PROTOCOL = "registered-protocol"; - private static final String NOT_REGISTERED_PROTOCOL = "not-registered-protocol"; - @Mock - private Map receivers; - @InjectMocks - private WebSocketTransmissionValidator validator; - - @Mock - private WebSocketTransmission message; - - @Before - public void before() { - when(receivers.keySet()).thenReturn(Collections.singleton(REGISTERED_PROTOCOL)); - } - - @Before - public void beforeMethod() { - when(message.getProtocol()).thenReturn(REGISTERED_PROTOCOL); - when(message.getMessage()).thenReturn(VALID_JSON); - } - - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfProtocolIsNull() { - when(message.getProtocol()).thenReturn(null); - - validator.validate(message); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfProtocolIsEmpty() { - when(message.getProtocol()).thenReturn(""); - - validator.validate(message); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsNull() { - when(message.getMessage()).thenReturn(null); - - validator.validate(message); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsEmpty() { - when(message.getMessage()).thenReturn(""); - - validator.validate(message); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfProtocolIsNotRegistered() { - when(message.getProtocol()).thenReturn(NOT_REGISTERED_PROTOCOL); - - validator.validate(message); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldThrowExceptionIfMessageIsNotValidJson() { - when(message.getMessage()).thenReturn(NOT_VALID_JSON); - - validator.validate(message); - } - - @Test - public void validateTransmissionShouldPassForValidWebSocketMessage() { - validator.validate(message); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSenderTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSenderTest.java new file mode 100644 index 00000000000..60d9cd61d7a --- /dev/null +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/MessagesReSenderTest.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link MessagesReSender} + * + * @author Dmitry Kuleshov + */ +@RunWith(MockitoJUnitRunner.class) +public class MessagesReSenderTest { + @Mock + private WebSocketConnectionManager connectionManager; + @InjectMocks + private MessagesReSender reSender; + + @Test + public void shouldResendAllMessages() { + reSender.add("url", "1"); + reSender.add("url", "2"); + reSender.add("url", "3"); + + when(connectionManager.isConnectionOpen("url")).thenReturn(true); + + reSender.reSend("url"); + verify(connectionManager, times(3)).sendMessage(eq("url"), anyString()); + } + + @Test + public void shouldStopSendingIfSessionIsClosed() { + reSender.add("url", "1"); + reSender.add("url", "2"); + reSender.add("url", "3"); + + final int[] i = {0}; + when(connectionManager.isConnectionOpen("url")).thenAnswer(invocation -> (i[0]++ <= 1)); + reSender.reSend("url"); + verify(connectionManager, times(2)).sendMessage(eq("url"), anyString()); + + when(connectionManager.isConnectionOpen("url")).thenReturn(true); + reSender.reSend("url"); + + verify(connectionManager, times(3)).sendMessage(eq("url"), anyString()); + } +} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSenderTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSenderTest.java deleted file mode 100644 index 62b554d21fb..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/PendingMessagesReSenderTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link PendingMessagesReSender} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class PendingMessagesReSenderTest { - @Mock - private WebSocketConnection connection; - @InjectMocks - private PendingMessagesReSender reSender; - - @Test - public void shouldResendAllMessages() { - reSender.add(mock(WebSocketTransmission.class)); - reSender.add(mock(WebSocketTransmission.class)); - reSender.add(mock(WebSocketTransmission.class)); - - when(connection.isOpen()).thenReturn(true); - - reSender.resend(); - verify(connection, times(3)).send(any(WebSocketTransmission.class)); - - reSender.resend(); - verify(connection, times(3)).send(any(WebSocketTransmission.class)); - - - } - - @Test - public void shouldStopSendingIfSessionIsClosed() { - reSender.add(mock(WebSocketTransmission.class)); - reSender.add(mock(WebSocketTransmission.class)); - reSender.add(mock(WebSocketTransmission.class)); - - final int[] i = {0}; - when(connection.isOpen()).thenAnswer(invocation -> (i[0]++ <= 1)); - reSender.resend(); - verify(connection, times(2)).send(any(WebSocketTransmission.class)); - - when(connection.isOpen()).thenReturn(true); - reSender.resend(); - - verify(connection, times(3)).send(any(WebSocketTransmission.class)); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializerTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializerTest.java deleted file mode 100644 index 661ad1c1a6a..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/SessionWebSocketInitializerTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.util.Collections; - -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link SessionWebSocketInitializer} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class SessionWebSocketInitializerTest { - @Mock - private WebSocketConnection connection; - @Mock - private WebSocketConnectionSustainer sustainer; - @InjectMocks - private SessionWebSocketInitializer initializer; - - @Before - public void before(){ - when(connection.initialize(any())).thenReturn(connection); - } - - @Test - public void shouldInitializeControllerOnInitialize() { - initializer.initialize(singletonMap("url", "url-value")); - - verify(connection).initialize((eq("url-value"))); - } - - @Test - public void shouldOpenConnectionOnInitialize() { - initializer.initialize(emptyMap()); - - verify(connection).open(WebSocketConnection.IMMEDIATELY); - } - - @Test - public void shouldEnableSustainerOnInitialize() { - initializer.initialize(emptyMap()); - - verify(sustainer).enable(); - } - - @Test - public void shouldCloseSessionOnTerminate() { - initializer.terminate(); - - verify(connection).close(); - } - - @Test - public void shouldDisableSustainerOnInitialize() { - initializer.terminate(); - - verify(sustainer).disable(); - } - -} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionValidator.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolverTest.java similarity index 52% rename from ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionValidator.java rename to ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolverTest.java index ddce4e577bb..afad667141c 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionValidator.java +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/UrlResolverTest.java @@ -10,15 +10,33 @@ *******************************************************************************/ package org.eclipse.che.ide.websocket.ng.impl; -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** - * It is used to make sure that {@link WebSocketTransmission} is a valid entity. - * Implementation of this interface must be called before any other operation - * is performed to avoid any kind of inconsistency. + * Tests for {@link UrlResolver} * * @author Dmitry Kuleshov */ -public interface WebSocketTransmissionValidator { - void validate(WebSocketTransmission message); +public class UrlResolverTest { + private UrlResolver urlResolver = new UrlResolver(); + + @Test + public void shouldResolveUrl(){ + urlResolver.setMapping("id", "url"); + + final String id = urlResolver.resolve("url"); + + assertEquals("id", id); + } + + @Test + public void shouldResolveId(){ + urlResolver.setMapping("id", "url"); + + final String url = urlResolver.getUrl("id"); + + assertEquals("url", url); + } } diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManagerTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManagerTest.java new file mode 100644 index 00000000000..9efa2d1c68a --- /dev/null +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionManagerTest.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link WebSocketConnectionManager} + * + * @author Dmitry Kuleshov + */ +@RunWith(MockitoJUnitRunner.class) +public class WebSocketConnectionManagerTest { + @Mock + private WebSocketFactory webSocketFactory; + @InjectMocks + private WebSocketConnectionManager connectionManager; + + @Mock + private WebSocketConnection connection; + + @Before + public void setUp() throws Exception { + when(webSocketFactory.create("url")).thenReturn(connection); + + connectionManager.initializeConnection("url"); + } + + @Test + public void shouldCreateConnectionOnInitialize() { + verify(webSocketFactory).create("url"); + } + + @Test + public void shouldOpenOnEstablishConnection(){ + connectionManager.establishConnection("url"); + + verify(connection).open(); + } + + @Test + public void shouldCloseOnCloseConnection(){ + connectionManager.closeConnection("url"); + + verify(connection).close(); + } + + @Test + public void shouldSendOnSendMessage(){ + connectionManager.sendMessage("url", "message"); + + verify(connection).send("message"); + } + + @Test + public void shouldReturnTrueWhenConnectionIsOpened(){ + when(connection.isOpen()).thenReturn(true); + + final boolean opened = connectionManager.isConnectionOpen("url"); + + assertTrue(opened); + + } + + @Test + public void shouldReturnFalseWhenConnectionIsClosed(){ + when(connection.isOpen()).thenReturn(false); + + final boolean opened = connectionManager.isConnectionOpen("url"); + + assertFalse(opened); + } +} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainerTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainerTest.java index 41719a6f062..37eb06c17c7 100644 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainerTest.java +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionSustainerTest.java @@ -10,18 +10,17 @@ *******************************************************************************/ package org.eclipse.che.ide.websocket.ng.impl; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; -import static java.util.stream.IntStream.range; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; - +import static org.mockito.Mockito.when; /** * Tests for {@link WebSocketConnectionSustainer} @@ -30,42 +29,125 @@ */ @RunWith(MockitoJUnitRunner.class) public class WebSocketConnectionSustainerTest { - @Mock - private WebSocketConnection connection; - @Spy + private WebSocketConnectionManager connectionManager; + @Mock + private WebSocketPropertyManager propertyManager; @InjectMocks private WebSocketConnectionSustainer sustainer; @Before - public void before() { - sustainer.enable(); + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void shouldGetReConnectionAttemptsOnReset() { + sustainer.reset("url"); + + verify(propertyManager).getReConnectionAttempts("url"); + } + + @Test + public void shouldSetReConnectionAttemptsOnReset() { + sustainer.reset("url"); + + verify(propertyManager).setReConnectionAttempts("url", 0); } @Test - public void shouldDisableSustainerOnExceedingLimits() { - range(0, 5).forEach(value -> sustainer.sustain()); + public void shouldGetReConnectionAttemptsOnSustain() { + sustainer.sustain("url"); - sustainer.sustain(); + verify(propertyManager).getReConnectionAttempts("url"); - verify(sustainer).disable(); } @Test - public void shouldResetAttemptsOnSustainerReset() { - range(0, 5).forEach(value -> sustainer.sustain()); + public void shouldDisableSustainerOnExceedingTheLimitOfAttepts(){ + when(propertyManager.getReConnectionAttempts("url")).thenReturn(10); - sustainer.reset(); + sustainer.sustain("url"); - range(0, 5).forEach(value -> sustainer.sustain()); + verify(propertyManager).disableSustainer("url"); + } - verify(sustainer, never()).disable(); + @Test + public void shouldNotDisableSustainerIfNotExceededTheLimitOfAttepts(){ + when(propertyManager.getReConnectionAttempts("url")).thenReturn(0); + + sustainer.sustain("url"); + + verify(propertyManager, never()).disableSustainer("url"); } @Test - public void shouldOpenConnectionOnSustain() { - sustainer.sustain(); + public void shouldCheckIfSustainerIsEnabled(){ + sustainer.sustain("url"); + + verify(propertyManager).sustainerEnabled("url"); + } + + @Test + public void shouldProperlySetReconnectionAttemptsWhenSustainerIsEnabled(){ + when(propertyManager.getReConnectionAttempts("url")).thenReturn(0); + when(propertyManager.sustainerEnabled("url")).thenReturn(true); + + sustainer.sustain("url"); + + verify(propertyManager).setReConnectionAttempts("url", 1); + } + + @Test + public void shouldNotSetReconnectionAttemptsWhenSustainerIsDisabled(){ + when(propertyManager.sustainerEnabled("url")).thenReturn(false); + + sustainer.sustain("url"); + + verify(propertyManager, never()).setReConnectionAttempts("url", 1); + } + + + @Test + public void shouldProperlySetConnectionDelayWhenSustainerIsEnabled(){ + when(propertyManager.getReConnectionAttempts("url")).thenReturn(0); + + when(propertyManager.sustainerEnabled("url")).thenReturn(true); + + sustainer.sustain("url"); + + verify(propertyManager).setConnectionDelay("url", 1_000); + } + + @Test + public void shouldNotSetConnectionDelayWhenSustainerIsDisabled(){ + when(propertyManager.sustainerEnabled("url")).thenReturn(false); + + sustainer.sustain("url"); + + verify(propertyManager, never()).setConnectionDelay("url", 1_000); + } + + @Test + public void shouldRunEstablishConnectionWhenSustainerIsEnabled(){ + when(propertyManager.sustainerEnabled("url")).thenReturn(true); + + sustainer.sustain("url"); + + verify(connectionManager).establishConnection("url"); + } + + @Test + public void shouldNotRunConnectionWhenSustainerIsDisabled(){ + when(propertyManager.sustainerEnabled("url")).thenReturn(false); + + sustainer.sustain("url"); - verify(connection).open(500); + verify(connectionManager, never()).establishConnection("url"); } } diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionTest.java deleted file mode 100644 index 76c712df79a..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketConnectionTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link WebSocketConnection} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketConnectionTest { - private static final String URL = "url"; - private static final int DELAY = 0; - private static final String MESSAGE = "message"; - @Mock - private WebSocketCreator connector; - @InjectMocks - private WebSocketConnection connection; - - @Mock - private WebSocket webSocket; - - @Before - public void before() { - when(connector.create(anyString(), any())).thenReturn(webSocket); - - connection.initialize(URL); - connection.open(DELAY); - } - - @Test(expected = IllegalStateException.class) - public void shouldThrowExceptionIfNoUrlIsSetWhenTryToOpen() { - connection.initialize(null); - connection.open(DELAY); - } - - @Test - public void shouldCreateConnectionOnOpen() { - verify(connector).create(URL, DELAY); - } - - @Test - public void shouldOpenConnectionOnOpen() { - verify(webSocket).open(); - } - - @Test - public void shouldCloseConnectionOnClose() { - connection.close(); - - verify(webSocket).close(); - } - - @Test - public void shouldSendMessageOnSend() { - final WebSocketTransmission message = mock(WebSocketTransmission.class); - when(message.toString()).thenReturn(MESSAGE); - - connection.send(message); - - verify(webSocket).send(MESSAGE); - } - - - @Test - public void shouldBeOpenWhenConnectionIsOpen() { - when(webSocket.isOpen()).thenReturn(true); - - assertTrue(connection.isOpen()); - - verify(webSocket).isOpen(); - } - - @Test - public void shouldBeNotOpenWhenConnectionIsNull() { - when(connector.create(anyString(), any())).thenReturn(null); - new WebSocketConnection(connector).isOpen(); - - assertFalse(connection.isOpen()); - } - - @Test - public void shouldBeNotOpenWhenConnectionIsNotOpen() { - when(webSocket.isOpen()).thenReturn(false); - - assertFalse(connection.isOpen()); - - verify(webSocket).isOpen(); - } -} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcherTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcherTest.java new file mode 100644 index 00000000000..e566cf458e2 --- /dev/null +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketDispatcherTest.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link WebSocketDispatcher} + * + * @author Dmitry Kuleshov + */ + +@RunWith(MockitoJUnitRunner.class) +public class WebSocketDispatcherTest { + @Mock + private WebSocketMessageReceiver receiver; + @Mock + private UrlResolver urlResolver; + @InjectMocks + private WebSocketDispatcher dispatcher; + + @Before + public void setUp() throws Exception { + when(urlResolver.resolve("url")).thenReturn("id"); + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void shouldResolveUrlOnDispatch() { + dispatcher.dispatch("url", "message"); + + verify(urlResolver).resolve("url"); + } + + @Test + public void shouldRunReceiveOnDispatch(){ + dispatcher.dispatch("url", "message"); + + verify(receiver).receive("id", "message"); + } + +} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializerTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializerTest.java new file mode 100644 index 00000000000..7ef9eff3b2f --- /dev/null +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketInitializerTest.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link WebSocketInitializer} + * + * @author Dmitry Kuleshov + */ +@RunWith(MockitoJUnitRunner.class) +public class WebSocketInitializerTest { + @Mock + private WebSocketConnectionManager connectionManager; + @Mock + private WebSocketPropertyManager propertyManager; + @Mock + private UrlResolver urlResolver; + @InjectMocks + private WebSocketInitializer initializer; + + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void shouldSetUrlMappingOnInitialize() { + initializer.initialize("id", "url"); + + verify(urlResolver).setMapping("id", "url"); + } + + @Test + public void shouldRunConnectionManagerInitializeConnectionOnInitialize() { + initializer.initialize("id", "url"); + + verify(connectionManager).initializeConnection("url"); + } + + @Test + public void shouldRunPropertyManagerInitializeConnectionOnInitialize() { + initializer.initialize("id", "url"); + + verify(propertyManager).initializeConnection("url"); + } + + @Test + public void shouldRunEstablishConnectionOnInitialize() { + initializer.initialize("id", "url"); + + verify(connectionManager).establishConnection("url"); + } + + @Test + public void shouldGetUrlOnTerminate(){ + when(urlResolver.removeMapping("id")).thenReturn("url"); + + initializer.terminate("id"); + + verify(urlResolver).removeMapping("id"); + } + + @Test + public void shouldDisableSustainerOnTerminate(){ + when(urlResolver.removeMapping("id")).thenReturn("url"); + + initializer.terminate("id"); + + verify(propertyManager).disableSustainer("url"); + } + + @Test + public void shouldCloseConnectionOnTerminate(){ + when(urlResolver.removeMapping("id")).thenReturn("url"); + + initializer.terminate("id"); + + verify(connectionManager).closeConnection("url"); + } +} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManagerTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManagerTest.java new file mode 100644 index 00000000000..8f270dbf4c5 --- /dev/null +++ b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketPropertyManagerTest.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.websocket.ng.impl; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Test for {@link WebSocketPropertyManager} + * + * @author Dmitry Kuleshov + */ +@RunWith(MockitoJUnitRunner.class) +public class WebSocketPropertyManagerTest { + @InjectMocks + private WebSocketPropertyManager propertyManager; + + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void shouldInitializeDefaultDelayOnInitialize() { + propertyManager.initializeConnection("url"); + + final int delay = propertyManager.getConnectionDelay("url"); + assertEquals(0, delay); + } + + @Test + public void shouldInitializeDefaultAttemptsOnInitialize() { + propertyManager.initializeConnection("url"); + + final int attempts = propertyManager.getReConnectionAttempts("url"); + + assertEquals(0, attempts); + } + + @Test + public void shouldInitializeDefaultUrlOnInitialize() { + propertyManager.initializeConnection("url"); + + final String url = propertyManager.getUrl("url"); + + assertEquals("url", url); + } + + @Test + public void shouldInitializeDefaultSustainerStatusOnInitialize() { + propertyManager.initializeConnection("url"); + + final boolean sustainerEnabled = propertyManager.sustainerEnabled("url"); + + assertTrue(sustainerEnabled); + } +} diff --git a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcherTest.java b/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcherTest.java deleted file mode 100644 index 1a233b7c589..00000000000 --- a/ide/commons-gwt/src/test/java/org/eclipse/che/ide/websocket/ng/impl/WebSocketTransmissionDispatcherTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.websocket.ng.impl; - -import org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.websocket.ng.WebSocketMessageReceiver; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.util.Map; - -import static java.util.Collections.singletonMap; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Test for {@link WebSocketTransmissionDispatcher} - * - * @author Dmitry Kuleshov - */ -@RunWith(MockitoJUnitRunner.class) -public class WebSocketTransmissionDispatcherTest { - private static final String REGISTERED_PROTOCOL = "registered-protocol"; - private static final String NOT_REGISTERED_PROTOCOL = "not-registered-protocol"; - private static final String MESSAGE = "message"; - private static final String RAW_TRANSMISSION = "raw_transmission"; - @Mock - private Map receivers; - @Mock - private WebSocketTransmissionValidator validator; - @Mock - private DtoFactory dtoFactory; - @InjectMocks - private WebSocketTransmissionDispatcher dispatcher; - - @Mock - private WebSocketTransmission transmission; - @Mock - private WebSocketMessageReceiver receiver; - - @Before - public void before() { - when(dtoFactory.createDtoFromJson(any(), eq(WebSocketTransmission.class))).thenReturn(transmission); - - when(transmission.getProtocol()).thenReturn(REGISTERED_PROTOCOL); - when(transmission.getMessage()).thenReturn(MESSAGE); - - when(receivers.entrySet()).thenReturn(singletonMap(REGISTERED_PROTOCOL, receiver).entrySet()); - } - - @Test - public void shouldCreateWebSocketTransmission() { - dispatcher.dispatch(RAW_TRANSMISSION); - - verify(dtoFactory).createDtoFromJson(RAW_TRANSMISSION, WebSocketTransmission.class); - } - - @Test - public void shouldValidateWebSocketTransmission() { - dispatcher.dispatch(RAW_TRANSMISSION); - - verify(validator).validate(transmission); - } - - @Test - public void shouldRunReceiverOnMatch() { - dispatcher.dispatch(RAW_TRANSMISSION); - - verify(receiver).receive(MESSAGE); - } - - @Test - public void shouldNotRunReceiverOnNoMatch() { - when(receivers.entrySet()).thenReturn(singletonMap(NOT_REGISTERED_PROTOCOL, receiver).entrySet()); - - dispatcher.dispatch(RAW_TRANSMISSION); - - verify(receiver, never()).receive(MESSAGE); - } -} diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitCheckoutStatusNotificationReceiver.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitCheckoutStatusNotificationHandler.java similarity index 76% rename from plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitCheckoutStatusNotificationReceiver.java rename to plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitCheckoutStatusNotificationHandler.java index 7f24bc20f54..c978e28946f 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitCheckoutStatusNotificationReceiver.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitCheckoutStatusNotificationHandler.java @@ -11,12 +11,10 @@ package org.eclipse.che.ide.ext.git.client; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; import org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto; import org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto.Type; import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; +import org.eclipse.che.ide.jsonrpc.RequestHandler; import org.eclipse.che.ide.util.loging.Log; import javax.inject.Inject; @@ -35,24 +33,19 @@ * @author Dmitry Kuleshov */ @Singleton -public class GitCheckoutStatusNotificationReceiver implements JsonRpcRequestReceiver { - private final DtoFactory dtoFactory; - +public class GitCheckoutStatusNotificationHandler extends RequestHandler { private final Provider notificationManagerProvider; @Inject - public GitCheckoutStatusNotificationReceiver(DtoFactory dtoFactory, Provider notificationManagerProvider) { - this.dtoFactory = dtoFactory; + public GitCheckoutStatusNotificationHandler(Provider notificationManagerProvider) { + super(GitCheckoutEventDto.class, Void.class); this.notificationManagerProvider = notificationManagerProvider; } @Override - public void receive(JsonRpcRequest request) { - final String params = request.getParams(); - final GitCheckoutEventDto gitCheckoutEventDto = dtoFactory.createDtoFromJson(params, GitCheckoutEventDto.class); - - final Type type = gitCheckoutEventDto.getType(); - final String name = gitCheckoutEventDto.getName(); + public void handleNotification(String endpointId, GitCheckoutEventDto dto) { + final Type type = dto.getType(); + final String name = dto.getName(); switch (type) { case BRANCH: { diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/inject/GitGinModule.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/inject/GitGinModule.java index 02513fd91e7..adf66277ddc 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/inject/GitGinModule.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/inject/GitGinModule.java @@ -19,7 +19,7 @@ import org.eclipse.che.ide.api.extension.ExtensionGinModule; import org.eclipse.che.ide.api.preferences.PreferencePagePresenter; import org.eclipse.che.ide.api.project.wizard.ImportWizardRegistrar; -import org.eclipse.che.ide.ext.git.client.GitCheckoutStatusNotificationReceiver; +import org.eclipse.che.ide.ext.git.client.GitCheckoutStatusNotificationHandler; import org.eclipse.che.ide.ext.git.client.add.AddToIndexView; import org.eclipse.che.ide.ext.git.client.add.AddToIndexViewImpl; import org.eclipse.che.ide.ext.git.client.branch.BranchView; @@ -59,11 +59,12 @@ import org.eclipse.che.ide.ext.git.client.reset.commit.ResetToCommitViewImpl; import org.eclipse.che.ide.ext.git.client.reset.files.ResetFilesView; import org.eclipse.che.ide.ext.git.client.reset.files.ResetFilesViewImpl; -import org.eclipse.che.ide.jsonrpc.JsonRpcRequestReceiver; +import org.eclipse.che.ide.jsonrpc.RequestHandler; /** @author Andrey Plotnikov */ @ExtensionGinModule public class GitGinModule extends AbstractGinModule { + /** {@inheritDoc} */ @Override protected void configure() { @@ -91,8 +92,12 @@ protected void configure() { install(new GinFactoryModuleBuilder().implement(GitOutputConsole.class, GitOutputConsolePresenter.class) .build(GitOutputConsoleFactory.class)); - GinMapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class) + configureGitCheckoutNotifications(); + } + + private void configureGitCheckoutNotifications() { + GinMapBinder.newMapBinder(binder(), String.class, RequestHandler.class) .addBinding("event:git-checkout") - .to(GitCheckoutStatusNotificationReceiver.class); + .to(GitCheckoutStatusNotificationHandler.class); } } diff --git a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitCheckoutHiEventDetector.java b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitCheckoutHiEventDetector.java index 83867836970..f816579ddb3 100644 --- a/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitCheckoutHiEventDetector.java +++ b/wsagent/che-core-api-git/src/main/java/org/eclipse/che/api/git/GitCheckoutHiEventDetector.java @@ -14,8 +14,7 @@ import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestTransmitter; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; +import org.eclipse.che.api.core.jsonrpc.RequestTransmitter; import org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto; import org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto.Type; import org.eclipse.che.api.vfs.Path; @@ -61,17 +60,15 @@ public class GitCheckoutHiEventDetector implements HiEventDetector { private static final Logger LOG = getLogger(GitCheckoutHiEventDetector.class); - private static final String GIT_DIR = ".git"; - private static final String HEAD_FILE = "HEAD"; - private static final Pattern PATTERN = compile("ref: refs/heads/"); + private static final String GIT_DIR = ".git"; + private static final String HEAD_FILE = "HEAD"; + private static final Pattern PATTERN = compile("ref: refs/heads/"); private final VirtualFileSystemProvider virtualFileSystemProvider; - - private final JsonRpcRequestTransmitter transmitter; + private final RequestTransmitter transmitter; @Inject - public GitCheckoutHiEventDetector(VirtualFileSystemProvider virtualFileSystemProvider, - JsonRpcRequestTransmitter transmitter) { + public GitCheckoutHiEventDetector(VirtualFileSystemProvider virtualFileSystemProvider, RequestTransmitter transmitter) { this.virtualFileSystemProvider = virtualFileSystemProvider; this.transmitter = transmitter; } @@ -93,10 +90,7 @@ public Optional> detect(EventTreeNode eventTreeNode final Type type = getType(fileContent); final String name = getName(fileContent, type); - transmitter.transmit(newDto(JsonRpcRequest.class) - .withMethod("event:git-checkout") - .withJsonrpc("2.0") - .withParams(newDto(GitCheckoutEventDto.class).withName(name).withType(type).toString())); + transmitter.broadcast("event:git-checkout", newDto(GitCheckoutEventDto.class).withName(name).withType(type)); } } diff --git a/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitCheckoutHiEventDetectorTest.java b/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitCheckoutHiEventDetectorTest.java index 0f5d316b28a..93296b62ce2 100644 --- a/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitCheckoutHiEventDetectorTest.java +++ b/wsagent/che-core-api-git/src/test/java/org/eclipse/che/api/git/GitCheckoutHiEventDetectorTest.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.git; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestTransmitter; +import org.eclipse.che.api.core.jsonrpc.RequestTransmitter; import org.eclipse.che.api.vfs.VirtualFileSystemProvider; import org.junit.Before; import org.junit.Test; @@ -41,7 +41,7 @@ public class GitCheckoutHiEventDetectorTest extends HiVfsEventDetectorTestHelper private static final String GIT_OPERATIONS_CHANNEL = "git-operations-channel"; @Mock - private JsonRpcRequestTransmitter transmitter; + private RequestTransmitter transmitter; @Mock private VirtualFileSystemProvider virtualFileSystemProvider; diff --git a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/event/VfsFileStatusUpdateDto.java b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/event/VfsFileStatusUpdateDto.java index 9491cf6587d..4ffbe7704e0 100644 --- a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/event/VfsFileStatusUpdateDto.java +++ b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/event/VfsFileStatusUpdateDto.java @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.che.api.project.shared.dto.event; -import com.google.common.hash.HashCode; - import org.eclipse.che.dto.shared.DTO; @DTO diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java index bdfdd72b350..6dacdef5e2a 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectApiModule.java @@ -16,7 +16,7 @@ import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestReceiver; +import org.eclipse.che.api.core.jsonrpc.RequestHandler; import org.eclipse.che.api.project.server.handlers.CreateBaseProjectTypeHandler; import org.eclipse.che.api.project.server.handlers.ProjectHandler; import org.eclipse.che.api.project.server.importer.ProjectImporter; @@ -120,9 +120,9 @@ private void configureVfsEvent() { bind(FileTrackingOperationTransmitter.class).asEagerSingleton(); - MapBinder requestReceivers = - MapBinder.newMapBinder(binder(), String.class, JsonRpcRequestReceiver.class); - requestReceivers.addBinding("track:editor-file").to(FileTrackingOperationReceiver.class); + MapBinder.newMapBinder(binder(), String.class, RequestHandler.class) + .addBinding("track:editor-file") + .to(FileTrackingOperationReceiver.class); } } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationReceiver.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationReceiver.java index ad2b1c11145..4372ee54b54 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationReceiver.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationReceiver.java @@ -10,12 +10,9 @@ *******************************************************************************/ package org.eclipse.che.api.vfs.impl.file.event.detectors; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestReceiver; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; +import org.eclipse.che.api.core.jsonrpc.RequestHandler; import org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto; import org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto.Type; -import org.eclipse.che.api.vfs.impl.file.event.HiEventClientBroadcaster; -import org.eclipse.che.dto.server.DtoFactory; import org.slf4j.Logger; import javax.inject.Inject; @@ -40,20 +37,19 @@ * @author Dmitry Kuleshov */ @Singleton -public class FileTrackingOperationReceiver implements JsonRpcRequestReceiver { +public class FileTrackingOperationReceiver extends RequestHandler { private static final Logger LOG = getLogger(FileTrackingOperationReceiver.class); private final FileTrackingRegistry registry; @Inject public FileTrackingOperationReceiver(FileTrackingRegistry registry) { + super(FileTrackingOperationDto.class, Void.class); this.registry = registry; } @Override - public void receive(JsonRpcRequest request, Integer endpoint) { - final String params = request.getParams(); - final FileTrackingOperationDto operation = DtoFactory.getInstance().createDtoFromJson(params, FileTrackingOperationDto.class); + public void handleNotification(String endpointId, FileTrackingOperationDto operation) { final Type type = operation.getType(); final String path = operation.getPath(); final String oldPath = operation.getOldPath(); @@ -62,28 +58,28 @@ public void receive(JsonRpcRequest request, Integer endpoint) { case START: { LOG.debug("Received file tracking operation START trigger."); - registry.add(path, endpoint); + registry.add(path, endpointId); break; } case STOP: { LOG.debug("Received file tracking operation STOP trigger."); - registry.remove(path, endpoint); + registry.remove(path, endpointId); break; } case SUSPEND: { LOG.debug("Received file tracking operation SUSPEND trigger."); - registry.suspend(endpoint); + registry.suspend(endpointId); break; } case RESUME: { LOG.debug("Received file tracking operation RESUME trigger."); - registry.resume(endpoint); + registry.resume(endpointId); break; } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationTransmitter.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationTransmitter.java index 9c25f27a902..664a40514ec 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationTransmitter.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingOperationTransmitter.java @@ -10,8 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.vfs.impl.file.event.detectors; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestTransmitter; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; +import org.eclipse.che.api.core.jsonrpc.RequestTransmitter; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.core.notification.EventSubscriber; import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType; @@ -39,13 +38,11 @@ public class FileTrackingOperationTransmitter { private static final Logger LOG = getLogger(FileTrackingOperationTransmitter.class); - private final JsonRpcRequestTransmitter transmitter; - private final FileTrackingRegistry registry; + private final RequestTransmitter transmitter; + private final FileTrackingRegistry registry; @Inject - public FileTrackingOperationTransmitter(EventService eventService, - JsonRpcRequestTransmitter transmitter, - FileTrackingRegistry registry) { + public FileTrackingOperationTransmitter(EventService eventService, RequestTransmitter transmitter, FileTrackingRegistry registry) { this.transmitter = transmitter; this.registry = registry; @@ -60,7 +57,7 @@ public void onEvent(FileTrackingEvent event) { final String path = event.getPath(); final FileWatcherEventType type = event.getType(); - if (!registry.contains(path)){ + if (!registry.contains(path)) { return; } @@ -88,31 +85,28 @@ public void onEvent(FileTrackingEvent event) { } private void transmitDeleted(String path) { - final String params = getParams(path, null, DELETED); - final JsonRpcRequest request = getJsonRpcRequest(params); + final VfsFileStatusUpdateDto params = getParams(path, null, DELETED); - registry.getEndpoints(path).forEach(endpoint -> transmitter.transmit(request, endpoint)); + registry.getEndpoints(path).forEach(endpoint -> { + final String method = "event:file-in-vfs-status-changed"; + transmitter.transmitNotification(endpoint, method, params); + }); } private void transmitModified(String path) { if (registry.updateHash(path)) { final String hashCode = registry.getHashCode(path); - final String params = getParams(path, hashCode, MODIFIED); - final JsonRpcRequest request = getJsonRpcRequest(params); + final VfsFileStatusUpdateDto params = getParams(path, hashCode, MODIFIED); - registry.getEndpoints(path).forEach(endpoint -> transmitter.transmit(request, endpoint)); + registry.getEndpoints(path).forEach(endpoint -> { + final String method = "event:file-in-vfs-status-changed"; + transmitter.transmitNotification(endpoint, method, params); + }); } } - private String getParams(String path, String hashCode, FileWatcherEventType type) { - return newDto(VfsFileStatusUpdateDto.class).withPath(path).withType(type).withHashCode(hashCode).toString(); - } - - private JsonRpcRequest getJsonRpcRequest(String params) { - return newDto(JsonRpcRequest.class) - .withMethod("event:file-in-vfs-status-changed") - .withJsonrpc("2.0") - .withParams(params); + private VfsFileStatusUpdateDto getParams(String path, String hashCode, FileWatcherEventType type) { + return newDto(VfsFileStatusUpdateDto.class).withPath(path).withType(type).withHashCode(hashCode); } } } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingRegistry.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingRegistry.java index 096e8517fb7..3af0d19feb3 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingRegistry.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/FileTrackingRegistry.java @@ -52,7 +52,7 @@ public FileTrackingRegistry(VirtualFileSystemProvider vfsProvider) { this.vfsProvider = vfsProvider; } - public void add(String path, int endpoint) { + public void add(String path, String endpoint) { final FileTrackingMetadata fileTrackingMetadata = registry.get(path); if (fileTrackingMetadata == null) { @@ -62,14 +62,14 @@ public void add(String path, int endpoint) { } } - public void suspend(int endpoint) { + public void suspend(String endpoint) { registry.values() .stream() .filter(m -> m.getNotSuspendedEndpoints().contains(endpoint)) .forEach(m -> m.suspend(endpoint)); } - public void resume(int endpoint) { + public void resume(String endpoint) { registry.values() .stream() .filter(m -> m.getSuspendedEndpoints().contains(endpoint)) @@ -96,7 +96,7 @@ public void copy(String oldPath, String newPath) { registry.put(newPath, fileTrackingMetadata); } - public void remove(String path, int endpoint) { + public void remove(String path, String endpoint) { final FileTrackingMetadata fileTrackingMetadata = registry.get(path); if (fileTrackingMetadata == null) { @@ -132,7 +132,7 @@ public boolean contains(String path) { return registry.keySet().contains(path); } - public Set getEndpoints(String path) { + public Set getEndpoints(String path) { return registry.get(path).getNotSuspendedEndpoints(); } @@ -163,20 +163,20 @@ private class FileTrackingMetadata { private static final boolean ACTIVE = true; private static final boolean NOT_ACTIVE = false; private String hashCode; - private Map endpoints = new ConcurrentHashMap<>(); + private Map endpoints = new ConcurrentHashMap<>(); - public FileTrackingMetadata(String path, int endpoint) { + public FileTrackingMetadata(String path, String endpoint) { this.hashCode = getHash(path); this.endpoints.put(endpoint, ACTIVE); } - public void suspend(int endpoint) { + public void suspend(String endpoint) { if (endpoints.containsKey(endpoint)) { endpoints.put(endpoint, NOT_ACTIVE); } } - public void resume(int endpoint) { + public void resume(String endpoint) { if (endpoints.containsKey(endpoint)) { endpoints.put(endpoint, ACTIVE); } @@ -190,19 +190,19 @@ public void setHashCode(String hashCode) { this.hashCode = hashCode; } - public void addEndpoint(int endpoint) { + public void addEndpoint(String endpoint) { endpoints.put(endpoint, ACTIVE); } - public void removeEndpoint(int endpoint) { + public void removeEndpoint(String endpoint) { endpoints.remove(endpoint); } - public Set getNotSuspendedEndpoints() { + public Set getNotSuspendedEndpoints() { return endpoints.entrySet().stream().filter(Entry::getValue).map(Entry::getKey).collect(toSet()); } - public Set getSuspendedEndpoints() { + public Set getSuspendedEndpoints() { return endpoints.entrySet().stream().filter(e -> !e.getValue()).map(Entry::getKey).collect(toSet()); } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/ProjectTreeChangesDetector.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/ProjectTreeChangesDetector.java index 50eda5474ad..3b83fb5c00d 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/ProjectTreeChangesDetector.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/detectors/ProjectTreeChangesDetector.java @@ -12,8 +12,7 @@ import com.google.common.annotations.Beta; -import org.eclipse.che.api.core.jsonrpc.JsonRpcRequestTransmitter; -import org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; +import org.eclipse.che.api.core.jsonrpc.RequestTransmitter; import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType; import org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto; import org.eclipse.che.api.vfs.impl.file.event.EventTreeNode; @@ -31,7 +30,6 @@ import static java.lang.Math.min; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.SECONDS; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.slf4j.LoggerFactory.getLogger; @@ -43,15 +41,15 @@ public class ProjectTreeChangesDetector implements HiEventDetector { private static final Logger LOG = getLogger(ProjectTreeChangesDetector.class); - private final JsonRpcRequestTransmitter transmitter; - private final ThreadPullLauncher launcher; + private final RequestTransmitter transmitter; + private final ThreadPullLauncher launcher; private final Set trees = new HashSet<>(); private State state; @Inject - public ProjectTreeChangesDetector(JsonRpcRequestTransmitter transmitter, ThreadPullLauncher launcher) { + public ProjectTreeChangesDetector(RequestTransmitter transmitter, ThreadPullLauncher launcher) { this.transmitter = transmitter; this.launcher = launcher; } @@ -120,21 +118,12 @@ private void transmit() { } private void transmit(String path, FileWatcherEventType type) { - final String params = getParams(path, type); - final JsonRpcRequest request = getJsonRpcRequest(params); - - transmitter.transmit(request); - } - - private String getParams(String path, FileWatcherEventType type) { - return newDto(ProjectTreeStatusUpdateDto.class).withPath(path).withType(type).toString(); + final ProjectTreeStatusUpdateDto params = getParams(path, type); + transmitter.broadcast("event:project-tree-status-changed", params); } - private JsonRpcRequest getJsonRpcRequest(String params) { - return newDto(JsonRpcRequest.class) - .withMethod("event:project-tree-status-changed") - .withJsonrpc("2.0") - .withParams(params); + private ProjectTreeStatusUpdateDto getParams(String path, FileWatcherEventType type) { + return newDto(ProjectTreeStatusUpdateDto.class).withPath(path).withType(type); } private enum State { From 5fbaf3d9ac45344b5596742b27d9335652d3d0ca Mon Sep 17 00:00:00 2001 From: Anatoliy Bazko Date: Fri, 25 Nov 2016 15:53:12 +0200 Subject: [PATCH 18/74] CHE-3137: Ensure java version is greater or equal to 1.8 (#3162) --- .../agents/org.eclipse.che.ws-agent.json | 2 +- .../org.eclipse.che.ws-agent.script.sh | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.ws-agent.json b/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.ws-agent.json index 18000a79ebd..005d23c193c 100644 --- a/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.ws-agent.json +++ b/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.ws-agent.json @@ -15,5 +15,5 @@ } } }, -"script" : "#\n# Copyright (c) 2012-2016 Codenvy, S.A.\n# All rights reserved. This program and the accompanying materials\n# are made available under the terms of the Eclipse Public License v1.0\n# which accompanies this distribution, and is available at\n# http://www.eclipse.org/legal/epl-v10.html\n#\n# Contributors:\n# Codenvy, S.A. - initial API and implementation\n#\n\nunset PACKAGES\nunset SUDO\ncommand -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" tar\"; }\ncommand -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" curl\"; }\ntest \"$(id -u)\" = 0 || SUDO=\"sudo\"\n\nLOCAL_AGENT_BINARIES_URI=\"/mnt/che/ws-agent.tar.gz\"\nDOWNLOAD_AGENT_BINARIES_URI='${WORKSPACE_MASTER_URI}/agent-binaries/ws-agent.tar.gz'\n\nCHE_DIR=$HOME/che\n\nif [ -f /etc/centos-release ]; then\n FILE=\"/etc/centos-release\"\n LINUX_TYPE=$(cat $FILE | awk '{print $1}')\n elif [ -f /etc/redhat-release ]; then\n FILE=\"/etc/redhat-release\"\n LINUX_TYPE=$(cat $FILE | cut -c 1-8)\n else\n FILE=\"/etc/os-release\"\n LINUX_TYPE=$(cat $FILE | grep ^ID= | tr '[:upper:]' '[:lower:]')\n LINUX_VERSION=$(cat $FILE | grep ^VERSION_ID=)\nfi\nMACHINE_TYPE=$(uname -m)\n\nmkdir -p ${CHE_DIR}\n${SUDO} mkdir -p /projects\n${SUDO} sh -c \"chown -R $(id -u -n) /projects\"\n\n########################\n### Install packages ###\n########################\n\n# Red Hat Enterprise Linux 7\n############################\nif echo ${LINUX_TYPE} | grep -qi \"rhel\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\n# Ubuntu 14.04 16.04 / Linux Mint 17\n####################################\nelif echo ${LINUX_TYPE} | grep -qi \"ubuntu\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Debian 8\n##########\nelif echo ${LINUX_TYPE} | grep -qi \"debian\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Fedora 23\n###########\nelif echo ${LINUX_TYPE} | grep -qi \"fedora\"; then\n PACKAGES=${PACKAGES}\" procps-ng\"\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} dnf -y install ${PACKAGES};\n }\n\n# CentOS 7.1 & Oracle Linux 7.1\n###############################\nelif echo ${LINUX_TYPE} | grep -qi \"centos\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# openSUSE 13.2\n###############\nelif echo ${LINUX_TYPE} | grep -qi \"opensuse\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} zypper install -y ${PACKAGES};\n }\n\n# Alpine 3.3\n############$$\nelif echo ${LINUX_TYPE} | grep -qi \"alpine\"; then\n\n # Setup OpenJDK8 (not using glibc) if missing\n INSTALL_JDK=false\n command -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" openjdk8\"; INSTALL_JDK=true;}\n\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apk update\n ${SUDO} apk add ${PACKAGES};\n }\n\n # Link OpenJDK to JAVA_HOME\n if [ ${INSTALL_JDK} = true ]; then\n export JAVA_HOME=${CHE_DIR}/jdk1.8\n ln -s /usr/lib/jvm/java-1.8-openjdk $JAVA_HOME\n fi\n\n# Centos 6.6, 6.7, 6.8\n############\nelif echo ${LINUX_TYPE} | grep -qi \"CentOS\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# Red Hat Enterprise Linux 6 \n############################\nelif echo ${LINUX_TYPE} | grep -qi \"Red Hat\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\nelse\n >&2 echo \"Unrecognized Linux Type\"\n >&2 cat $FILE\n exit 1\nfi\n\n####################\n### Install java ###\n####################\ncommand -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || {\n export JAVA_HOME=${CHE_DIR}/jdk1.8\n command -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || {\n JDK_URL=http://download.oracle.com/otn-pub/java/jdk/8u45-b14/jdk-8u45-linux-x64.tar.gz\n curl -s -j -k -L -H \"Cookie: oraclelicense=accept-securebackup-cookie\" \"${JDK_URL}\" | tar -C ${CHE_DIR} -xzf -\n mv ${CHE_DIR}/jdk1.8.0_45 ${CHE_DIR}/jdk1.8\n }\n}\n\n########################\n### Install ws-agent ###\n########################\n\nrm -rf ${CHE_DIR}/ws-agent\nmkdir -p ${CHE_DIR}/ws-agent\n\n\n# Compute URI of workspace master\nWORKSPACE_MASTER_URI=$(echo $CHE_API | cut -d / -f 1-3)\n\n## Evaluate variables now that prefix is defined\neval \"DOWNLOAD_AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\"\n\n\nif [ -f \"${LOCAL_AGENT_BINARIES_URI}\" ]\nthen\n AGENT_BINARIES_URI=\"file://${LOCAL_AGENT_BINARIES_URI}\"\nelse\n echo \"Workspace Agent will be downloaded from Workspace Master\"\n AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\nfi\n\ncurl -s ${AGENT_BINARIES_URI} | tar xzf - -C ${CHE_DIR}/ws-agent\n\n###############################################\n### ws-agent run command will be added here ###\n### ~/che/ws-agent/bin/catalina.sh run ###\n###############################################" +"script" : "#\n# Copyright (c) 2012-2016 Codenvy, S.A.\n# All rights reserved. This program and the accompanying materials\n# are made available under the terms of the Eclipse Public License v1.0\n# which accompanies this distribution, and is available at\n# http://www.eclipse.org/legal/epl-v10.html\n#\n# Contributors:\n# Codenvy, S.A. - initial API and implementation\n#\n\nunset PACKAGES\nunset SUDO\ncommand -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" tar\"; }\ncommand -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" curl\"; }\ntest \"$(id -u)\" = 0 || SUDO=\"sudo\"\n\nLOCAL_AGENT_BINARIES_URI=\"/mnt/che/ws-agent.tar.gz\"\nDOWNLOAD_AGENT_BINARIES_URI='${WORKSPACE_MASTER_URI}/agent-binaries/ws-agent.tar.gz'\n\nCHE_DIR=$HOME/che\n\nif [ -f /etc/centos-release ]; then\n FILE=\"/etc/centos-release\"\n LINUX_TYPE=$(cat $FILE | awk '{print $1}')\n elif [ -f /etc/redhat-release ]; then\n FILE=\"/etc/redhat-release\"\n LINUX_TYPE=$(cat $FILE | cut -c 1-8)\n else\n FILE=\"/etc/os-release\"\n LINUX_TYPE=$(cat $FILE | grep ^ID= | tr '[:upper:]' '[:lower:]')\n LINUX_VERSION=$(cat $FILE | grep ^VERSION_ID=)\nfi\nMACHINE_TYPE=$(uname -m)\n\nmkdir -p ${CHE_DIR}\n${SUDO} mkdir -p /projects\n${SUDO} sh -c \"chown -R $(id -u -n) /projects\"\n\n########################\n### Install packages ###\n########################\n\n# Red Hat Enterprise Linux 7\n############################\nif echo ${LINUX_TYPE} | grep -qi \"rhel\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\n# Ubuntu 14.04 16.04 / Linux Mint 17\n####################################\nelif echo ${LINUX_TYPE} | grep -qi \"ubuntu\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Debian 8\n##########\nelif echo ${LINUX_TYPE} | grep -qi \"debian\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Fedora 23\n###########\nelif echo ${LINUX_TYPE} | grep -qi \"fedora\"; then\n PACKAGES=${PACKAGES}\" procps-ng\"\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} dnf -y install ${PACKAGES};\n }\n\n# CentOS 7.1 & Oracle Linux 7.1\n###############################\nelif echo ${LINUX_TYPE} | grep -qi \"centos\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# openSUSE 13.2\n###############\nelif echo ${LINUX_TYPE} | grep -qi \"opensuse\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} zypper install -y ${PACKAGES};\n }\n\n# Alpine 3.3\n############$$\nelif echo ${LINUX_TYPE} | grep -qi \"alpine\"; then\n\n # Setup OpenJDK8 (not using glibc) if missing\n INSTALL_JDK=false\n command -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" openjdk8\"; INSTALL_JDK=true;}\n\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apk update\n ${SUDO} apk add ${PACKAGES};\n }\n\n # Link OpenJDK to JAVA_HOME\n if [ ${INSTALL_JDK} = true ]; then\n export JAVA_HOME=${CHE_DIR}/jdk1.8\n ln -s /usr/lib/jvm/java-1.8-openjdk $JAVA_HOME\n fi\n\n# Centos 6.6, 6.7, 6.8\n############\nelif echo ${LINUX_TYPE} | grep -qi \"CentOS\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# Red Hat Enterprise Linux 6 \n############################\nelif echo ${LINUX_TYPE} | grep -qi \"Red Hat\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\nelse\n >&2 echo \"Unrecognized Linux Type\"\n >&2 cat $FILE\n exit 1\nfi\n\n####################\n### Install java ###\n####################\ndownloadJava() {\n echo \"Downloading JDK 1.8.0_111\"\n JDK_URL=http://download.oracle.com/otn-pub/java/jdk/8u111-b14/jdk-8u111-linux-x64.tar.gz\n curl -s -j -k -L -H \"Cookie: oraclelicense=accept-securebackup-cookie\" \"${JDK_URL}\" | tar -C ${CHE_DIR} -xzf -\n mv ${CHE_DIR}/jdk1.8.0_111 ${CHE_DIR}/jdk1.8\n\n export JAVA_HOME=${CHE_DIR}/jdk1.8\n}\n\ncommand -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || {\n downloadJava;\n} && {\n java_version=$(${JAVA_HOME}/bin/java -version 2>&1 | sed 's/.* version \"\\(.*\\)\\.\\(.*\\)\\..*\"/\\1\\2/; 1q')\n if [ \"${java_version}\" -lt \"18\" ]; then\n downloadJava;\n fi\n}\n\n########################\n### Install ws-agent ###\n########################\n\nrm -rf ${CHE_DIR}/ws-agent\nmkdir -p ${CHE_DIR}/ws-agent\n\n\n# Compute URI of workspace master\nWORKSPACE_MASTER_URI=$(echo $CHE_API | cut -d / -f 1-3)\n\n## Evaluate variables now that prefix is defined\neval \"DOWNLOAD_AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\"\n\n\nif [ -f \"${LOCAL_AGENT_BINARIES_URI}\" ]\nthen\n AGENT_BINARIES_URI=\"file://${LOCAL_AGENT_BINARIES_URI}\"\nelse\n echo \"Workspace Agent will be downloaded from Workspace Master\"\n AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\nfi\n\ncurl -s ${AGENT_BINARIES_URI} | tar xzf - -C ${CHE_DIR}/ws-agent\n\n###############################################\n### ws-agent run command will be added here ###\n### ~/che/ws-agent/bin/catalina.sh run ###\n###############################################" } diff --git a/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.ws-agent.script.sh b/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.ws-agent.script.sh index 981d8fc39f2..517191875a8 100644 --- a/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.ws-agent.script.sh +++ b/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.ws-agent.script.sh @@ -128,13 +128,22 @@ fi #################### ### Install java ### #################### -command -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || { +downloadJava() { + echo "Downloading JDK 1.8.0_111" + JDK_URL=http://download.oracle.com/otn-pub/java/jdk/8u111-b14/jdk-8u111-linux-x64.tar.gz + curl -s -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" "${JDK_URL}" | tar -C ${CHE_DIR} -xzf - + mv ${CHE_DIR}/jdk1.8.0_111 ${CHE_DIR}/jdk1.8 + export JAVA_HOME=${CHE_DIR}/jdk1.8 - command -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || { - JDK_URL=http://download.oracle.com/otn-pub/java/jdk/8u45-b14/jdk-8u45-linux-x64.tar.gz - curl -s -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" "${JDK_URL}" | tar -C ${CHE_DIR} -xzf - - mv ${CHE_DIR}/jdk1.8.0_45 ${CHE_DIR}/jdk1.8 - } +} + +command -v ${JAVA_HOME}/bin/java >/dev/null 2>&1 || { + downloadJava; +} && { + java_version=$(${JAVA_HOME}/bin/java -version 2>&1 | sed 's/.* version "\\(.*\\)\\.\\(.*\\)\\..*"/\\1\\2/; 1q') + if [ "${java_version}" -lt "18" ]; then + downloadJava; + fi } ######################## From ac14c9e1baff452b291b99e4dc1c8d2139b9a7f0 Mon Sep 17 00:00:00 2001 From: Aleksandr Andrienko Date: Mon, 28 Nov 2016 10:03:21 +0200 Subject: [PATCH 19/74] CHE-3181: Fix appearing 'Restore project structure' loader. (#3182) Signed-off-by: Aleksandr Andrienko --- .../explorer/project/ProjectExplorerStateComponent.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java index 47dd129d0b9..5a6e50609bd 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerStateComponent.java @@ -91,12 +91,10 @@ public void loadState(@NotNull JsonObject state) { projectExplorer.showHiddenFiles(state.getBoolean(SHOW_HIDDEN_FILES)); } - JsonArray paths; + JsonArray paths = state.hasKey(PATH_PARAM_ID) ? state.getArray(PATH_PARAM_ID) : Json.createArray(); - if (state.hasKey(PATH_PARAM_ID)) { - paths = state.getArray(PATH_PARAM_ID); - } else { - paths = Json.createArray(); + if (paths.length() == 0) { + return; } Promise revealPromise = null; From afadcd24f3aaa538e65ea1d686348256360b39b6 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 28 Nov 2016 11:50:50 +0200 Subject: [PATCH 20/74] CHE-3065 Add uncaught exceptions handler in threads being run by ExecutorService (#3174) --- .../notification/WSocketEventBusClient.java | 4 ++ .../che/api/core/util/FileCleaner.java | 4 ++ .../ServerContainerInitializeListener.java | 7 +++- .../LoggingUncaughtExceptionHandler.java | 39 +++++++++++++++++++ .../commons/che-core-commons-schedule/pom.xml | 4 ++ .../schedule/executor/ThreadPullLauncher.java | 6 ++- .../docker/client/CgroupOOMDetector.java | 3 ++ .../plugin/docker/client/DockerConnector.java | 3 ++ .../machine/DockerInstanceStopDetector.java | 3 ++ .../docker/machine/MachineProviderImpl.java | 3 ++ ...esAfterRemoveWorkspaceEventSubscriber.java | 3 ++ .../core/BufferOutputFixedRateSender.java | 2 + .../server/core/MavenExecutorService.java | 5 ++- .../nodejsdbg/server/NodeJsDebugProcess.java | 3 ++ .../api/project/server/ProjectManager.java | 3 ++ .../ProjectImportOutputWSLineConsumer.java | 6 ++- .../api/vfs/impl/file/FileTreeWatcher.java | 7 +++- .../vfs/impl/file/event/VfsEventService.java | 3 ++ .../impl/AbstractLuceneSearcherProvider.java | 3 ++ .../launcher/AbstractAgentLauncher.java | 3 ++ .../server/MachineProcessManager.java | 3 ++ .../workspace/server/WorkspaceManager.java | 3 ++ .../workspace/server/WorkspaceRuntimes.java | 3 ++ 23 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/LoggingUncaughtExceptionHandler.java diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/notification/WSocketEventBusClient.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/notification/WSocketEventBusClient.java index e2516e7cf66..fe7705bf2e7 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/notification/WSocketEventBusClient.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/notification/WSocketEventBusClient.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.core.notification; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.lang.Pair; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -108,6 +109,9 @@ public void onEvent(Object event) { } if (!cfg.isEmpty()) { executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("WSocketEventBusClient-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler + .getInstance()) .setDaemon(true).build()); for (Map.Entry> entry : cfg.entrySet()) { executor.execute(new ConnectTask(entry.getKey(), entry.getValue())); diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/util/FileCleaner.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/util/FileCleaner.java index 25714b19ffd..7d52c2b981b 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/util/FileCleaner.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/util/FileCleaner.java @@ -15,6 +15,7 @@ import org.eclipse.che.commons.lang.IoUtil; import org.eclipse.che.commons.lang.Pair; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,6 +44,9 @@ public class FileCleaner { private static ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder() .setNameFormat("FileCleaner") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler + .getInstance()) .setDaemon(true).build()); static { diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/everrest/ServerContainerInitializeListener.java b/core/che-core-api-core/src/main/java/org/eclipse/che/everrest/ServerContainerInitializeListener.java index 12e224c3ff9..3c9d1693180 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/everrest/ServerContainerInitializeListener.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/everrest/ServerContainerInitializeListener.java @@ -13,6 +13,7 @@ import com.google.common.base.MoreObjects; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.subject.Subject; import org.everrest.core.DependencySupplier; @@ -174,7 +175,11 @@ protected ExecutorService createExecutor(final ServletContext servletContext) { final EverrestConfiguration everrestConfiguration = getEverrestConfiguration(servletContext); final String threadNameFormat = "everrest.WSConnection." + servletContext.getServletContextName() + "-%d"; return Executors.newFixedThreadPool(everrestConfiguration.getAsynchronousPoolSize(), - new ThreadFactoryBuilder().setNameFormat(threadNameFormat).setDaemon(true).build()); + new ThreadFactoryBuilder().setNameFormat(threadNameFormat) + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) + .setDaemon(true) + .build()); } protected SecurityContext createSecurityContext(final HandshakeRequest req) { diff --git a/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/LoggingUncaughtExceptionHandler.java b/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/LoggingUncaughtExceptionHandler.java new file mode 100644 index 00000000000..5cd3a3be303 --- /dev/null +++ b/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/LoggingUncaughtExceptionHandler.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.commons.lang.concurrent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writes uncaught exceptions in threads being run by {@link java.util.concurrent.ExecutorService} into application log. + * + * @author Max Shaposhnik + */ +public class LoggingUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + + private static final Logger LOG = LoggerFactory.getLogger(LoggingUncaughtExceptionHandler.class); + + private static final LoggingUncaughtExceptionHandler INSTANCE = new LoggingUncaughtExceptionHandler(); + + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error(String.format("Runtime exception caught in thread %s. Message: %s", t.getName(), e.getLocalizedMessage()), e); + } + + public static LoggingUncaughtExceptionHandler getInstance() { + return INSTANCE; + } + + private LoggingUncaughtExceptionHandler() { + } + +} diff --git a/core/commons/che-core-commons-schedule/pom.xml b/core/commons/che-core-commons-schedule/pom.xml index dda748fbd39..28f55dfa37a 100644 --- a/core/commons/che-core-commons-schedule/pom.xml +++ b/core/commons/che-core-commons-schedule/pom.xml @@ -45,6 +45,10 @@ org.eclipse.che.core che-core-commons-inject
+ + org.eclipse.che.core + che-core-commons-lang + org.slf4j slf4j-api diff --git a/core/commons/che-core-commons-schedule/src/main/java/org/eclipse/che/commons/schedule/executor/ThreadPullLauncher.java b/core/commons/che-core-commons-schedule/src/main/java/org/eclipse/che/commons/schedule/executor/ThreadPullLauncher.java index 7c268c3fec7..3019559f70d 100644 --- a/core/commons/che-core-commons-schedule/src/main/java/org/eclipse/che/commons/schedule/executor/ThreadPullLauncher.java +++ b/core/commons/che-core-commons-schedule/src/main/java/org/eclipse/che/commons/schedule/executor/ThreadPullLauncher.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.commons.schedule.executor; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.schedule.Launcher; import org.eclipse.che.inject.ConfigurationException; @@ -44,7 +45,10 @@ public class ThreadPullLauncher implements Launcher { @Inject public ThreadPullLauncher(@Named("schedule.core_pool_size") Integer corePoolSize) { this.service = new CronThreadPoolExecutor(corePoolSize, - new ThreadFactoryBuilder().setNameFormat("Annotated-scheduler-%d").setDaemon(false) + new ThreadFactoryBuilder().setNameFormat("Annotated-scheduler-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) + .setDaemon(false) .build()); } diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/CgroupOOMDetector.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/CgroupOOMDetector.java index aed58d967f3..3c10325ea8d 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/CgroupOOMDetector.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/CgroupOOMDetector.java @@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sun.jna.ptr.LongByReference; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.core.util.SystemInfo; import org.eclipse.che.commons.lang.Size; import org.slf4j.Logger; @@ -55,6 +56,8 @@ public CgroupOOMDetector(URI dockerDaemonUri, DockerConnector dockerConnector) { this.dockerConnector = dockerConnector; this.oomDetectors = new ConcurrentHashMap<>(); this.executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("CgroupOOMDetector-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build()); } diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java index 6ac395f279f..140c582c444 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerConnector.java @@ -19,6 +19,7 @@ import com.google.gson.JsonParseException; import org.eclipse.che.api.core.util.FileCleaner; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.lang.TarUtils; import org.eclipse.che.commons.lang.ws.rs.ExtMediaType; @@ -147,6 +148,8 @@ public DockerConnector(DockerConnectorConfiguration connectorConfiguration, this.authResolver = authResolver; this.apiVersionPathPrefix = dockerApiVersionPathPrefixProvider.get(); executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder() + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setNameFormat("DockerApiConnector-%d") .setDaemon(true) .build()); diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceStopDetector.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceStopDetector.java index 999f933e4ab..413784c023d 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceStopDetector.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceStopDetector.java @@ -15,6 +15,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.machine.server.event.InstanceStateEvent; import org.eclipse.che.commons.lang.Pair; import org.eclipse.che.plugin.docker.client.DockerConnector; @@ -74,6 +75,8 @@ public DockerInstanceStopDetector(EventService eventService, DockerConnector doc .build(); this.executorService = Executors.newSingleThreadExecutor( new ThreadFactoryBuilder().setNameFormat("DockerInstanceStopDetector-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build()); } 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 b9461e9a3b3..03cf3e53d5c 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 @@ -21,6 +21,7 @@ import org.eclipse.che.api.core.model.machine.ServerConf; import org.eclipse.che.api.core.util.FileCleaner; import org.eclipse.che.api.core.util.LineConsumer; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.core.util.SystemInfo; import org.eclipse.che.api.environment.server.MachineInstanceProvider; import org.eclipse.che.api.environment.server.model.CheServiceImpl; @@ -235,6 +236,8 @@ public MachineProviderImpl(DockerConnector docker, // TODO single point of failure in case of highly loaded system executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("MachineLogsStreamer-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build()); } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/cleaner/RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/cleaner/RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber.java index 137385bed29..aa8f03c5a1e 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/cleaner/RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/cleaner/RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber.java @@ -18,6 +18,7 @@ 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.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.workspace.server.WorkspaceFilesCleaner; import org.eclipse.che.api.workspace.server.event.WorkspaceRemovedEvent; import org.eclipse.che.commons.lang.concurrent.ThreadLocalPropagateContext; @@ -49,6 +50,8 @@ public RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber(EventService even this.workspaceFilesCleaner = workspaceFilesCleaner; this.eventService = eventService; executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build()); } diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/BufferOutputFixedRateSender.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/BufferOutputFixedRateSender.java index 357650411eb..a7e4b44d70a 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/BufferOutputFixedRateSender.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/BufferOutputFixedRateSender.java @@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.eclipse.che.api.core.util.ListLineConsumer; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.everrest.websockets.WSConnectionContext; import org.everrest.websockets.message.ChannelBroadcastMessage; import org.slf4j.Logger; @@ -40,6 +41,7 @@ public class BufferOutputFixedRateSender extends ListLineConsumer { public BufferOutputFixedRateSender(String channel, long delay) { this.channel = channel; ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(BufferOutputFixedRateSender.class.getSimpleName() + "-%d") + .setUncaughtExceptionHandler(LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build(); diff --git a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenExecutorService.java b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenExecutorService.java index d83bfd72b5d..0f157218dc9 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenExecutorService.java +++ b/plugins/plugin-maven/che-plugin-maven-server/src/main/java/org/eclipse/che/plugin/maven/server/core/MavenExecutorService.java @@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.inject.Singleton; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +34,9 @@ public class MavenExecutorService { private final ExecutorService service; public MavenExecutorService() { - ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("Maven Executor - %d").build(); + ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("Maven Executor - %d") + .setUncaughtExceptionHandler(LoggingUncaughtExceptionHandler.getInstance()) + .build(); service = Executors.newFixedThreadPool(1, threadFactory); } diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugProcess.java b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugProcess.java index 7e6e56a2674..22c6812b19c 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugProcess.java +++ b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/src/main/java/org/eclipse/che/plugin/nodejsdbg/server/NodeJsDebugProcess.java @@ -12,6 +12,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.lang.IoUtil; import org.eclipse.che.plugin.nodejsdbg.server.exception.NodeJsDebuggerException; import org.eclipse.che.plugin.nodejsdbg.server.exception.NodeJsDebuggerTerminatedException; @@ -70,6 +71,8 @@ private NodeJsDebugProcess(String outputSeparator, String... options) throws Nod processWriter = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); executor = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().setNameFormat("nodejs-debugger-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build()); executor.scheduleWithFixedDelay(new OutputReader(), 0, 100, TimeUnit.MILLISECONDS); diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java index 3e6925e3056..66495bedbd1 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java @@ -22,6 +22,7 @@ import org.eclipse.che.api.core.model.project.type.ProjectType; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.core.util.LineConsumerFactory; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.project.server.handlers.CreateProjectHandler; import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry; import org.eclipse.che.api.project.server.importer.ProjectImportOutputWSLineConsumer; @@ -106,6 +107,8 @@ public ProjectManager(VirtualFileSystemProvider vfsProvider, executor = Executors.newFixedThreadPool(1 + Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat("ProjectService-IndexingThread-") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true).build()); } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java index 4277e4eb413..e804e071681 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java @@ -13,6 +13,7 @@ import org.eclipse.che.api.core.util.LineConsumer; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.everrest.core.impl.provider.json.JsonUtils; import org.everrest.websockets.WSConnectionContext; import org.everrest.websockets.message.ChannelBroadcastMessage; @@ -44,7 +45,10 @@ public ProjectImportOutputWSLineConsumer(String projectName, String workspaceId, this.workspaceId = workspaceId; lineToSendQueue = new ArrayBlockingQueue<>(1024); executor = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder().setNameFormat(ProjectImportOutputWSLineConsumer.class.getSimpleName()+"-%d").setDaemon(true).build()); + new ThreadFactoryBuilder().setNameFormat(ProjectImportOutputWSLineConsumer.class.getSimpleName() + "-%d") + .setDaemon(true) + .setUncaughtExceptionHandler(LoggingUncaughtExceptionHandler.getInstance()) + .build()); executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcher.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcher.java index 9f7e9958331..77e166abc74 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcher.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/FileTreeWatcher.java @@ -12,6 +12,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,7 +86,11 @@ public FileTreeWatcher(@Named("che.user.workspaces.storage") File watchRoot, this.excludePatterns = newArrayList(excludePatterns); this.fileWatcherNotificationHandler = fileWatcherNotificationHandler; - ThreadFactory threadFactory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("FileTreeWatcher-%d").build(); + ThreadFactory threadFactory = new ThreadFactoryBuilder().setDaemon(true) + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) + .setNameFormat("FileTreeWatcher-%d") + .build(); executor = Executors.newSingleThreadExecutor(threadFactory); running = new AtomicBoolean(); watchedDirectories = newHashMap(); diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/VfsEventService.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/VfsEventService.java index f0d66615b90..1756e7adba5 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/VfsEventService.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/impl/file/event/VfsEventService.java @@ -13,6 +13,7 @@ import com.google.common.annotations.Beta; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.slf4j.Logger; import javax.annotation.PostConstruct; @@ -41,6 +42,8 @@ abstract class VfsEventService { VfsEventService() { final String threadName = getClass().getSimpleName().concat("Thread-%d"); final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(threadName) + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(TRUE) .build(); diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/AbstractLuceneSearcherProvider.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/AbstractLuceneSearcherProvider.java index be1be9a5e17..937a89f6cb4 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/AbstractLuceneSearcherProvider.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/AbstractLuceneSearcherProvider.java @@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.vfs.VirtualFileFilter; import org.eclipse.che.api.vfs.VirtualFileFilters; import org.eclipse.che.api.vfs.VirtualFileSystem; @@ -42,6 +43,8 @@ protected AbstractLuceneSearcherProvider(Set excludeFileIndex this.excludeFileIndexFilters = mergeFileIndexFilters(excludeFileIndexFilters); executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() .setDaemon(true) + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setNameFormat("LuceneSearcherInitThread") .build()); } diff --git a/wsmaster/che-core-api-agent/src/main/java/org/eclipse/che/api/agent/server/launcher/AbstractAgentLauncher.java b/wsmaster/che-core-api-agent/src/main/java/org/eclipse/che/api/agent/server/launcher/AbstractAgentLauncher.java index 37140cd99b8..e3429025a9b 100644 --- a/wsmaster/che-core-api-agent/src/main/java/org/eclipse/che/api/agent/server/launcher/AbstractAgentLauncher.java +++ b/wsmaster/che-core-api-agent/src/main/java/org/eclipse/che/api/agent/server/launcher/AbstractAgentLauncher.java @@ -18,6 +18,7 @@ import org.eclipse.che.api.core.model.machine.Command; import org.eclipse.che.api.core.util.AbstractLineConsumer; import org.eclipse.che.api.core.util.LineConsumer; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.machine.server.exception.MachineException; import org.eclipse.che.api.machine.server.model.impl.CommandImpl; import org.eclipse.che.api.machine.server.spi.Instance; @@ -47,6 +48,8 @@ public abstract class AbstractAgentLauncher implements AgentLauncher { private static final Logger LOG = LoggerFactory.getLogger(AbstractAgentLauncher.class); private static final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("AgentLauncher-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build()); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/MachineProcessManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/MachineProcessManager.java index 3acf4659db7..b447b667cd1 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/MachineProcessManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/MachineProcessManager.java @@ -22,6 +22,7 @@ import org.eclipse.che.api.core.util.CompositeLineConsumer; import org.eclipse.che.api.core.util.FileLineConsumer; import org.eclipse.che.api.core.util.LineConsumer; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.core.util.WebsocketLineConsumer; import org.eclipse.che.api.machine.server.exception.MachineException; import org.eclipse.che.api.machine.server.spi.Instance; @@ -75,6 +76,8 @@ public MachineProcessManager(@Named("che.workspace.logs") String machineLogsDir, this.environmentEngine = environmentEngine; executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("MachineProcessManager-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(false) .build()); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index 3c7cccdd00b..7651f763616 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -26,6 +26,7 @@ import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.environment.server.exception.EnvironmentException; import org.eclipse.che.api.machine.server.exception.SnapshotException; import org.eclipse.che.api.machine.server.exception.SourceNotFoundException; @@ -122,6 +123,8 @@ public WorkspaceManager(WorkspaceDao workspaceDao, this.snapshotDao = snapshotDao; executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("WorkspaceManager-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(true) .build()); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java index 259ca9ac5c1..70596332cd5 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java @@ -34,6 +34,7 @@ import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.core.util.AbstractMessageConsumer; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.core.util.MessageConsumer; import org.eclipse.che.api.core.util.WebsocketMessageConsumer; import org.eclipse.che.api.environment.server.CheEnvironmentEngine; @@ -126,6 +127,8 @@ public WorkspaceRuntimes(EventService eventService, this.stripedLocks = new StripedLocks(16); executor = Executors.newFixedThreadPool(2 * Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat("WorkspaceRuntimes-%d") + .setUncaughtExceptionHandler( + LoggingUncaughtExceptionHandler.getInstance()) .setDaemon(false) .build()); } From 3da5a96b3a1ed82723fc348a066c1cdf6d148d7c Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskyi Date: Mon, 28 Nov 2016 12:30:44 +0200 Subject: [PATCH 21/74] Unexpected loss of focus on the project (#3170) * Add ability to set up manual focus to the terminal panel * Fix imports * Add ability to auto select first node when tree becomes visible and it has at least one node * Fixes * Fixes --- .../extension/ExtensionsInitializedEvent.java | 63 +++++++++++++++++++ .../ide/api/parts/ProjectExplorerPart.java | 20 ------ .../che/ide/client/ExtensionInitializer.java | 9 ++- .../eclipse/che/ide/part/PartApiModule.java | 3 - .../project/ProjectExplorerPresenter.java | 25 +++++++- .../project/ProjectPerspective.java | 15 ++--- .../NotificationManagerImplTest.java | 6 -- .../project/ProjectPerspectiveTest.java | 34 ++-------- .../machine/client/MachineExtension.java | 44 +------------ .../inject/factories/TerminalFactory.java | 2 +- .../perspective/terminal/TerminalJso.java | 4 ++ .../terminal/TerminalOptionsJso.java | 4 +- .../terminal/TerminalPresenter.java | 27 +++++--- .../perspective/terminal/TerminalView.java | 10 ++- .../terminal/TerminalViewImpl.java | 29 ++++++--- .../terminal/container/TerminalContainer.java | 2 +- .../client/processes/NewTerminalAction.java | 2 +- .../panel/ProcessesPanelPresenter.java | 39 +++++++----- .../processes/panel/ProcessesPanelView.java | 4 +- .../panel/ProcessesPanelViewImpl.java | 17 ++++- .../client/actions/NewTerminalActionTest.java | 3 +- .../container/TerminalContainerTest.java | 16 ++--- .../recipe/RecipePartPresenterTest.java | 2 - .../panel/ProcessesPanelPresenterTest.java | 48 +++++++------- 24 files changed, 239 insertions(+), 189 deletions(-) create mode 100644 ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/extension/ExtensionsInitializedEvent.java delete mode 100644 ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/ProjectExplorerPart.java diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/extension/ExtensionsInitializedEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/extension/ExtensionsInitializedEvent.java new file mode 100644 index 00000000000..f6ac5222bc4 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/extension/ExtensionsInitializedEvent.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.api.extension; + +import com.google.common.annotations.Beta; +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; + +/** + * Event describes state when all extensions that marked with annotation {@link Extension} have initialized. + * This event may be useful to perform some work when IDE actually has been initialized and displayed. + * + * @author Vlad Zhukovskyi + * @since 5.0.0 + */ +@Beta +public class ExtensionsInitializedEvent extends GwtEvent { + + /** + * A listener is notified when extensions have been already initialized. + * + * @since 5.0.0 + */ + public interface ExtensionsInitializedHandler extends EventHandler { + + /** + * Notifies the listener that extensions have been already initialized. + * + * @param event + * instance of {@link ExtensionsInitializedEvent} + * @see ExtensionsInitializedEvent + * @since 5.0.0 + */ + void onExtensionsInitialized(ExtensionsInitializedEvent event); + } + + private static Type TYPE; + + public static Type getType() { + if (TYPE == null) { + TYPE = new Type<>(); + } + return TYPE; + } + + @Override + public Type getAssociatedType() { + return getType(); + } + + @Override + protected void dispatch(ExtensionsInitializedHandler handler) { + handler.onExtensionsInitialized(this); + } +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/ProjectExplorerPart.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/ProjectExplorerPart.java deleted file mode 100644 index 7583a0003b7..00000000000 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/ProjectExplorerPart.java +++ /dev/null @@ -1,20 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.api.parts; - -/** - * Part with Project Explorer view. - * - * @author Nikolay Zamosenchuk - */ -public interface ProjectExplorerPart extends PartPresenter { - -} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/ExtensionInitializer.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/ExtensionInitializer.java index 6bad4a43a49..9d51cd4b481 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/ExtensionInitializer.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/ExtensionInitializer.java @@ -13,9 +13,11 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; +import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.api.extension.ExtensionDescription; import org.eclipse.che.ide.api.extension.ExtensionRegistry; +import org.eclipse.che.ide.api.extension.ExtensionsInitializedEvent; import org.eclipse.che.ide.util.loging.Log; import java.util.Map; @@ -33,12 +35,15 @@ public class ExtensionInitializer { protected final ExtensionRegistry extensionRegistry; private final ExtensionManager extensionManager; + private final EventBus eventBus; @Inject public ExtensionInitializer(final ExtensionRegistry extensionRegistry, - final ExtensionManager extensionManager) { + final ExtensionManager extensionManager, + EventBus eventBus) { this.extensionRegistry = extensionRegistry; this.extensionManager = extensionManager; + this.eventBus = eventBus; } public void startExtensions() { @@ -54,6 +59,8 @@ public void startExtensions() { Log.error(ExtensionInitializer.class, "Can't initialize extension: " + extensionFqn, e); } } + + eventBus.fireEvent(new ExtensionsInitializedEvent()); } public Map getExtensionDescriptions() { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartApiModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartApiModule.java index 778e641d0e0..0201515af2a 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartApiModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartApiModule.java @@ -24,9 +24,7 @@ import org.eclipse.che.ide.api.parts.PartStackView; import org.eclipse.che.ide.api.parts.Perspective; import org.eclipse.che.ide.api.parts.PerspectiveView; -import org.eclipse.che.ide.api.parts.ProjectExplorerPart; import org.eclipse.che.ide.part.editor.multipart.EditorMultiPartStackPresenter; -import org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter; import org.eclipse.che.ide.part.explorer.project.ProjectExplorerView; import org.eclipse.che.ide.part.explorer.project.ProjectExplorerViewImpl; import org.eclipse.che.ide.workspace.PartStackPresenterFactory; @@ -66,7 +64,6 @@ protected void configure() { // project explorer bind(ProjectExplorerView.class).to(ProjectExplorerViewImpl.class).in(Singleton.class); - bind(ProjectExplorerPart.class).to(ProjectExplorerPresenter.class).in(Singleton.class); } @Provides 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 8ad663012cd..15e70d284ab 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 @@ -25,8 +25,12 @@ 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.ProjectExplorerPart; +import org.eclipse.che.ide.api.parts.PartStack; +import org.eclipse.che.ide.api.parts.PartStackType; +import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.parts.base.BasePresenter; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.Project; @@ -54,6 +58,7 @@ import javax.validation.constraints.NotNull; import static com.google.common.base.MoreObjects.firstNonNull; +import static com.google.common.base.Preconditions.checkNotNull; import static org.eclipse.che.ide.api.resources.ResourceDelta.ADDED; import static org.eclipse.che.ide.api.resources.ResourceDelta.MOVED_FROM; import static org.eclipse.che.ide.api.resources.ResourceDelta.MOVED_TO; @@ -69,7 +74,6 @@ @Singleton @DynaObject public class ProjectExplorerPresenter extends BasePresenter implements ActionDelegate, - ProjectExplorerPart, ResourceChangedHandler, MarkerChangedHandler, SyntheticNodeUpdateEvent.SyntheticNodeUpdateHandler { @@ -91,7 +95,8 @@ public ProjectExplorerPresenter(final ProjectExplorerView view, Resources resources, final ResourceNode.NodeFactory nodeFactory, final SettingsProvider settingsProvider, - final AppContext appContext) { + final AppContext appContext, + final WorkspaceAgent workspaceAgent) { this.view = view; this.nodeFactory = nodeFactory; this.settingsProvider = settingsProvider; @@ -130,6 +135,19 @@ public void onBeforeExpand(BeforeExpandNodeEvent event) { treeExpander = new ProjectExplorerTreeExpander(view.getTree(), appContext); registerNative(); + + final PartStack partStack = checkNotNull(workspaceAgent.getPartStack(PartStackType.NAVIGATION), + "Navigation part stack should not be a null"); + partStack.addPart(this); + partStack.setActivePart(this); + + // 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); + } + }); } /* Expose Project Explorer's internal API to the world, to allow automated Selenium scripts expand all projects tree. */ @@ -162,6 +180,7 @@ private void doCollapse() { } @Override + @SuppressWarnings("unchecked") public void onResourceChanged(ResourceChangedEvent event) { final Tree tree = view.getTree(); final ResourceDelta delta = event.getDelta(); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspective.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspective.java index 872e6a1085e..cb5145e590e 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspective.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspective.java @@ -17,7 +17,6 @@ import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.parts.PartStack; -import org.eclipse.che.ide.api.parts.ProjectExplorerPart; import org.eclipse.che.ide.part.editor.multipart.EditorMultiPartStackPresenter; import org.eclipse.che.ide.workspace.PartStackPresenterFactory; import org.eclipse.che.ide.workspace.PartStackViewFactory; @@ -55,19 +54,16 @@ public ProjectPerspective(PerspectiveViewImpl view, PartStackPresenterFactory stackPresenterFactory, PartStackViewFactory partViewFactory, WorkBenchControllerFactory controllerFactory, - ProjectExplorerPart projectExplorerPart, - NotificationManager notificationManager, EventBus eventBus, - DynaProvider dynaProvider) { + DynaProvider dynaProvider, + NotificationManager notificationManager) { super(PROJECT_PERSPECTIVE_ID, view, stackPresenterFactory, partViewFactory, controllerFactory, eventBus, dynaProvider); - notificationManager.addRule(PROJECT_PERSPECTIVE_ID); - partStacks.put(EDITING, editorMultiPartStackPresenter); addPart(notificationManager, INFORMATION); - addPart(projectExplorerPart, NAVIGATION); - PartStack navigatorPanel = getPartStack(NAVIGATION); + + PartStack navigatorPanel = getPartStack(NAVIGATION); PartStack editorPanel = getPartStack(EDITING); PartStack toolPanel = getPartStack(TOOLING); PartStack infoPanel = getPartStack(INFORMATION); @@ -76,13 +72,10 @@ public ProjectPerspective(PerspectiveViewImpl view, return; } - infoPanel.updateStack(); - navigatorPanel.go(view.getNavigationPanel()); editorPanel.go(view.getEditorPanel()); toolPanel.go(view.getToolPanel()); infoPanel.go(view.getInformationPanel()); - openActivePart(NAVIGATION); } /** {@inheritDoc} */ diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/notification/NotificationManagerImplTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/notification/NotificationManagerImplTest.java index ac4ff67d54d..ab41119e5c0 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/notification/NotificationManagerImplTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/notification/NotificationManagerImplTest.java @@ -12,7 +12,6 @@ import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.gwtmockito.GwtMockitoTestRunner; -import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.notification.Notification; @@ -20,7 +19,6 @@ import org.eclipse.che.ide.api.notification.ReadState; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.part.PartStackPresenter; -import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,13 +48,9 @@ public class NotificationManagerImplTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Resources resources; - @Mock - private EventBus eventBus; @Mock private NotificationManagerView view; @Mock - private DialogFactory dialogFactory; - @Mock private NotificationContainer notificationContainer; @Mock private NotificationPopupStack notificationMessageStack; diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspectiveTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspectiveTest.java index beb94f388c4..6e5a5863932 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspectiveTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/workspace/perspectives/project/ProjectPerspectiveTest.java @@ -19,9 +19,7 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.api.parts.EditorPartStack; import org.eclipse.che.ide.api.parts.PartStackView; -import org.eclipse.che.ide.api.parts.ProjectExplorerPart; import org.eclipse.che.ide.part.PartStackPresenter; import org.eclipse.che.ide.part.editor.multipart.EditorMultiPartStackPresenter; import org.eclipse.che.ide.workspace.PartStackPresenterFactory; @@ -50,18 +48,12 @@ public class ProjectPerspectiveTest { @Mock private PerspectiveViewImpl view; @Mock - private EditorPartStack editorPartStackPresenter; - @Mock private PartStackViewFactory partViewFactory; @Mock private WorkBenchControllerFactory controllerFactory; @Mock private PartStackPresenterFactory stackPresenterFactory; @Mock - private ProjectExplorerPart projectExplorerPart; - @Mock - private NotificationManager notificationManager; - @Mock private EventBus eventBus; @Mock private EditorMultiPartStackPresenter editorMultiPartStackPresenter; @@ -85,6 +77,8 @@ public class ProjectPerspectiveTest { private AcceptsOneWidget container; @Mock private DynaProvider dynaProvider; + @Mock + private NotificationManager notificationManager; private ProjectPerspective perspective; @@ -116,28 +110,9 @@ public void setUp() { stackPresenterFactory, partViewFactory, controllerFactory, - projectExplorerPart, - notificationManager, eventBus, - dynaProvider); - } - - @Test - public void constructorShouldBeVerified() { - when(partStackPresenter.containsPart(projectExplorerPart)).thenReturn(true); - - perspective = new ProjectPerspective(view, - editorMultiPartStackPresenter, - stackPresenterFactory, - partViewFactory, - controllerFactory, - projectExplorerPart, - notificationManager, - eventBus, - dynaProvider); - - verify(partStackPresenter, times(2)).addPart(notificationManager, null); - verify(partStackPresenter).addPart(projectExplorerPart, null); + dynaProvider, + notificationManager); } @Test @@ -151,7 +126,6 @@ public void perspectiveShouldBeDisplayed() { verify(partStackPresenter, times(2)).go(simplePanel); verify(partStackPresenter).go(simpleLayoutPanel); - verify(partStackPresenter).openPreviousActivePart(); verify(container).setWidget(view); } } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java index ae9ed3eaadc..8e0badc50cd 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java @@ -20,7 +20,6 @@ import org.eclipse.che.ide.api.action.ActionManager; import org.eclipse.che.ide.api.action.DefaultActionGroup; import org.eclipse.che.ide.api.action.IdeActions; -import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.constraints.Constraints; import org.eclipse.che.ide.api.extension.Extension; import org.eclipse.che.ide.api.icon.Icon; @@ -29,10 +28,8 @@ import org.eclipse.che.ide.api.keybinding.KeyBuilder; import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; -import org.eclipse.che.ide.api.parts.PartStackType; import org.eclipse.che.ide.api.parts.Perspective; import org.eclipse.che.ide.api.parts.PerspectiveManager; -import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.workspace.event.WorkspaceStartingEvent; import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; import org.eclipse.che.ide.extension.machine.client.actions.CreateMachineAction; @@ -50,10 +47,7 @@ import org.eclipse.che.ide.extension.machine.client.processes.actions.CloseConsoleAction; import org.eclipse.che.ide.extension.machine.client.processes.actions.ReRunProcessAction; import org.eclipse.che.ide.extension.machine.client.processes.actions.StopProcessAction; -import org.eclipse.che.ide.extension.machine.client.processes.panel.ProcessesPanelPresenter; import org.eclipse.che.ide.extension.machine.client.targets.EditTargetsAction; -import org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter; -import org.eclipse.che.ide.statepersistance.AppStateManager; import org.eclipse.che.ide.util.input.KeyCodeMap; import javax.inject.Named; @@ -66,7 +60,6 @@ import static org.eclipse.che.ide.api.action.IdeActions.GROUP_WORKSPACE; import static org.eclipse.che.ide.api.constraints.Anchor.AFTER; import static org.eclipse.che.ide.api.constraints.Constraints.FIRST; -import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; /** * Machine extension entry point. @@ -85,7 +78,6 @@ public class MachineExtension { public static final String GROUP_MACHINES_LIST = "MachinesListGroup"; private final PerspectiveManager perspectiveManager; - private final Provider appStateManagerProvider; /** * Controls central toolbar action group visibility. Use for example next snippet: @@ -100,16 +92,10 @@ public class MachineExtension { @Inject public MachineExtension(final MachineResources machineResources, final EventBus eventBus, - final WorkspaceAgent workspaceAgent, - final AppContext appContext, - final ProcessesPanelPresenter processesPanelPresenter, final Provider machinePortProvider, final PerspectiveManager perspectiveManager, - final Provider machineStatusHandlerProvider, - final ProjectExplorerPresenter projectExplorerPresenter, - final Provider appStateManagerProvider) { + final Provider machineStatusHandlerProvider) { this.perspectiveManager = perspectiveManager; - this.appStateManagerProvider = appStateManagerProvider; machineResources.getCss().ensureInjected(); machineStatusHandlerProvider.get(); @@ -120,20 +106,6 @@ public void onWsAgentStarted(WsAgentStateEvent event) { restoreTerminal(); machinePortProvider.get(); - /* Do not show terminal on factories by default */ - if (appContext.getFactory() == null) { - Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { - @Override - public void execute() { - processesPanelPresenter.selectDevMachine(); - processesPanelPresenter.newTerminal(); - } - }); - workspaceAgent.openPart(processesPanelPresenter, PartStackType.INFORMATION); - } - if (!appStateManagerProvider.get().hasStateForWorkspace(appContext.getWorkspaceId())) { - workspaceAgent.setActivePart(projectExplorerPresenter); - } } @Override @@ -154,25 +126,11 @@ public void onWorkspaceStopped(WorkspaceStoppedEvent event) { Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { - workspaceAgent.setActivePart(projectExplorerPresenter); - processesPanelPresenter.selectDevMachine(); maximizeTerminal(); } }); } }); - - Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { - @Override - public void execute() { - // Add Processes part to Project perspective - perspectiveManager.setPerspectiveId(PROJECT_PERSPECTIVE_ID); - workspaceAgent.openPart(processesPanelPresenter, PartStackType.INFORMATION); - if (appContext.getFactory() == null) { - workspaceAgent.setActivePart(processesPanelPresenter); - } - } - }); } /** diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/factories/TerminalFactory.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/factories/TerminalFactory.java index e76df9f6b47..922c1f5dd40 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/factories/TerminalFactory.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/factories/TerminalFactory.java @@ -31,5 +31,5 @@ public interface TerminalFactory { * machine for which terminal will be created * @return an instance of {@link TerminalPresenter} */ - TerminalPresenter create(@NotNull @Assisted MachineEntity machine); + TerminalPresenter create(@NotNull @Assisted MachineEntity machine, Object source); } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalJso.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalJso.java index 8ad4a379465..42698fdbc0c 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalJso.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalJso.java @@ -49,4 +49,8 @@ public final native void write(String data) /*-{ public final native void focus() /*-{ this.focus(); }-*/; + + public final native void blur() /*-{ + this.blur(); + }-*/; } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalOptionsJso.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalOptionsJso.java index 36c984d4b82..44378bf161e 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalOptionsJso.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalOptionsJso.java @@ -24,7 +24,9 @@ public static native TerminalOptionsJso createDefault() /*-{ cols: 80, rows: 24, useStyle: true, - screenKeys: true + screenKeys: true, + useFocus: false, + useMouse: true } }-*/; } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalPresenter.java index 738d6bdf45c..1a5d4231677 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalPresenter.java @@ -26,12 +26,13 @@ import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper; +import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.collections.Jso; import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.api.machine.MachineEntity; import org.eclipse.che.ide.extension.machine.client.perspective.widgets.tab.content.TabPresenter; -import org.eclipse.che.ide.util.loging.Log; +import org.eclipse.che.ide.extension.machine.client.processes.AddTerminalClickHandler; import org.eclipse.che.ide.websocket.WebSocket; import org.eclipse.che.ide.websocket.events.ConnectionErrorHandler; import org.eclipse.che.ide.websocket.events.ConnectionOpenedHandler; @@ -57,6 +58,7 @@ public class TerminalPresenter implements TabPresenter, TerminalView.ActionDeleg private static final int TIME_BETWEEN_CONNECTIONS = 2_000; private final TerminalView view; + private final Object source; private final NotificationManager notificationManager; private final MachineLocalizationConstant locale; private final MachineEntity machine; @@ -77,8 +79,10 @@ public class TerminalPresenter implements TabPresenter, TerminalView.ActionDeleg public TerminalPresenter(TerminalView view, NotificationManager notificationManager, MachineLocalizationConstant locale, - @Assisted MachineEntity machine) { + @Assisted MachineEntity machine, + @Assisted Object source) { this.view = view; + this.source = source; view.setDelegate(this); this.notificationManager = notificationManager; this.locale = locale; @@ -131,7 +135,8 @@ public void apply(Boolean arg) throws OperationException { }).catchError(new Operation() { @Override public void apply(PromiseError arg) throws OperationException { - notificationManager.notify(locale.failedToConnectTheTerminal(), locale.terminalCanNotLoadScript(), FAIL, NOT_EMERGE_MODE); + notificationManager + .notify(locale.failedToConnectTheTerminal(), locale.terminalCanNotLoadScript(), FAIL, NOT_EMERGE_MODE); reconnect(); } }); @@ -165,6 +170,11 @@ public void onOpen() { view.openTerminal(terminal); + // if terminal was created programmatically then we don't set focus on it + if (source instanceof AddTerminalClickHandler || source instanceof Action) { + setFocus(true); + } + terminal.on(DATA_EVENT_NAME, new Operation() { @Override public void apply(String arg) throws OperationException { @@ -242,7 +252,6 @@ public void setTerminalSize(int x, int y) { } terminal.resize(x, y); - terminal.focus(); Jso jso = Jso.create(); JsArrayInteger arr = Jso.createArray().cast(); arr.set(0, x); @@ -252,10 +261,14 @@ public void setTerminalSize(int x, int y) { socket.send(jso.serialize()); } - /** Set focus on terminal */ - public void setFocus() { + @Override + public void setFocus(boolean focused) { if (connected) { - terminal.focus(); + if (focused) { + terminal.focus(); + } else { + terminal.blur(); + } } } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalView.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalView.java index f13752db4e9..33d7b788e88 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalView.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalView.java @@ -24,8 +24,16 @@ @ImplementedBy(TerminalViewImpl.class) interface TerminalView extends View { - interface ActionDelegate{ + interface ActionDelegate { void setTerminalSize(int x, int y); + + /** + * Set focus on the terminal panel. + * + * @param focused + * {@code true} if terminal should be in focus + */ + void setFocus(boolean focused); } /** diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java index 97760de9420..624e400c807 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java @@ -16,8 +16,8 @@ import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Focusable; import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.Widget; import javax.validation.constraints.NotNull; @@ -27,7 +27,7 @@ * * @author Dmitry Shnurenko */ -final class TerminalViewImpl extends Composite implements TerminalView, RequiresResize{ +final class TerminalViewImpl extends Composite implements TerminalView, Focusable { interface TerminalViewImplUiBinder extends UiBinder { } @@ -76,12 +76,6 @@ public void showErrorMessage(@NotNull String message) { terminalPanel.setVisible(false); } - @Override - public void onResize() { - resizeTimer.cancel(); - resizeTimer.schedule(200); - } - private Timer resizeTimer = new Timer() { @Override public void run() { @@ -103,4 +97,23 @@ private void resizeTerminal() { delegate.setTerminalSize(x, y); } + @Override + public int getTabIndex() { + return 0; + } + + @Override + public void setAccessKey(char key) { + + } + + @Override + public void setFocus(boolean focused) { + delegate.setFocus(focused); + } + + @Override + public void setTabIndex(int index) { + + } } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/container/TerminalContainer.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/container/TerminalContainer.java index 1b547120edb..22db12d2fff 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/container/TerminalContainer.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/container/TerminalContainer.java @@ -58,7 +58,7 @@ public void addOrShowTerminal(MachineEntity machine) { return; } - TerminalPresenter newTerminal = terminalFactory.create(machine); + TerminalPresenter newTerminal = terminalFactory.create(machine, this); terminals.put(machineId, newTerminal); diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/NewTerminalAction.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/NewTerminalAction.java index 2a90412cea2..4ae32b27961 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/NewTerminalAction.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/NewTerminalAction.java @@ -78,7 +78,7 @@ public void updateInPerspective(ActionEvent event) { @Override public void actionPerformed(ActionEvent event) { - processesPanelPresenter.newTerminal(); + processesPanelPresenter.newTerminal(this); } @Override diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java index b3cdb95078c..a6d5cae5e0d 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java @@ -46,6 +46,8 @@ import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.outputconsole.OutputConsole; +import org.eclipse.che.ide.api.parts.PartStack; +import org.eclipse.che.ide.api.parts.PartStackType; import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.parts.base.BasePresenter; import org.eclipse.che.ide.api.ssh.SshServiceClient; @@ -72,13 +74,14 @@ import org.vectomatic.dom.svg.ui.SVGResource; import javax.validation.constraints.NotNull; +import java.util.HashMap; import java.util.ArrayList; import java.util.Collection; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.Collections.emptyList; import static org.eclipse.che.api.core.model.machine.MachineStatus.RUNNING; @@ -120,8 +123,8 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP private final MachineLocalizationConstant localizationConstant; private final MachineResources resources; private final MachineServiceClient machineServiceClient; - private final SshServiceClient sshServiceClient; private final WorkspaceAgent workspaceAgent; + private final SshServiceClient sshServiceClient; private final AppContext appContext; private final NotificationManager notificationManager; private final EntityFactory entityFactory; @@ -158,8 +161,8 @@ public ProcessesPanelPresenter(ProcessesPanelView view, this.localizationConstant = localizationConstant; this.resources = resources; this.machineServiceClient = machineServiceClient; - this.sshServiceClient = sshServiceClient; this.workspaceAgent = workspaceAgent; + this.sshServiceClient = sshServiceClient; this.appContext = appContext; this.notificationManager = notificationManager; this.entityFactory = entityFactory; @@ -188,6 +191,14 @@ public ProcessesPanelPresenter(ProcessesPanelView view, eventBus.addHandler(DownloadWorkspaceOutputEvent.TYPE, this); updateMachineList(); + + final PartStack partStack = checkNotNull(workspaceAgent.getPartStack(PartStackType.INFORMATION), + "Information part stack should not be a null"); + partStack.addPart(this); + + if (appContext.getFactory() == null) { + partStack.setActivePart(this); + } } /** @@ -222,8 +233,6 @@ public void updateMachineList() { view.selectNode(machineToSelect); notifyTreeNodeSelected(machineToSelect); - - workspaceAgent.setActivePart(ProcessesPanelPresenter.this); } @Override @@ -259,7 +268,6 @@ public SVGResource getTitleImage() { @Override public void onMachineCreating(MachineStateEvent event) { - workspaceAgent.setActivePart(this); provideMachineNode(event.getMachine(), false); } @@ -318,13 +326,11 @@ private void closeTerminal(ProcessTreeNode node) { } /** Opens new terminal for the selected machine. */ - public void newTerminal() { - workspaceAgent.setActivePart(this); - + public void newTerminal(Object source) { final ProcessTreeNode selectedTreeNode = view.getSelectedTreeNode(); final MachineEntity devMachine = appContext.getDevMachine(); if (selectedTreeNode == null && devMachine != null) { - onAddTerminal(devMachine.getId()); + onAddTerminal(devMachine.getId(), source); return; } @@ -337,14 +343,14 @@ public void newTerminal() { if (selectedTreeNode.getType() == MACHINE_NODE) { MachineEntity machine = (MachineEntity)selectedTreeNode.getData(); - onAddTerminal(machine.getId()); + onAddTerminal(machine.getId(), source); return; } ProcessTreeNode parent = selectedTreeNode.getParent(); if (parent != null && parent.getType() == MACHINE_NODE) { MachineEntity machine = (MachineEntity)parent.getData(); - onAddTerminal(machine.getId()); + onAddTerminal(machine.getId(), source); } } @@ -369,7 +375,7 @@ public void selectDevMachine() { * id of machine in which the terminal will be added */ @Override - public void onAddTerminal(final String machineId) { + public void onAddTerminal(final String machineId, Object source) { final MachineEntity machine = getMachine(machineId); if (machine == null) { notificationManager.notify(localizationConstant.failedToConnectTheTerminal(), @@ -379,7 +385,7 @@ public void onAddTerminal(final String machineId) { } final ProcessTreeNode machineTreeNode = provideMachineNode(machine, false); - final TerminalPresenter newTerminal = terminalFactory.create(machine); + final TerminalPresenter newTerminal = terminalFactory.create(machine, source); final IsWidget terminalWidget = newTerminal.getView(); final String terminalName = getUniqueTerminalName(machineTreeNode); final ProcessTreeNode terminalNode = new ProcessTreeNode(TERMINAL_NODE, @@ -891,8 +897,6 @@ public void onWorkspaceStarted(WorkspaceStartedEvent event) { notifyTreeNodeSelected(machineToSelect); } - workspaceAgent.setActivePart(ProcessesPanelPresenter.this); - for (MachineEntity machine : machines.values()) { if (RUNNING.equals(machine.getStatus()) && !wsMachines.contains(machine)) { provideMachineNode(machine, true); @@ -954,6 +958,9 @@ public void onWsAgentStarted(WsAgentStateEvent event) { for (MachineEntity machine : machines) { restoreState(machine); } + + selectDevMachine(); + newTerminal(this); } private void restoreState(final MachineEntity machine) { diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java index 54ea2ceb5a8..c7c5df627e5 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java @@ -107,8 +107,10 @@ interface ActionDelegate extends BaseActionDelegate { * * @param machineId * id of machine in which the terminal will be added + * @param source + * source object that called current method */ - void onAddTerminal(String machineId); + void onAddTerminal(String machineId, Object source); /** * Will be called when user clicks 'Preview Ssh' button diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelViewImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelViewImpl.java index caad0e617cd..946e8bbf356 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelViewImpl.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelViewImpl.java @@ -10,10 +10,10 @@ *******************************************************************************/ package org.eclipse.che.ide.extension.machine.client.processes.panel; -import com.google.gwt.core.client.Scheduler; import elemental.events.KeyboardEvent; import elemental.events.MouseEvent; +import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; @@ -22,6 +22,7 @@ import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Focusable; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.SplitLayoutPanel; @@ -88,6 +89,8 @@ public class ProcessesPanelViewImpl extends BaseView> processesPromise; @@ -155,6 +159,7 @@ public void setUp() { when(commandConsoleFactory.create(anyString())).thenReturn(mock(OutputConsole.class)); when(appContext.getWorkspaceId()).thenReturn(WORKSPACE_ID); + when(workspaceAgent.getPartStack(eq(PartStackType.INFORMATION))).thenReturn(partStack); presenter = new ProcessesPanelPresenter(view, localizationConstant, @@ -193,7 +198,6 @@ public void shouldAddMachineWhenMachineCreating() throws Exception { IsWidget widget = mock(IsWidget.class); acceptsOneWidgetCaptor.getValue().setWidget(widget); - verify(workspaceAgent).setActivePart(anyObject()); verify(commandConsoleFactory).create(eq(MACHINE_NAME)); verify(view).addWidget(anyString(), anyString(), anyObject(), anyObject(), anyBoolean()); verify(view).setProcessesData(eq(presenter.rootNode)); @@ -318,14 +322,14 @@ public void shouldHideStopProcessButtonAtAddingTerminal() throws Exception { presenter.rootNode = new ProcessTreeNode(ROOT_NODE, null, null, null, children); TerminalPresenter terminal = mock(TerminalPresenter.class); - when(terminalFactory.create(machine)).thenReturn(terminal); + when(terminalFactory.create(machine, presenter)).thenReturn(terminal); IsWidget terminalWidget = mock(IsWidget.class); when(terminal.getView()).thenReturn(terminalWidget); presenter.addCommandOutput(MACHINE_ID, outputConsole); - presenter.onAddTerminal(MACHINE_ID); + presenter.onAddTerminal(MACHINE_ID, presenter); - verify(terminalFactory).create(eq(machine)); + verify(terminalFactory).create(eq(machine), eq(presenter)); verify(terminal).getView(); verify(view, times(2)).setProcessesData(anyObject()); verify(view, times(2)).selectNode(anyObject()); @@ -387,13 +391,13 @@ public void shouldAddTerminal() throws Exception { presenter.rootNode = new ProcessTreeNode(ROOT_NODE, null, null, null, new ArrayList()); TerminalPresenter terminal = mock(TerminalPresenter.class); - when(terminalFactory.create(machine)).thenReturn(terminal); + when(terminalFactory.create(machine, presenter)).thenReturn(terminal); IsWidget terminalWidget = mock(IsWidget.class); when(terminal.getView()).thenReturn(terminalWidget); - presenter.onAddTerminal(MACHINE_ID); + presenter.onAddTerminal(MACHINE_ID, presenter); - verify(terminalFactory).create(eq(machine)); + verify(terminalFactory).create(eq(machine), eq(presenter)); verify(terminal).getView(); verify(view, times(2)).setProcessesData(anyObject()); verify(view).selectNode(anyObject()); From eb23877b03ea8e393a342cc718695029b84f8809 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskyi Date: Mon, 28 Nov 2016 12:36:12 +0200 Subject: [PATCH 22/74] Correct handling parent element during creating new resource (#3166) * Correct handling parent element during creating new resource * Add missing header --- .../AbstractNewResourceAction.java | 8 +- .../che/ide/newresource/NewFolderAction.java | 8 +- .../AbstractNewResourceActionTest.java | 114 ++++++++++++++++++ .../ide/newresource/NewFolderActionTest.java | 112 +++++++++++++++++ 4 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java create mode 100644 ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java index c073dc48859..9ce5e29f112 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java @@ -87,21 +87,21 @@ public void actionPerformed(ActionEvent e) { new InputCallback() { @Override public void accepted(String value) { - onAccepted(value); + createFile(value); } }, null).withValidator(fileNameValidator); inputDialog.show(); } - private void onAccepted(String value) { - final String name = getExtension().isEmpty() ? value : value + '.' + getExtension(); + final void createFile(String nameWithoutExtension) { + final String name = getExtension().isEmpty() ? nameWithoutExtension : nameWithoutExtension + '.' + getExtension(); Resource resource = appContext.getResource(); if (!(resource instanceof Container)) { final Optional parent = resource.getParent(); - checkState(!parent.isPresent(), "Parent should be a container"); + checkState(parent.isPresent(), "Parent should be a container"); resource = parent.get(); } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java index 720a5382f6a..0ac1f4d54f2 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java @@ -70,24 +70,24 @@ public void actionPerformed(ActionEvent e) { new InputCallback() { @Override public void accepted(String value) { - onAccepted(value); + createFolder(value); } }, null).withValidator(folderNameValidator); inputDialog.show(); } - private void onAccepted(String value) { + final void createFolder(String name) { Resource resource = appContext.getResource(); if (!(resource instanceof Container)) { final Optional parent = resource.getParent(); - checkState(!parent.isPresent(), "Parent should be a container"); + checkState(parent.isPresent(), "Parent should be a container"); resource = parent.get(); } - ((Container)resource).newFolder(value).then(new Operation() { + ((Container)resource).newFolder(name).then(new Operation() { @Override public void apply(Folder folder) throws OperationException { eventBus.fireEvent(new RevealResourceEvent(folder)); diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java new file mode 100644 index 00000000000..82f15755d74 --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.newresource; + +import com.google.common.base.Optional; +import com.google.gwtmockito.GwtMockitoTestRunner; +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.CoreLocalizationConstant; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.resources.Container; +import org.eclipse.che.ide.api.resources.File; +import org.eclipse.che.ide.api.resources.Resource; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Unit tests for the {@link AbstractNewResourceAction}. + * + * @author Vlad Zhukovskyi + */ +@RunWith(GwtMockitoTestRunner.class) +public class AbstractNewResourceActionTest { + + @Mock + DialogFactory dialogFactory; + @Mock + CoreLocalizationConstant coreLocalizationConstant; + @Mock + EventBus eventBus; + @Mock + AppContext appContext; + @Mock + NotificationManager notificationManager; + + @Mock + Resource file; + @Mock + Container parent; + + @Mock + Promise filePromise; + + private AbstractNewResourceAction action; + + @Before + public void setUp() throws Exception { + action = new AbstractNewResourceAction("", + "", + null, + dialogFactory, + coreLocalizationConstant, + eventBus, + appContext, + notificationManager) { + // + }; + } + + @Test + public void testShouldCreateFileIfSelectedFile() throws Exception { + when(file.getParent()).thenReturn(Optional.of(parent)); + when(appContext.getResource()).thenReturn(file); + when(parent.newFile(anyString(), anyString())).thenReturn(filePromise); + when(filePromise.then(any(Operation.class))).thenReturn(filePromise); + when(filePromise.catchError(any(Operation.class))).thenReturn(filePromise); + + action.createFile("name"); + + verify(parent).newFile(eq("name"), eq("")); + } + + @Test + public void testShouldCreateFileIfSelectedContainer() throws Exception { + when(appContext.getResource()).thenReturn(parent); + + when(parent.newFile(anyString(), anyString())).thenReturn(filePromise); + when(filePromise.then(any(Operation.class))).thenReturn(filePromise); + when(filePromise.catchError(any(Operation.class))).thenReturn(filePromise); + + action.createFile("name"); + + verify(parent).newFile(eq("name"), eq("")); + } + + @Test(expected = IllegalStateException.class) + public void testShouldThrowExceptionIfFileDoesNotContainParent() throws Exception { + when(appContext.getResource()).thenReturn(file); + when(file.getParent()).thenReturn(Optional.absent()); + + action.createFile("name"); + } + +} \ No newline at end of file diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java new file mode 100644 index 00000000000..1414f0bd7c8 --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.newresource; + +import com.google.common.base.Optional; +import com.google.gwtmockito.GwtMockitoTestRunner; +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.CoreLocalizationConstant; +import org.eclipse.che.ide.Resources; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.resources.Container; +import org.eclipse.che.ide.api.resources.Folder; +import org.eclipse.che.ide.api.resources.Resource; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Unit tests for the {@link NewFolderAction}. + * + * @author Vlad Zhukovskyi + */ +@RunWith(GwtMockitoTestRunner.class) +public class NewFolderActionTest { + + @Mock + CoreLocalizationConstant coreLocalizationConstant; + @Mock + Resources resources; + @Mock + DialogFactory dialogFactory; + @Mock + EventBus eventBus; + @Mock + AppContext appContext; + @Mock + NotificationManager notificationManager; + + @Mock + Resource file; + @Mock + Container parent; + + @Mock + Promise folderPromise; + + private NewFolderAction action; + + @Before + public void setUp() throws Exception { + action = new NewFolderAction(coreLocalizationConstant, + resources, + dialogFactory, + eventBus, + appContext, notificationManager); + } + + @Test + public void testShouldCreateFolderIfSelectedFile() throws Exception { + when(file.getParent()).thenReturn(Optional.of(parent)); + when(appContext.getResource()).thenReturn(file); + when(parent.newFolder(anyString())).thenReturn(folderPromise); + when(folderPromise.then(any(Operation.class))).thenReturn(folderPromise); + when(folderPromise.catchError(any(Operation.class))).thenReturn(folderPromise); + + action.createFolder("name"); + + verify(parent).newFolder(eq("name")); + } + + @Test + public void testShouldCreateFolderIfSelectedContainer() throws Exception { + when(appContext.getResource()).thenReturn(parent); + + when(parent.newFolder(anyString())).thenReturn(folderPromise); + when(folderPromise.then(any(Operation.class))).thenReturn(folderPromise); + when(folderPromise.catchError(any(Operation.class))).thenReturn(folderPromise); + + action.createFolder("name"); + + verify(parent).newFolder(eq("name")); + } + + @Test(expected = IllegalStateException.class) + public void testShouldThrowExceptionIfFileDoesNotContainParent() throws Exception { + when(appContext.getResource()).thenReturn(file); + when(file.getParent()).thenReturn(Optional.absent()); + + action.createFolder("name"); + } + +} \ No newline at end of file From bfd635d673badcb2dd5c6a7c937c0e3f82c0fe66 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskyi Date: Mon, 28 Nov 2016 13:39:38 +0200 Subject: [PATCH 23/74] Set tooltip with refresh description to the correct button (#3189) --- .../che/ide/part/explorer/project/ProjectExplorerViewImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java index c4d7b4977d2..44a5fc0efec 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java @@ -182,7 +182,7 @@ public void onClick(ClickEvent event) { } }); - Tooltip.create((elemental.dom.Element)collapseAllButton.getElement(), BOTTOM, MIDDLE, "Refresh selected path"); + Tooltip.create((elemental.dom.Element)refreshPathButton.getElement(), BOTTOM, MIDDLE, "Refresh selected path"); refreshPathButton.ensureDebugId(REFRESH_BUTTON_ID); refreshPathButton.setVisible(true); addToolButton(refreshPathButton); From bd5e511518e9398a1a53b3185552080787ee3868 Mon Sep 17 00:00:00 2001 From: Sergii Leschenko Date: Mon, 28 Nov 2016 11:41:38 +0200 Subject: [PATCH 24/74] Move StripedLocks to commons-lang module --- core/commons/che-core-commons-lang/pom.xml | 4 ++ .../lang/concurrent/CloseableLock.java | 30 ++++++++++++++ .../lang/concurrent}/StripedLocks.java | 23 ++++++----- .../server/CheEnvironmentEngine.java | 39 ++++++++++--------- .../workspace/server/WorkspaceRuntimes.java | 30 +++++++------- .../integration-tests/postgresql-tck/pom.xml | 5 +++ 6 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/CloseableLock.java rename {wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server => core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent}/StripedLocks.java (81%) diff --git a/core/commons/che-core-commons-lang/pom.xml b/core/commons/che-core-commons-lang/pom.xml index 492f998e6ac..64e1ba096bf 100644 --- a/core/commons/che-core-commons-lang/pom.xml +++ b/core/commons/che-core-commons-lang/pom.xml @@ -25,6 +25,10 @@ ${project.build.testSourceDirectory}/../resources/findbugs-exclude.xml + + com.google.guava + guava + javax.ws.rs javax.ws.rs-api diff --git a/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/CloseableLock.java b/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/CloseableLock.java new file mode 100644 index 00000000000..c2b057da643 --- /dev/null +++ b/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/CloseableLock.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.commons.lang.concurrent; + +/** + * Lock that is designed to use in try-with-resources statement. + * + *

Implementers should lock on instance creation + * and unlock when {@link CloseableLock#close()} method invokes. + * + * @author Sergii Leschenko + */ +public interface CloseableLock extends AutoCloseable { + /** + * Unlocks this lock. + * + * This method is invoked automatically on objects managed by the + * {@code try}-with-resources statement. + */ + @Override + void close(); +} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/StripedLocks.java b/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/StripedLocks.java similarity index 81% rename from wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/StripedLocks.java rename to core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/StripedLocks.java index c807f07f1a8..ce0c8b26953 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/StripedLocks.java +++ b/core/commons/che-core-commons-lang/src/main/java/org/eclipse/che/commons/lang/concurrent/StripedLocks.java @@ -8,11 +8,10 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.api.workspace.server; +package org.eclipse.che.commons.lang.concurrent; import com.google.common.util.concurrent.Striped; -import java.io.Closeable; import java.util.concurrent.locks.ReadWriteLock; /** @@ -21,15 +20,15 @@ * Examples of usage: *


  *     StripedLocks stripedLocks = new StripedLocks(16);
- *     try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(myKey)) {
+ *     try (CloseableLock lock = stripedLocks.acquireWriteLock(myKey)) {
  *         syncedObject.write();
  *     }
  *
- *     try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(myKey)) {
+ *     try (CloseableLock lock = stripedLocks.acquireReadLock(myKey)) {
  *         syncedObject.read();
  *     }
  *
- *     try (StripedLocks.WriteAllLock lock = stripedLocks.acquireWriteAllLock(myKey)) {
+ *     try (CloseableLock lock = stripedLocks.acquireWriteAllLock(myKey)) {
  *         for (ObjectToSync objectToSync : allObjectsToSync) {
  *             objectToSync.write();
  *         }
@@ -37,9 +36,9 @@
  * 
* * @author Alexander Garagatyi + * @author Sergii Leschenko */ // TODO consider usage of plain map with locks instead of Guava's Striped -// TODO consider moving to the util module of Che core public class StripedLocks { private final Striped striped; @@ -50,21 +49,21 @@ public StripedLocks(int stripesCount) { /** * Acquire read lock for provided key. */ - public ReadLock acquireReadLock(String key) { + public CloseableLock acquireReadLock(String key) { return new ReadLock(key); } /** * Acquire write lock for provided key. */ - public WriteLock acquireWriteLock(String key) { + public CloseableLock acquireWriteLock(String key) { return new WriteLock(key); } /** * Acquire write lock for all possible keys. */ - public WriteAllLock acquireWriteAllLock() { + public CloseableLock acquireWriteAllLock() { return new WriteAllLock(); } @@ -72,7 +71,7 @@ public WriteAllLock acquireWriteAllLock() { * Represents read lock for the provided key. * Can be used as {@link AutoCloseable} to release lock. */ - public class ReadLock implements Closeable { + private class ReadLock implements CloseableLock { private String key; private ReadLock(String key) { @@ -90,7 +89,7 @@ public void close() { * Represents write lock for the provided key. * Can be used as {@link AutoCloseable} to release lock. */ - public class WriteLock implements Closeable { + private class WriteLock implements CloseableLock { private String key; private WriteLock(String key) { @@ -108,7 +107,7 @@ public void close() { * Represents write lock for all possible keys. * Can be used as {@link AutoCloseable} to release locks. */ - public class WriteAllLock implements Closeable { + private class WriteAllLock implements CloseableLock { private WriteAllLock() { for (int i = 0; i < striped.size(); i++) { striped.getAt(i).writeLock().lock(); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java index 9694ee85de9..dc2982a0709 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java @@ -57,7 +57,8 @@ import org.eclipse.che.api.machine.server.spi.SnapshotDao; import org.eclipse.che.api.machine.server.util.RecipeDownloader; import org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; -import org.eclipse.che.api.workspace.server.StripedLocks; +import org.eclipse.che.commons.lang.concurrent.CloseableLock; +import org.eclipse.che.commons.lang.concurrent.StripedLocks; import org.eclipse.che.api.workspace.server.model.impl.ExtendedMachineImpl; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.IoUtil; @@ -165,7 +166,7 @@ public CheEnvironmentEngine(SnapshotDao snapshotDao, */ public List getMachines(String workspaceId) throws EnvironmentNotRunningException { EnvironmentHolder environment; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { environment = environments.get(workspaceId); if (environment == null) { throw new EnvironmentNotRunningException("Environment with ID '" + workspaceId + "' is not found"); @@ -189,7 +190,7 @@ public List getMachines(String workspaceId) throws EnvironmentNotRunni */ public Instance getMachine(String workspaceId, String machineId) throws NotFoundException { EnvironmentHolder environment; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { environment = environments.get(workspaceId); } if (environment == null) { @@ -253,7 +254,7 @@ public List start(String workspaceId, networkId, recover); - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { EnvironmentHolder environmentHolder = environments.get(workspaceId); // possible only if environment was stopped during its start if (environmentHolder == null) { @@ -279,7 +280,7 @@ public void stop(String workspaceId) throws EnvironmentNotRunningException, ServerException { List machinesCopy = null; EnvironmentHolder environmentHolder; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { environmentHolder = environments.get(workspaceId); if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) { throw new EnvironmentNotRunningException( @@ -297,7 +298,7 @@ public void stop(String workspaceId) throws EnvironmentNotRunningException, destroyEnvironment(environmentHolder.networkId, machinesCopy); } - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { environments.remove(workspaceId); } } @@ -328,7 +329,7 @@ public Instance startMachine(String workspaceId, MachineConfig machineConfigCopy = new MachineConfigImpl(machineConfig); EnvironmentHolder environmentHolder; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { environmentHolder = environments.get(workspaceId); if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) { throw new EnvironmentNotRunningException(format("Environment '%s' is not running", workspaceId)); @@ -423,7 +424,7 @@ public void stopMachine(String workspaceId, String machineId) throws NotFoundExc ServerException, ConflictException { Instance targetMachine = null; - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { EnvironmentHolder environmentHolder = environments.get(workspaceId); if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) { throw new EnvironmentNotRunningException(format("Environment '%s' is not running", workspaceId)); @@ -473,7 +474,7 @@ public SnapshotImpl saveSnapshot(String namespace, EnvironmentHolder environmentHolder; SnapshotImpl snapshot = null; Instance instance = null; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { environmentHolder = environments.get(workspaceId); if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) { throw new EnvironmentNotRunningException(format("Environment '%s' is not running", workspaceId)); @@ -558,7 +559,7 @@ private void initializeEnvironment(String namespace, envName, networkId); - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { if (environments.putIfAbsent(workspaceId, environmentHolder) != null) { throw new ConflictException(format("Environment of workspace '%s' already exists", workspaceId)); } @@ -719,7 +720,7 @@ private void startEnvironmentQueue(String namespace, // Config will be null only if there are no machines left in the queue String envName; MessageConsumer envLogger; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { EnvironmentHolder environmentHolder = environments.get(workspaceId); if (environmentHolder == null) { throw new ServerException("Environment start is interrupted."); @@ -740,7 +741,7 @@ private void startEnvironmentQueue(String namespace, String creator = EnvironmentContext.getCurrent().getSubject().getUserId(); CheServiceImpl service; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { EnvironmentHolder environmentHolder = environments.get(workspaceId); if (environmentHolder == null) { throw new ServerException("Environment start is interrupted."); @@ -798,7 +799,7 @@ private void startEnvironmentQueue(String namespace, // polled flag to true if the environment wasn't stopped. // Also polls the proceeded machine configuration from the queue boolean queuePolled = false; - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { ensurePreDestroyIsNotExecuted(); EnvironmentHolder environmentHolder = environments.get(workspaceId); if (environmentHolder != null) { @@ -843,7 +844,7 @@ private void startEnvironmentQueue(String namespace, } } catch (RuntimeException | ServerException e) { EnvironmentHolder env; - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { env = environments.remove(workspaceId); } @@ -999,7 +1000,7 @@ private Machine normalizeMachineSource(MachineImpl machine, MachineSource machin private void addMachine(MachineImpl machine) throws ServerException { Instance instance = new NoOpMachineInstance(machine); - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(machine.getWorkspaceId())) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(machine.getWorkspaceId())) { ensurePreDestroyIsNotExecuted(); EnvironmentHolder environmentHolder = environments.get(machine.getWorkspaceId()); if (environmentHolder != null && environmentHolder.status != EnvStatus.STOPPING) { @@ -1018,7 +1019,7 @@ private int bytesToMB(long bytes) { private void removeMachine(String workspaceId, String machineId) { - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { EnvironmentHolder environmentHolder = environments.get(workspaceId); if (environmentHolder != null) { for (Instance machine : environmentHolder.machines) { @@ -1032,7 +1033,7 @@ private void removeMachine(String workspaceId, } private void replaceMachine(Instance machine) throws ServerException { - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(machine.getWorkspaceId())) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(machine.getWorkspaceId())) { ensurePreDestroyIsNotExecuted(); EnvironmentHolder environmentHolder = environments.get(machine.getWorkspaceId()); if (environmentHolder != null) { @@ -1072,7 +1073,7 @@ private void replaceMachine(Instance machine) throws ServerException { * if pre destroy has been invoked before peek config retrieved */ private String queuePeekOrFail(String workspaceId) throws ServerException { - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { ensurePreDestroyIsNotExecuted(); EnvironmentHolder environmentHolder = environments.get(workspaceId); if (environmentHolder == null || environmentHolder.startQueue == null) { @@ -1278,7 +1279,7 @@ private class MachineCleaner implements EventSubscriber { public void onEvent(InstanceStateEvent event) { if ((event.getType() == OOM) || (event.getType() == DIE)) { EnvironmentHolder environmentHolder; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock("workspaceId")) { + try (CloseableLock lock = stripedLocks.acquireReadLock("workspaceId")) { environmentHolder = environments.get(event.getWorkspaceId()); } if (environmentHolder != null) { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java index 70596332cd5..f07e47e9405 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java @@ -49,6 +49,8 @@ import org.eclipse.che.api.workspace.server.model.impl.WorkspaceRuntimeImpl; import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent; import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType; +import org.eclipse.che.commons.lang.concurrent.CloseableLock; +import org.eclipse.che.commons.lang.concurrent.StripedLocks; import org.eclipse.che.commons.lang.concurrent.ThreadLocalPropagateContext; import org.slf4j.Logger; @@ -154,7 +156,7 @@ public WorkspaceRuntimes(EventService eventService, public RuntimeDescriptor get(String workspaceId) throws NotFoundException, ServerException { WorkspaceState workspaceState; - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { workspaceState = workspaces.get(workspaceId); } if (workspaceState == null) { @@ -268,7 +270,7 @@ public void stop(String workspaceId) throws NotFoundException, ServerException, // The double check is required as it is still possible to get unlucky timing // between locking and stopping workspace. ensurePreDestroyIsNotExecuted(); - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { ensurePreDestroyIsNotExecuted(); WorkspaceState workspaceState = workspaces.get(workspaceId); if (workspaceState == null) { @@ -291,7 +293,7 @@ public void stop(String workspaceId) throws NotFoundException, ServerException, } catch (ServerException | RuntimeException e) { error = e.getLocalizedMessage(); } finally { - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { workspaces.remove(workspaceId); } } @@ -329,7 +331,7 @@ public void stop(String workspaceId) throws NotFoundException, ServerException, * @return true if workspace is running, otherwise false */ public boolean hasRuntime(String workspaceId) { - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { return workspaces.containsKey(workspaceId); } } @@ -355,7 +357,7 @@ public Instance startMachine(String workspaceId, NotFoundException, EnvironmentException { - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { getRunningState(workspaceId); } @@ -368,7 +370,7 @@ public Instance startMachine(String workspaceId, Instance instance = environmentEngine.startMachine(workspaceId, machineConfigCopy, agents); launchAgents(instance, agents); - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { WorkspaceState workspaceState = workspaces.get(workspaceId); if (workspaceState == null || workspaceState.status != RUNNING) { try { @@ -395,7 +397,7 @@ public Instance startMachine(String workspaceId, * @see WorkspaceStatus#SNAPSHOTTING */ public void beginSnapshotting(String workspaceId) throws NotFoundException, ConflictException { - try (StripedLocks.WriteLock ignored = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock ignored = stripedLocks.acquireWriteLock(workspaceId)) { getRunningState(workspaceId).status = SNAPSHOTTING; } } @@ -410,7 +412,7 @@ public void beginSnapshotting(String workspaceId) throws NotFoundException, Conf * @see WorkspaceStatus#SNAPSHOTTING */ public void finishSnapshotting(String workspaceId) { - try (StripedLocks.WriteLock ignored = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock ignored = stripedLocks.acquireWriteLock(workspaceId)) { final WorkspaceState state = workspaces.get(workspaceId); if (state != null && state.status == SNAPSHOTTING) { state.status = RUNNING; @@ -437,7 +439,7 @@ public void finishSnapshotting(String workspaceId) { public void stopMachine(String workspaceId, String machineId) throws NotFoundException, ServerException, ConflictException { - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { WorkspaceState workspaceState = workspaces.get(workspaceId); if (workspaceState == null || workspaceState.status != RUNNING) { throw new ConflictException(format("Environment of workspace '%s' is not running", workspaceId)); @@ -469,7 +471,7 @@ public SnapshotImpl saveMachine(String namespace, ServerException, ConflictException { - try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireReadLock(workspaceId)) { WorkspaceState workspaceState = workspaces.get(workspaceId); if (workspaceState == null || !(workspaceState.status == SNAPSHOTTING || workspaceState.status == RUNNING)) { throw new ConflictException(format("Environment of workspace '%s' is not running or snapshotting", workspaceId)); @@ -534,7 +536,7 @@ public void consume(MachineLogMessage message) throws IOException { void cleanup() { isPreDestroyInvoked = true; - try (StripedLocks.WriteAllLock lock = stripedLocks.acquireWriteAllLock()) { + try (CloseableLock lock = stripedLocks.acquireWriteAllLock()) { for (Map.Entry workspace : workspaces.entrySet()) { if (workspace.getValue().status.equals(RUNNING) || workspace.getValue().status.equals(WorkspaceStatus.STARTING)) { @@ -611,7 +613,7 @@ protected void launchAgents(Instance instance, List agents) throws Serve * saves the state or throws an appropriate exception if the workspace is already initialized. */ private void initState(String workspaceId, String workspaceName, String envName) throws ConflictException, ServerException { - try (StripedLocks.WriteLock ignored = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock ignored = stripedLocks.acquireWriteLock(workspaceId)) { ensurePreDestroyIsNotExecuted(); final WorkspaceState state = workspaces.get(workspaceId); if (state != null) { @@ -637,7 +639,7 @@ private void doStart(EnvironmentImpl environment, getEnvironmentLogger(workspaceId)); launchAgents(environment, machines); - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { WorkspaceState workspaceState = workspaces.get(workspaceId); workspaceState.status = WorkspaceStatus.RUNNING; } @@ -653,7 +655,7 @@ private void doStart(EnvironmentImpl environment, } String environmentStartError = "Start of environment " + envName + " failed. Error: " + e.getLocalizedMessage(); - try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) { + try (CloseableLock lock = stripedLocks.acquireWriteLock(workspaceId)) { workspaces.remove(workspaceId); } publishWorkspaceEvent(EventType.ERROR, diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml index 0a3718b561f..c5a521034b7 100644 --- a/wsmaster/integration-tests/postgresql-tck/pom.xml +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -80,6 +80,11 @@ tests test
+ + org.eclipse.che.core + che-core-api-model + test + org.eclipse.che.core che-core-api-ssh From 92ba698b9a3879c2e346097ee7599d7eeb770dfa Mon Sep 17 00:00:00 2001 From: Yevhenii Voevodin Date: Tue, 29 Nov 2016 13:35:46 +0200 Subject: [PATCH 25/74] Add synthetic id to hashCode & equals methods (#3192) --- .../api/factory/server/jpa/JpaFactoryDao.java | 12 ++-- .../factory/server/model/impl/ActionImpl.java | 32 +++++++---- .../factory/server/model/impl/ButtonImpl.java | 27 +++++---- .../server/model/impl/FactoryImpl.java | 4 ++ .../factory/server/model/impl/IdeImpl.java | 31 ++++++---- .../server/model/impl/OnAppClosedImpl.java | 22 ++++++-- .../server/model/impl/OnAppLoadedImpl.java | 22 ++++++-- .../model/impl/OnProjectsLoadedImpl.java | 22 ++++++-- .../server/spi/tck/FactoryDaoTest.java | 12 ++-- .../server/model/impl/CommandImpl.java | 19 ++++--- .../api/workspace/server/jpa/JpaStackDao.java | 10 +++- .../workspace/server/jpa/JpaWorkspaceDao.java | 30 ++++++---- .../server/model/impl/EnvironmentImpl.java | 30 +++++++--- .../model/impl/ExtendedMachineImpl.java | 37 ++++++++---- .../server/model/impl/ProjectConfigImpl.java | 49 +++++++++------- .../server/model/impl/ServerConf2Impl.java | 29 +++++++--- .../server/model/impl/SourceStorageImpl.java | 29 ++++++---- .../model/impl/WorkspaceConfigImpl.java | 30 +++++----- .../server/model/impl/WorkspaceImpl.java | 4 ++ .../server/jpa/WorkspaceTckModule.java | 32 ++++++++++- .../server/spi/tck/StackDaoTest.java | 7 ++- .../server/spi/tck/WorkspaceDaoTest.java | 13 +++-- .../integration-tests/cascade-removal/pom.xml | 20 +++++++ .../che/core/db/jpa/TestObjectsFactory.java | 56 ++++++++++++++++++- .../integration-tests/postgresql-tck/pom.xml | 20 +++++++ .../src/test/java/PostgreSqlTckModule.java | 29 +++++++++- 26 files changed, 458 insertions(+), 170 deletions(-) diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java index 00ad472a567..b9d616b0b49 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.StringJoiner; +import java.util.stream.Collectors; import static java.lang.String.format; import static java.util.Collections.singletonList; @@ -65,14 +66,14 @@ public FactoryImpl create(FactoryImpl factory) throws ConflictException, ServerE } catch (RuntimeException ex) { throw new ServerException(ex.getLocalizedMessage(), ex); } - return factory; + return new FactoryImpl(factory); } @Override public FactoryImpl update(FactoryImpl update) throws NotFoundException, ConflictException, ServerException { requireNonNull(update); try { - return doUpdate(update); + return new FactoryImpl(doUpdate(update)); } catch (DuplicateKeyException ex) { throw new ConflictException(ex.getLocalizedMessage()); } catch (RuntimeException ex) { @@ -99,7 +100,7 @@ public FactoryImpl getById(String id) throws NotFoundException, ServerException if (factory == null) { throw new NotFoundException(format("Factory with id '%s' doesn't exist", id)); } - return factory; + return new FactoryImpl(factory); } catch (RuntimeException ex) { throw new ServerException(ex.getLocalizedMessage(), ex); } @@ -131,7 +132,10 @@ public List getByAttribute(int maxItems, for (Map.Entry entry : params.entrySet()) { typedQuery.setParameter(entry.getKey(), entry.getValue()); } - return typedQuery.getResultList(); + return typedQuery.getResultList() + .stream() + .map(FactoryImpl::new) + .collect(Collectors.toList()); } catch (RuntimeException ex) { throw new ServerException(ex.getLocalizedMessage(), ex); } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java index fce0d12638b..c4cb65785be 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ActionImpl.java @@ -12,7 +12,6 @@ import org.eclipse.che.api.core.model.factory.Action; -import javax.persistence.Basic; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; @@ -53,7 +52,9 @@ public ActionImpl() {} public ActionImpl(String id, Map properties) { this.id = id; - this.properties = properties; + if (properties != null) { + this.properties = new HashMap<>(properties); + } } public ActionImpl(Action action) { @@ -83,25 +84,32 @@ public void setProperties(Map properties) { @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof ActionImpl)) return false; - final ActionImpl other = (ActionImpl)obj; - return Objects.equals(id, other.getId()) - && getProperties().equals(other.getProperties()); + if (this == obj) { + return true; + } + if (!(obj instanceof ActionImpl)) { + return false; + } + final ActionImpl that = (ActionImpl)obj; + return Objects.equals(entityId, that.entityId) + && Objects.equals(id, that.id) + && getProperties().equals(that.getProperties()); } @Override public int hashCode() { - int result = 7; - result = 31 * result + Objects.hashCode(id); - result = 31 * result + getProperties().hashCode(); - return result; + int hash = 7; + hash = 31 * hash + Objects.hashCode(entityId); + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + getProperties().hashCode(); + return hash; } @Override public String toString() { return "ActionImpl{" + - "id='" + id + '\'' + + "entityId=" + entityId + + ", id='" + id + '\'' + ", properties=" + properties + '}'; } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java index 2654cf363e2..8d5bd6ed04f 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/ButtonImpl.java @@ -76,25 +76,32 @@ public void setType(Type type) { @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof ButtonImpl)) return false; - final ButtonImpl other = (ButtonImpl)obj; - return Objects.equals(attributes, other.attributes) - && Objects.equals(type, other.type); + if (this == obj) { + return true; + } + if (!(obj instanceof ButtonImpl)) { + return false; + } + final ButtonImpl that = (ButtonImpl)obj; + return Objects.equals(id, that.id) + && Objects.equals(attributes, that.attributes) + && Objects.equals(type, that.type); } @Override public int hashCode() { - int result = 7; - result = 31 * result + Objects.hashCode(attributes); - result = 31 * result + Objects.hashCode(type); - return result; + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + Objects.hashCode(attributes); + hash = 31 * hash + Objects.hashCode(type); + return hash; } @Override public String toString() { return "ButtonImpl{" + - "attributes=" + attributes + + "id=" + id + + ", attributes=" + attributes + ", type=" + type + '}'; } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java index 0d25c66dbc6..02174c41338 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/FactoryImpl.java @@ -135,6 +135,10 @@ public FactoryImpl(Factory factory, Set images) { images); } + public FactoryImpl(FactoryImpl factory) { + this(factory, factory.images); + } + @Override public String getId() { return id; diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java index 458b4320624..5931f8bbc93 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/IdeImpl.java @@ -102,27 +102,34 @@ public void setOnAppClosed(OnAppClosedImpl onAppClosed) { @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof IdeImpl)) return false; - final IdeImpl other = (IdeImpl)obj; - return Objects.equals(onAppLoaded, other.onAppLoaded) - && Objects.equals(onProjectsLoaded, other.onProjectsLoaded) - && Objects.equals(onAppClosed, other.onAppClosed); + if (this == obj) { + return true; + } + if (!(obj instanceof IdeImpl)) { + return false; + } + final IdeImpl that = (IdeImpl)obj; + return Objects.equals(id, that.id) + && Objects.equals(onAppLoaded, that.onAppLoaded) + && Objects.equals(onProjectsLoaded, that.onProjectsLoaded) + && Objects.equals(onAppClosed, that.onAppClosed); } @Override public int hashCode() { - int result = 7; - result = 31 * result + Objects.hashCode(onAppLoaded); - result = 31 * result + Objects.hashCode(onProjectsLoaded); - result = 31 * result + Objects.hashCode(onAppClosed); - return result; + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + Objects.hashCode(onAppLoaded); + hash = 31 * hash + Objects.hashCode(onProjectsLoaded); + hash = 31 * hash + Objects.hashCode(onAppClosed); + return hash; } @Override public String toString() { return "IdeImpl{" + - "onAppLoaded=" + onAppLoaded + + "id=" + id + + ", onAppLoaded=" + onAppLoaded + ", onProjectsLoaded=" + onProjectsLoaded + ", onAppClosed=" + onAppClosed + '}'; diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java index 14e872827ef..666a3ea021e 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppClosedImpl.java @@ -23,6 +23,7 @@ import javax.persistence.Table; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static java.util.stream.Collectors.toList; import static javax.persistence.CascadeType.ALL; @@ -75,21 +76,30 @@ public void setActions(List actions) { @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof OnAppClosedImpl)) return false; - final OnAppClosedImpl other = (OnAppClosedImpl)obj; - return getActions().equals(other.getActions()); + if (this == obj) { + return true; + } + if (!(obj instanceof OnAppClosedImpl)) { + return false; + } + final OnAppClosedImpl that = (OnAppClosedImpl)obj; + return Objects.equals(id, that.id) + && getActions().equals(that.getActions()); } @Override public int hashCode() { - return getActions().hashCode(); + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + getActions().hashCode(); + return hash; } @Override public String toString() { return "OnAppClosedImpl{" + - "actions=" + actions + + "id=" + id + + ", actions=" + actions + '}'; } } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java index e9b843e10fe..059d77b3db6 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnAppLoadedImpl.java @@ -23,6 +23,7 @@ import javax.persistence.Table; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Data object for {@link OnAppLoaded}. @@ -75,21 +76,30 @@ public void setActions(List actions) { @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof OnAppLoadedImpl)) return false; - final OnAppLoadedImpl other = (OnAppLoadedImpl)obj; - return getActions().equals(other.getActions()); + if (this == obj) { + return true; + } + if (!(obj instanceof OnAppLoadedImpl)) { + return false; + } + final OnAppLoadedImpl that = (OnAppLoadedImpl)obj; + return Objects.equals(id, that.id) + && getActions().equals(that.getActions()); } @Override public int hashCode() { - return getActions().hashCode(); + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + getActions().hashCode(); + return hash; } @Override public String toString() { return "OnAppLoadedImpl{" + - "actions=" + actions + + "id=" + id + + ", actions=" + actions + '}'; } } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java index 45201efa24b..744d4c8d909 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/model/impl/OnProjectsLoadedImpl.java @@ -24,6 +24,7 @@ import javax.persistence.Table; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static java.util.stream.Collectors.toList; @@ -75,21 +76,30 @@ public void setActions(List actions) { @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof OnProjectsLoadedImpl)) return false; - final OnProjectsLoadedImpl other = (OnProjectsLoadedImpl)obj; - return getActions().equals(other.getActions()); + if (this == obj) { + return true; + } + if (!(obj instanceof OnProjectsLoadedImpl)) { + return false; + } + final OnProjectsLoadedImpl that = (OnProjectsLoadedImpl)obj; + return Objects.equals(id, that.id) + && getActions().equals(that.getActions()); } @Override public int hashCode() { - return getActions().hashCode(); + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + getActions().hashCode(); + return hash; } @Override public String toString() { return "OnProjectsLoadedImpl{" + - "actions=" + actions + + "id=" + id + + ", actions=" + actions + '}'; } } diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java index c9df5b6dbd4..f6f0b806210 100644 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java +++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java @@ -48,16 +48,20 @@ import javax.inject.Inject; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static java.util.stream.Collectors.toList; import static org.testng.Assert.assertEquals; /** @@ -95,8 +99,8 @@ public void setUp() throws Exception { for (int i = 0; i < ENTRY_COUNT; i++) { factories[i] = createFactory(i, users[i].getId()); } - userTckRepository.createAll(asList(users)); - factoryTckRepository.createAll(asList(factories)); + userTckRepository.createAll(Arrays.asList(users)); + factoryTckRepository.createAll(Stream.of(factories).map(FactoryImpl::new).collect(toList())); } @AfterMethod @@ -111,7 +115,7 @@ public void shouldCreateFactory() throws Exception { factory.getCreator().setUserId(factories[0].getCreator().getUserId()); factoryDao.create(factory); - assertEquals(factoryDao.getById(factory.getId()), factory); + assertEquals(factoryDao.getById(factory.getId()), new FactoryImpl(factory)); } @Test(expectedExceptions = NullPointerException.class) @@ -365,8 +369,6 @@ public static WorkspaceConfigImpl createWorkspaceConfig(int index) { wCfg.setProjects(projects); wCfg.setEnvironments(environments); - wCfg.getProjects().forEach(ProjectConfigImpl::prePersistAttributes); - return wCfg; } } diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java index 6063d7735fa..1efe018c1a9 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/CommandImpl.java @@ -117,30 +117,33 @@ public boolean equals(Object obj) { if (!(obj instanceof CommandImpl)) { return false; } - final CommandImpl command = (CommandImpl)obj; - return Objects.equals(name, command.name) && - Objects.equals(commandLine, command.commandLine) && - Objects.equals(type, command.type) && - Objects.equals(getAttributes(), command.getAttributes()); + final CommandImpl that = (CommandImpl)obj; + return Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(commandLine, that.commandLine) + && Objects.equals(type, that.type) + && getAttributes().equals(that.getAttributes()); } @Override public int hashCode() { int hash = 7; + hash = 31 * hash + Objects.hashCode(id); hash = 31 * hash + Objects.hashCode(name); hash = 31 * hash + Objects.hashCode(commandLine); hash = 31 * hash + Objects.hashCode(type); - hash = 31 * hash + Objects.hashCode(getAttributes()); + hash = 31 * hash + getAttributes().hashCode(); return hash; } @Override public String toString() { return "CommandImpl{" + - "name='" + name + '\'' + + "id=" + id + + ", name='" + name + '\'' + ", commandLine='" + commandLine + '\'' + ", type='" + type + '\'' + - ", attributes=" + getAttributes() + + ", attributes=" + attributes + '}'; } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java index eefb27f66c2..12474c59f4b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaStackDao.java @@ -29,6 +29,7 @@ import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import java.util.List; +import java.util.stream.Collectors; import static java.lang.String.format; import static java.util.Objects.requireNonNull; @@ -69,7 +70,7 @@ public StackImpl getById(String id) throws NotFoundException, ServerException { if (stack == null) { throw new NotFoundException(format("Stack with id '%s' doesn't exist", id)); } - return stack; + return new StackImpl(stack); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -89,7 +90,7 @@ public void remove(String id) throws ServerException { public StackImpl update(StackImpl update) throws NotFoundException, ServerException, ConflictException { requireNonNull(update, "Required non-null update"); try { - return doUpdate(update); + return new StackImpl(doUpdate(update)); } catch (DuplicateKeyException x) { throw new ConflictException(format("Stack with name '%s' already exists", update.getName())); } catch (RuntimeException x) { @@ -115,7 +116,10 @@ public List searchStacks(@Nullable String user, try { return query.setMaxResults(maxItems) .setFirstResult(skipCount) - .getResultList(); + .getResultList() + .stream() + .map(StackImpl::new) + .collect(Collectors.toList()); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java index e41e101a8dc..c21e3c511a6 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java @@ -34,6 +34,7 @@ import javax.persistence.EntityManager; import javax.persistence.NoResultException; import java.util.List; +import java.util.stream.Collectors; import static java.lang.String.format; import static java.util.Objects.requireNonNull; @@ -64,14 +65,14 @@ public WorkspaceImpl create(WorkspaceImpl workspace) throws ConflictException, S } catch (RuntimeException x) { throw new ServerException(x.getMessage(), x); } - return workspace; + return new WorkspaceImpl(workspace); } @Override public WorkspaceImpl update(WorkspaceImpl update) throws NotFoundException, ConflictException, ServerException { requireNonNull(update, "Required non-null update"); try { - return doUpdate(update); + return new WorkspaceImpl(doUpdate(update)); } catch (DuplicateKeyException dkEx) { throw new ConflictException(format("Workspace with name '%s' in namespace '%s' already exists", update.getConfig().getName(), @@ -100,7 +101,7 @@ public WorkspaceImpl get(String id) throws NotFoundException, ServerException { if (workspace == null) { throw new NotFoundException(format("Workspace with id '%s' doesn't exist", id)); } - return workspace; + return new WorkspaceImpl(workspace); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -112,11 +113,11 @@ public WorkspaceImpl get(String name, String namespace) throws NotFoundException requireNonNull(name, "Required non-null name"); requireNonNull(namespace, "Required non-null namespace"); try { - return managerProvider.get() - .createNamedQuery("Workspace.getByName", WorkspaceImpl.class) - .setParameter("namespace", namespace) - .setParameter("name", name) - .getSingleResult(); + return new WorkspaceImpl(managerProvider.get() + .createNamedQuery("Workspace.getByName", WorkspaceImpl.class) + .setParameter("namespace", namespace) + .setParameter("name", name) + .getSingleResult()); } catch (NoResultException noResEx) { throw new NotFoundException(format("Workspace with name '%s' in namespace '%s' doesn't exist", name, @@ -134,7 +135,10 @@ public List getByNamespace(String namespace) throws ServerExcepti return managerProvider.get() .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) .setParameter("namespace", namespace) - .getResultList(); + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(Collectors.toList()); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -143,9 +147,13 @@ public List getByNamespace(String namespace) throws ServerExcepti @Override @Transactional public List getWorkspaces(String userId) throws ServerException { - // TODO respect userId when workers become a part of che try { - return managerProvider.get().createNamedQuery("Workspace.getAll", WorkspaceImpl.class).getResultList(); + return managerProvider.get() + .createNamedQuery("Workspace.getAll", WorkspaceImpl.class) + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(Collectors.toList()); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java index 50151c1a323..97c03aed483 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/EnvironmentImpl.java @@ -25,6 +25,7 @@ import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; import javax.persistence.Table; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -89,6 +90,9 @@ public void setRecipe(EnvironmentRecipeImpl environmentRecipe) { @Override public Map getMachines() { + if (machines == null) { + machines = new HashMap<>(); + } return machines; } @@ -97,23 +101,33 @@ public void setMachines(Map machines) { } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof EnvironmentImpl)) return false; - EnvironmentImpl that = (EnvironmentImpl)o; - return Objects.equals(recipe, that.recipe) && - Objects.equals(machines, that.machines); + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof EnvironmentImpl)) { + return false; + } + final EnvironmentImpl that = (EnvironmentImpl)obj; + return Objects.equals(id, that.id) + && Objects.equals(recipe, that.recipe) + && getMachines().equals(that.getMachines()); } @Override public int hashCode() { - return Objects.hash(recipe, machines); + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + Objects.hashCode(recipe); + hash = 31 * hash + getMachines().hashCode(); + return hash; } @Override public String toString() { return "EnvironmentImpl{" + - "recipe=" + recipe + + "id=" + id + + ", recipe=" + recipe + ", machines=" + machines + '}'; } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java index 69099971194..a4e7a9faed4 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ExtendedMachineImpl.java @@ -87,6 +87,9 @@ public ExtendedMachineImpl(ExtendedMachine machine) { @Override public List getAgents() { + if (agents == null) { + agents = new ArrayList<>(); + } return agents; } @@ -118,6 +121,9 @@ public ExtendedMachineImpl withServers(Map servers) { @Override public Map getAttributes() { + if (attributes == null) { + attributes = new HashMap<>(); + } return attributes; } @@ -131,26 +137,37 @@ public ExtendedMachineImpl withAttributes(Map attributes) { } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ExtendedMachineImpl)) return false; - ExtendedMachineImpl that = (ExtendedMachineImpl)o; - return Objects.equals(agents, that.agents) && - Objects.equals(servers, that.servers) && - Objects.equals(attributes, that.attributes); + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ExtendedMachineImpl)) { + return false; + } + final ExtendedMachineImpl that = (ExtendedMachineImpl)obj; + return Objects.equals(id, that.id) + && getAgents().equals(that.getAgents()) + && getAttributes().equals(that.getAttributes()) + && getServers().equals(that.getServers()); } @Override public int hashCode() { - return Objects.hash(agents, servers, attributes); + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + getAgents().hashCode(); + hash = 31 * hash + getAttributes().hashCode(); + hash = 31 * hash + getServers().hashCode(); + return hash; } @Override public String toString() { return "ExtendedMachineImpl{" + - "agents=" + agents + - ", servers=" + servers + + "id=" + id + + ", agents=" + agents + ", attributes=" + attributes + + ", servers=" + servers + '}'; } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java index 3c3589a7fc4..63681e1d940 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ProjectConfigImpl.java @@ -175,42 +175,49 @@ public void setSource(SourceStorageImpl sourceStorage) { } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ProjectConfigImpl)) return false; - final ProjectConfigImpl other = (ProjectConfigImpl)o; - return Objects.equals(name, other.name) - && Objects.equals(path, other.path) - && Objects.equals(description, other.description) - && Objects.equals(type, other.type) - && getMixins().equals(other.getMixins()) - && getAttributes().equals(other.getAttributes()) - && Objects.equals(source, other.getSource()); + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ProjectConfigImpl)) { + return false; + } + final ProjectConfigImpl that = (ProjectConfigImpl)obj; + return Objects.equals(id, that.id) + && Objects.equals(path, that.path) + && Objects.equals(name, that.name) + && Objects.equals(type, that.type) + && Objects.equals(description, that.description) + && Objects.equals(source, that.source) + && getMixins().equals(that.getMixins()) + && getAttributes().equals(that.getAttributes()); } @Override public int hashCode() { int hash = 7; - hash = hash * 31 + Objects.hashCode(name); - hash = hash * 31 + Objects.hashCode(path); - hash = hash * 31 + Objects.hashCode(description); - hash = hash * 31 + Objects.hashCode(type); - hash = hash * 31 + getMixins().hashCode(); - hash = hash * 31 + getAttributes().hashCode(); - hash = hash * 31 + Objects.hashCode(source); + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + Objects.hashCode(path); + hash = 31 * hash + Objects.hashCode(name); + hash = 31 * hash + Objects.hashCode(type); + hash = 31 * hash + Objects.hashCode(description); + hash = 31 * hash + Objects.hashCode(source); + hash = 31 * hash + getMixins().hashCode(); + hash = 31 * hash + getAttributes().hashCode(); return hash; } @Override public String toString() { return "ProjectConfigImpl{" + - "name='" + name + '\'' + + "id=" + id + ", path='" + path + '\'' + - ", description='" + description + '\'' + + ", name='" + name + '\'' + ", type='" + type + '\'' + + ", description='" + description + '\'' + + ", source=" + source + ", mixins=" + mixins + ", attributes=" + attributes + - ", source=" + source + '}'; } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java index f972c69db81..48d9d12bbcd 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/ServerConf2Impl.java @@ -102,24 +102,35 @@ public void setProperties(Map properties) { } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ServerConf2Impl)) return false; - ServerConf2Impl that = (ServerConf2Impl)o; - return Objects.equals(port, that.port) && - Objects.equals(protocol, that.protocol) && - Objects.equals(properties, that.properties); + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ServerConf2Impl)) { + return false; + } + final ServerConf2Impl that = (ServerConf2Impl)obj; + return Objects.equals(id, that.id) + && Objects.equals(port, that.port) + && Objects.equals(protocol, that.protocol) + && getProperties().equals(that.getProperties()); } @Override public int hashCode() { - return Objects.hash(port, protocol, properties); + int hash = 7; + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + Objects.hashCode(port); + hash = 31 * hash + Objects.hashCode(protocol); + hash = 31 * hash + getProperties().hashCode(); + return hash; } @Override public String toString() { return "ServerConf2Impl{" + - "port='" + port + '\'' + + "id=" + id + + ", port='" + port + '\'' + ", protocol='" + protocol + '\'' + ", properties=" + properties + '}'; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java index 08b18ac74b7..b88d906204b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/SourceStorageImpl.java @@ -94,28 +94,35 @@ public void setParameters(Map parameters) { } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SourceStorageImpl)) return false; - final SourceStorageImpl other = (SourceStorageImpl)o; - return Objects.equals(type, other.type) && - Objects.equals(location, other.location) && - getParameters().equals(other.getParameters()); + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof SourceStorageImpl)) { + return false; + } + final SourceStorageImpl that = (SourceStorageImpl)obj; + return Objects.equals(id, that.id) + && Objects.equals(type, that.type) + && Objects.equals(location, that.location) + && getParameters().equals(that.getParameters()); } @Override public int hashCode() { int hash = 7; - hash = hash * 31 + Objects.hashCode(type); - hash = hash * 31 + Objects.hashCode(location); - hash = hash * 31 + getParameters().hashCode(); + hash = 31 * hash + Objects.hashCode(id); + hash = 31 * hash + Objects.hashCode(type); + hash = 31 * hash + Objects.hashCode(location); + hash = 31 * hash + getParameters().hashCode(); return hash; } @Override public String toString() { return "SourceStorageImpl{" + - "type='" + type + '\'' + + "id=" + id + + ", type='" + type + '\'' + ", location='" + location + '\'' + ", parameters=" + parameters + '}'; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java index 47340d0f7a7..1376f13778b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java @@ -26,8 +26,6 @@ import javax.persistence.JoinColumn; import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; -import javax.persistence.PrePersist; -import javax.persistence.PreUpdate; import javax.persistence.Table; import java.util.ArrayList; import java.util.HashMap; @@ -184,26 +182,32 @@ public void setEnvironments(Map environments) { @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof WorkspaceConfigImpl)) return false; - final WorkspaceConfigImpl other = (WorkspaceConfigImpl)obj; - return Objects.equals(name, other.name) - && Objects.equals(defaultEnv, other.defaultEnv) - && getCommands().equals(other.getCommands()) - && getEnvironments().equals(other.getEnvironments()) - && getProjects().equals(other.getProjects()) - && Objects.equals(description, other.description); + if (this == obj) { + return true; + } + if (!(obj instanceof WorkspaceConfigImpl)) { + return false; + } + final WorkspaceConfigImpl that = (WorkspaceConfigImpl)obj; + return Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(description, that.description) + && Objects.equals(defaultEnv, that.defaultEnv) + && getCommands().equals(that.getCommands()) + && getProjects().equals(that.getProjects()) + && getEnvironments().equals(that.getEnvironments()); } @Override public int hashCode() { int hash = 7; + hash = 31 * hash + Objects.hashCode(id); hash = 31 * hash + Objects.hashCode(name); + hash = 31 * hash + Objects.hashCode(description); hash = 31 * hash + Objects.hashCode(defaultEnv); hash = 31 * hash + getCommands().hashCode(); - hash = 31 * hash + getEnvironments().hashCode(); hash = 31 * hash + getProjects().hashCode(); - hash = 31 * hash + Objects.hashCode(description); + hash = 31 * hash + getEnvironments().hashCode(); return hash; } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java index b4f09cda382..164584e8173 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java @@ -152,6 +152,10 @@ public WorkspaceImpl(Workspace workspace, Account account) { workspace.getStatus()); } + public WorkspaceImpl(WorkspaceImpl workspace) { + this(workspace, workspace.account); + } + @Override public String getId() { return id; diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java index 39176866ee4..eefa8371e39 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java @@ -14,6 +14,7 @@ import com.google.inject.persist.jpa.JpaPersistModule; import org.eclipse.che.account.spi.AccountImpl; +import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; import org.eclipse.che.api.workspace.server.spi.StackDao; @@ -24,10 +25,13 @@ import org.eclipse.che.commons.test.tck.TckResourcesCleaner; import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; import org.eclipse.che.core.db.DBInitializer; import org.eclipse.che.core.db.schema.SchemaInitializer; import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer; +import java.util.Collection; + /** * @author Yevhenii Voevodin */ @@ -41,10 +45,34 @@ protected void configure() { bind(TckResourcesCleaner.class).to(H2JpaCleaner.class); bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(AccountImpl.class)); - bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(WorkspaceImpl.class)); - bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(StackImpl.class)); + bind(new TypeLiteral>() {}).toInstance(new WorkspaceRepository()); + bind(new TypeLiteral>() {}).toInstance(new StackRepository()); bind(WorkspaceDao.class).to(JpaWorkspaceDao.class); bind(StackDao.class).to(JpaStackDao.class); } + + private static class WorkspaceRepository extends JpaTckRepository { + public WorkspaceRepository() { super(WorkspaceImpl.class); } + + @Override + public void createAll(Collection entities) throws TckRepositoryException { + for (WorkspaceImpl entity : entities) { + entity.getConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); + } + super.createAll(entities); + } + } + + private static class StackRepository extends JpaTckRepository { + public StackRepository() { super(StackImpl.class); } + + @Override + public void createAll(Collection entities) throws TckRepositoryException { + for (StackImpl stack : entities) { + stack.getWorkspaceConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); + } + super.createAll(entities); + } + } } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/StackDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/StackDaoTest.java index d64f7d496e2..2a100e28b82 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/StackDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/StackDaoTest.java @@ -19,6 +19,7 @@ import org.eclipse.che.api.machine.server.spi.SnapshotDao; import org.eclipse.che.api.workspace.server.event.StackPersistedEvent; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackComponentImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackSourceImpl; @@ -35,8 +36,10 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.stream.Stream; import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toList; import static org.eclipse.che.api.workspace.server.spi.tck.WorkspaceDaoTest.createWorkspaceConfig; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -71,7 +74,7 @@ private void createStacks() throws TckRepositoryException { for (int i = 0; i < STACKS_SIZE; i++) { stacks[i] = createStack("stack-" + i, "name-" + i); } - stackRepo.createAll(asList(stacks)); + stackRepo.createAll(Stream.of(stacks).map(StackImpl::new).collect(toList())); } @AfterMethod @@ -102,7 +105,7 @@ public void shouldCreateStack() throws Exception { stackDao.create(stack); - assertEquals(stackDao.getById(stack.getId()), stack); + assertEquals(stackDao.getById(stack.getId()), new StackImpl(stack)); } @Test(expectedExceptions = ConflictException.class) diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java index 254afc946f8..eaa70c8a632 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java @@ -38,14 +38,17 @@ import javax.inject.Inject; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; import static java.util.Arrays.asList; import static java.util.Collections.singletonMap; +import static java.util.stream.Collectors.toList; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -96,15 +99,15 @@ public void createEntities() throws TckRepositoryException { // 2 workspaces share 1 namespace workspaces[i] = createWorkspace("workspace-" + i, accounts[i / 2], "name-" + i); } - accountRepo.createAll(asList(accounts)); - workspaceRepo.createAll(asList(workspaces)); + accountRepo.createAll(Arrays.asList(accounts)); + workspaceRepo.createAll(Stream.of(workspaces).map(WorkspaceImpl::new).collect(toList())); } @Test public void shouldGetWorkspaceById() throws Exception { final WorkspaceImpl workspace = workspaces[0]; - assertEquals(workspaceDao.get(workspace.getId()), workspace); + assertEquals(workspaceDao.get(workspace.getId()), new WorkspaceImpl(workspace)); } @Test(expectedExceptions = NotFoundException.class) @@ -142,7 +145,7 @@ public void shouldThrowNpeWhenGettingWorkspaceByNullNamespace() throws Exception public void shouldGetWorkspaceByNameAndNamespace() throws Exception { final WorkspaceImpl workspace = workspaces[0]; - assertEquals(workspaceDao.get(workspace.getConfig().getName(), workspace.getNamespace()), workspace); + assertEquals(workspaceDao.get(workspace.getConfig().getName(), workspace.getNamespace()), new WorkspaceImpl(workspace)); } @Test(expectedExceptions = NotFoundException.class) @@ -485,8 +488,6 @@ public static WorkspaceConfigImpl createWorkspaceConfig(String name) { wCfg.setProjects(projects); wCfg.setEnvironments(new HashMap<>(environments)); - wCfg.getProjects().forEach(ProjectConfigImpl::prePersistAttributes); - return wCfg; } diff --git a/wsmaster/integration-tests/cascade-removal/pom.xml b/wsmaster/integration-tests/cascade-removal/pom.xml index 929e344c091..a62055f9a42 100644 --- a/wsmaster/integration-tests/cascade-removal/pom.xml +++ b/wsmaster/integration-tests/cascade-removal/pom.xml @@ -56,6 +56,11 @@ che-core-api-account test + + org.eclipse.che.core + che-core-api-agent + test + org.eclipse.che.core che-core-api-core @@ -66,11 +71,21 @@ che-core-api-machine test + + org.eclipse.che.core + che-core-api-model + test + org.eclipse.che.core che-core-api-ssh test + + org.eclipse.che.core + che-core-api-ssh-shared + test + org.eclipse.che.core che-core-api-user @@ -81,6 +96,11 @@ che-core-api-workspace test + + org.eclipse.che.core + che-core-api-workspace-shared + test + org.eclipse.che.core che-core-commons-inject diff --git a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/TestObjectsFactory.java b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/TestObjectsFactory.java index b5dd6f3f5cb..cf400183b9f 100644 --- a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/TestObjectsFactory.java +++ b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/TestObjectsFactory.java @@ -10,14 +10,22 @@ *******************************************************************************/ package org.eclipse.che.core.db.jpa; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.eclipse.che.account.shared.model.Account; +import org.eclipse.che.api.machine.server.model.impl.CommandImpl; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl; import org.eclipse.che.api.user.server.model.impl.ProfileImpl; import org.eclipse.che.api.user.server.model.impl.UserImpl; +import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; +import org.eclipse.che.api.workspace.server.model.impl.EnvironmentRecipeImpl; +import org.eclipse.che.api.workspace.server.model.impl.ExtendedMachineImpl; +import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.ServerConf2Impl; +import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackComponentImpl; @@ -29,6 +37,8 @@ import java.util.Map; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; /** * Defines method for creating tests object instances. @@ -61,9 +71,49 @@ public static WorkspaceConfigImpl createWorkspaceConfig(String id) { return new WorkspaceConfigImpl(id + "_name", id + "description", "default-env", - null, - null, - null); + asList(new CommandImpl(id + "cmd1", "mvn clean install", "maven"), + new CommandImpl(id + "cmd2", "mvn clean install", "maven")), + asList(createProjectConfig(id + "-project1"), + createProjectConfig(id + "-project2")), + ImmutableMap.of(id + "env1", createEnv(), + id + "env2", createEnv())); + } + + public static ProjectConfigImpl createProjectConfig(String name) { + final ProjectConfigImpl project = new ProjectConfigImpl(); + project.setDescription(name + "-description"); + project.setName(name); + project.setPath("/" + name); + project.setType(name + "type"); + project.setSource(new SourceStorageImpl("source-type", + "source-location", + ImmutableMap.of("param1", "value", + "param2", "value"))); + project.setMixins(asList("mixin1", "mixin2")); + project.getAttributes().put("attribute1", singletonList("value1")); + project.getAttributes().put("attribute2", singletonList("value2")); + project.getAttributes().put("attribute3", singletonList("value3")); + return project; + } + + public static EnvironmentImpl createEnv() { + final EnvironmentRecipeImpl newRecipe = new EnvironmentRecipeImpl(); + newRecipe.setLocation("new-location"); + newRecipe.setType("new-type"); + newRecipe.setContentType("new-content-type"); + newRecipe.setContent("new-content"); + + final ExtendedMachineImpl newMachine = new ExtendedMachineImpl(); + final ServerConf2Impl serverConf1 = new ServerConf2Impl("2265", "http", ImmutableMap.of("prop1", "val")); + final ServerConf2Impl serverConf2 = new ServerConf2Impl("2266", "ftp", ImmutableMap.of("prop1", "val")); + newMachine.setServers(ImmutableMap.of("ref1", serverConf1, "ref2", serverConf2)); + newMachine.setAgents(ImmutableList.of("agent5", "agent4")); + newMachine.setAttributes(singletonMap("att1", "val")); + + final EnvironmentImpl newEnv = new EnvironmentImpl(); + newEnv.setMachines(ImmutableMap.of("new-machine", newMachine)); + newEnv.setRecipe(newRecipe); + return newEnv; } public static WorkspaceImpl createWorkspace(String id, Account account) { diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml index c5a521034b7..b370e7e2060 100644 --- a/wsmaster/integration-tests/postgresql-tck/pom.xml +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -85,6 +85,16 @@ che-core-api-model test + + org.eclipse.che.core + che-core-api-machine + test + + + org.eclipse.che.core + che-core-api-model + test + org.eclipse.che.core che-core-api-ssh @@ -96,6 +106,11 @@ tests test + + org.eclipse.che.core + che-core-api-ssh-shared + test + org.eclipse.che.core che-core-api-user @@ -112,6 +127,11 @@ tests test + + org.eclipse.che.core + che-core-api-workspace-shared + test + org.eclipse.che.core che-core-commons-test diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java index fdc3d40b144..3a163abe2ea 100644 --- a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java +++ b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java @@ -37,6 +37,7 @@ import org.eclipse.che.api.user.server.spi.UserDao; import org.eclipse.che.api.workspace.server.jpa.JpaStackDao; import org.eclipse.che.api.workspace.server.jpa.JpaWorkspaceDao; +import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; import org.eclipse.che.api.workspace.server.spi.StackDao; @@ -140,8 +141,8 @@ protected void configure() { // workspace bind(WorkspaceDao.class).to(JpaWorkspaceDao.class); bind(StackDao.class).to(JpaStackDao.class); - bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(WorkspaceImpl.class)); - bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(StackImpl.class)); + bind(new TypeLiteral>() {}).toInstance(new WorkspaceRepository()); + bind(new TypeLiteral>() {}).toInstance(new StackRepository()); } private static void waitConnectionIsEstablished(String dbUrl, String dbUser, String dbPassword) { @@ -229,4 +230,28 @@ public void createAll(Collection entities) throws TckReposi .collect(Collectors.toList())); } } + + private static class WorkspaceRepository extends JpaTckRepository { + public WorkspaceRepository() { super(WorkspaceImpl.class); } + + @Override + public void createAll(Collection entities) throws TckRepositoryException { + for (WorkspaceImpl entity : entities) { + entity.getConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); + } + super.createAll(entities); + } + } + + private static class StackRepository extends JpaTckRepository { + public StackRepository() { super(StackImpl.class); } + + @Override + public void createAll(Collection entities) throws TckRepositoryException { + for (StackImpl stack : entities) { + stack.getWorkspaceConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); + } + super.createAll(entities); + } + } } From 3d074de155fac45896107a284283339c60b59a87 Mon Sep 17 00:00:00 2001 From: Yevhenii Voevodin Date: Tue, 29 Nov 2016 14:16:46 +0200 Subject: [PATCH 26/74] Fix postgresql/pom.xml dependencies order --- wsmaster/integration-tests/postgresql-tck/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml index b370e7e2060..36dae7da820 100644 --- a/wsmaster/integration-tests/postgresql-tck/pom.xml +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -82,12 +82,12 @@ org.eclipse.che.core - che-core-api-model + che-core-api-machine test org.eclipse.che.core - che-core-api-machine + che-core-api-model test From 83439293465b5a8a6da8b0d302cd576b3bc2f5f4 Mon Sep 17 00:00:00 2001 From: Alexander Garagatyi Date: Tue, 29 Nov 2016 16:57:21 +0200 Subject: [PATCH 27/74] Fix maven warnings (#3201) Signed-off-by: Alexander Garagatyi --- .../che-java-testing-core/pom.xml | 13 +++++++++++-- .../che-java-testing-junit/pom.xml | 12 +++++++++++- wsmaster/integration-tests/postgresql-tck/pom.xml | 5 ----- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml index 3e83a2e2e47..a2fd7c69ab7 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml @@ -26,6 +26,15 @@ che-java-testing-core-ide che-java-testing-core-shared - - + + + + + org.eclipse.che.core + che-core-api-dto-maven-plugin + ${project.version} + + + + diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml index 9bf590a8097..535bd531d5b 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml @@ -26,5 +26,15 @@ che-java-testing-junit-shared che-java-testing-junit-ide - + + + + + org.eclipse.che.core + che-core-api-dto-maven-plugin + ${project.version} + + + + diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml index 36dae7da820..9f27b5ba604 100644 --- a/wsmaster/integration-tests/postgresql-tck/pom.xml +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -90,11 +90,6 @@ che-core-api-model test - - org.eclipse.che.core - che-core-api-model - test - org.eclipse.che.core che-core-api-ssh From 1652aef49044ee300b3cf0d0a7fa4db226c84c7a Mon Sep 17 00:00:00 2001 From: Anatoliy Bazko Date: Wed, 30 Nov 2016 09:22:57 +0200 Subject: [PATCH 28/74] CHE-3205: Fix typo in stack.json (#3206) --- ide/che-core-ide-stacks/src/main/resources/stacks.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 fb37eee48a0..83448facb56 100644 --- a/ide/che-core-ide-stacks/src/main/resources/stacks.json +++ b/ide/che-core-ide-stacks/src/main/resources/stacks.json @@ -598,7 +598,7 @@ "PHP", "mysql", "sqlite", - "Apaide", + "Apache", "dockerimager" ], "components": [ @@ -607,7 +607,7 @@ "version": "5.5.9" }, { - "name": "Apaide", + "name": "Apache", "version": "2" }, { From f1710e6a9b46ed5ec6f2ee8829af9fb200026b0e Mon Sep 17 00:00:00 2001 From: Kaloyan Raev Date: Wed, 30 Nov 2016 16:17:14 +0200 Subject: [PATCH 29/74] Performance improvements and other fixes in code completion (#3146) * Avoid overloading the DOM tree of the ContentAssistWidget Signed-off-by: Kaloyan Raev * Ensure the code assist widget is closed when applying proposal Signed-off-by: Kaloyan Raev * Respect isIncomplete flag in the completion result If the isIncomplete flag is false, i.e. the completion result is complete, then additional typing for the same word should not trigger a new completion request. The latest completion result should be reused. Signed-off-by: Kaloyan Raev * Fix flickering between keystrokes during code completion Signed-off-by: Kaloyan Raev * Fine tune the rules for making new completion request Signed-off-by: Kaloyan Raev * Set the correct offset when applying code completion * Force a completion request message on Ctrl+Space Signed-off-by: Kaloyan Raev * Fixed retrieval of CompletionItem document via Resolve request Signed-off-by: Kaloyan Raev --- .../codeassist/CodeAssistProcessor.java | 19 +- .../api/editor/codeassist/CodeAssistant.java | 3 +- .../editor/codeassist/CodeAssistantImpl.java | 6 +- .../editor/codeassist/CompletionProposal.java | 7 +- .../DefaultChainedCodeAssistProcessor.java | 4 +- .../api/editor/texteditor/TextEditorInit.java | 9 +- .../editor/ActionCompletionProposal.java | 7 +- .../editor/JavaCodeAssistProcessor.java | 4 +- .../client/editor/JavaCompletionProposal.java | 4 +- .../che-plugin-languageserver-ide/pom.xml | 9 + ...CompletionItemBasedCompletionProposal.java | 102 +++-- .../LanguageServerCodeAssistProcessor.java | 81 ++-- .../codeassist/LatestCompletionResult.java | 127 ++++++ .../service/TextDocumentServiceClient.java | 6 +- .../orion/client/ContentAssistWidget.java | 377 ++++++++++++------ .../editor/orion/client/OrionEditorInit.java | 9 +- .../JsonExampleCodeAssistProcessor.java | 2 +- .../ide/editor/SimpleCompletionProposal.java | 5 +- .../shared/lsapi/CompletionListDTO.java | 43 ++ .../service/TextDocumentService.java | 13 +- 20 files changed, 609 insertions(+), 228 deletions(-) create mode 100644 plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LatestCompletionResult.java create mode 100644 wsagent/che-core-api-languageserver-shared/src/main/java/org/eclipse/che/api/languageserver/shared/lsapi/CompletionListDTO.java diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistProcessor.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistProcessor.java index 3e17f9e1d59..d7717b40707 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistProcessor.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistProcessor.java @@ -25,17 +25,22 @@ public interface CodeAssistProcessor { /** - * Returns a list of completion proposals based on the - * specified location within the document that corresponds - * to the current cursor position within the text view. + * Returns a list of completion proposals based on the specified location + * within the document that corresponds to the current cursor position + * within the text view. * * @param editor - * the editor whose document is used to compute the proposals + * the editor whose document is used to compute the proposals * @param offset - * an offset within the document for which completions should be computed - * @return an array of completion proposals or null if no proposals are possible + * an offset within the document for which completions should be + * computed + * @param triggered + * if triggered by the content assist key binding + * + * @return an array of completion proposals or null if no + * proposals are possible */ - void computeCompletionProposals(TextEditor editor, int offset, CodeAssistCallback callback); + void computeCompletionProposals(TextEditor editor, int offset, boolean triggered, CodeAssistCallback callback); /** * Returns the reason why this content assist processor diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistant.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistant.java index d291190d3cc..3677bd39c22 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistant.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistant.java @@ -50,8 +50,9 @@ public interface CodeAssistant { * appropriate content assist processor to invoke. * * @param offset a document offset + * @param triggered if triggered by the content assist key binding * @param callback the callback to use once completions are ready */ - void computeCompletionProposals(int offset, CodeAssistCallback callback); + void computeCompletionProposals(int offset, boolean triggered, CodeAssistCallback callback); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistantImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistantImpl.java index f023ceb9773..c1d6f6d85e9 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistantImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CodeAssistantImpl.java @@ -52,12 +52,12 @@ public CodeAssistantImpl(@Assisted final DocumentPartitioner partitioner, } @Override - public void computeCompletionProposals(final int offset, final CodeAssistCallback callback) { + public void computeCompletionProposals(final int offset, final boolean triggered, final CodeAssistCallback callback) { this.lastErrorMessage = "processing"; final CodeAssistProcessor processor = getProcessor(offset); if (processor != null) { - processor.computeCompletionProposals(textEditor, offset, callback); + processor.computeCompletionProposals(textEditor, offset, triggered, callback); this.lastErrorMessage = processor.getErrorMessage(); if (this.lastErrorMessage != null) { notificationManager.notify("", lastErrorMessage, FAIL, EMERGE_MODE); @@ -66,7 +66,7 @@ public void computeCompletionProposals(final int offset, final CodeAssistCallbac } else { final CodeAssistProcessor fallbackProcessor = getFallbackProcessor(); if (fallbackProcessor != null) { - fallbackProcessor.computeCompletionProposals(textEditor, offset, callback); + fallbackProcessor.computeCompletionProposals(textEditor, offset, triggered, callback); this.lastErrorMessage = fallbackProcessor.getErrorMessage(); if (this.lastErrorMessage != null) { this.textEditor.showMessage(this.lastErrorMessage); diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CompletionProposal.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CompletionProposal.java index 596fd6b64b0..bc23a8e9cb2 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CompletionProposal.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/CompletionProposal.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.ide.api.editor.codeassist; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Widget; import org.eclipse.che.ide.api.icon.Icon; @@ -28,10 +29,10 @@ public interface CompletionProposal { /** * Returns optional additional information about the proposal. The additional information will be presented to assist the user * in deciding if the selected proposal is the desired choice. - * - * @return the additional information or null + * + * @param callback a callback to return a widget with additional information */ - Widget getAdditionalProposalInfo(); + void getAdditionalProposalInfo(AsyncCallback callback); /** * Returns the string to be displayed in the list of completion proposals. diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/DefaultChainedCodeAssistProcessor.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/DefaultChainedCodeAssistProcessor.java index 1bd994e7d41..5a29b828e10 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/DefaultChainedCodeAssistProcessor.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/codeassist/DefaultChainedCodeAssistProcessor.java @@ -36,13 +36,13 @@ protected void setProcessors(final Set codeAssist } @Override - public void computeCompletionProposals(final TextEditor textEditor, final int offset, final CodeAssistCallback callback) { + public void computeCompletionProposals(final TextEditor textEditor, final int offset, final boolean triggered, final CodeAssistCallback callback) { if (!this.codeAssistProcessors.isEmpty()) { final List proposalList = new ArrayList<>(); final List expected = new ArrayList<>(); for (final CodeAssistProcessor processor : this.codeAssistProcessors) { expected.add(processor); - processor.computeCompletionProposals(textEditor, offset, new CodeAssistCallback() { + processor.computeCompletionProposals(textEditor, offset, triggered, new CodeAssistCallback() { @Override public void proposalComputed(final List processorProposals) { expected.remove(processor); diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorInit.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorInit.java index b8dadd49788..3388c7d5bd7 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorInit.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorInit.java @@ -191,7 +191,7 @@ private void configureCodeAssist(final DocumentHandle documentHandle) { final KeyBindingAction action = new KeyBindingAction() { @Override public boolean action() { - showCompletion(codeAssistant); + showCompletion(codeAssistant, true); return true; } }; @@ -202,7 +202,7 @@ public boolean action() { documentHandle.getDocEventBus().addHandler(CompletionRequestEvent.TYPE, new CompletionRequestHandler() { @Override public void onCompletionRequest(final CompletionRequestEvent event) { - showCompletion(codeAssistant); + showCompletion(codeAssistant, false); } }); } else { @@ -234,8 +234,9 @@ public void onCompletionRequest(final CompletionRequestEvent event) { * Show the available completions. * * @param codeAssistant the code assistant + * @param triggered if triggered by the content assist key binding */ - private void showCompletion(final CodeAssistant codeAssistant) { + private void showCompletion(final CodeAssistant codeAssistant, final boolean triggered) { final int cursor = textEditor.getCursorOffset(); if (cursor < 0) { return; @@ -248,7 +249,7 @@ public void computeCompletions(final CompletionReadyCallback callback) { // cursor must be computed here again so it's original value is not baked in // the SMI instance closure - important for completion update when typing final int cursor = textEditor.getCursorOffset(); - codeAssistant.computeCompletionProposals(cursor, new CodeAssistCallback() { + codeAssistant.computeCompletionProposals(cursor, triggered, new CodeAssistCallback() { @Override public void proposalComputed(final List proposals) { callback.onCompletionReady(proposals); diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/ActionCompletionProposal.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/ActionCompletionProposal.java index 2156804d257..a51fcad4037 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/ActionCompletionProposal.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/ActionCompletionProposal.java @@ -10,11 +10,12 @@ *******************************************************************************/ package org.eclipse.che.ide.ext.java.client.editor; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Widget; +import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; import org.eclipse.che.ide.api.icon.Icon; import org.eclipse.che.ide.ext.java.client.action.ProposalAction; -import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; import org.eclipse.che.ide.util.loging.Log; /** @@ -35,8 +36,8 @@ public ActionCompletionProposal(String display, String actionId, ProposalAction } @Override - public Widget getAdditionalProposalInfo() { - return null; + public void getAdditionalProposalInfo(AsyncCallback callback) { + callback.onSuccess(null); } @Override diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCodeAssistProcessor.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCodeAssistProcessor.java index ce38a15fbdd..ec8161ad25f 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCodeAssistProcessor.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCodeAssistProcessor.java @@ -155,7 +155,9 @@ public static Icon getIcon(final String image) { } @Override - public void computeCompletionProposals(final TextEditor textEditor, final int offset, + public void computeCompletionProposals(final TextEditor textEditor, + final int offset, + final boolean triggered, final CodeAssistCallback callback) { if (errorMessage != null) { return; diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCompletionProposal.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCompletionProposal.java index 05070d12484..a6f29d7a610 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCompletionProposal.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCompletionProposal.java @@ -79,14 +79,14 @@ public JavaCompletionProposal(final int id, /** {@inheritDoc} */ @Override - public Widget getAdditionalProposalInfo() { + public void getAdditionalProposalInfo(AsyncCallback callback) { Frame frame = new Frame(); frame.setSize("100%", "100%"); frame.getElement().getStyle().setBorderStyle(Style.BorderStyle.NONE); frame.getElement().setAttribute("sandbox", ""); // empty value, not null frame.getElement().getStyle().setProperty("resize", "both"); frame.setUrl(client.getProposalDocUrl(id, sessionId)); - return frame; + callback.onSuccess(frame); } /** {@inheritDoc} */ diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml index 887139507f8..d226d1c53b3 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml @@ -120,6 +120,15 @@ + + com.mycila + license-maven-plugin + + + **/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LatestCompletionResult.java + + + org.codehaus.mojo build-helper-maven-plugin diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java index 09a940d9d97..1f129379da2 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java @@ -14,16 +14,16 @@ import com.google.gwt.dom.client.Style; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; -import java.util.List; - import org.eclipse.che.api.languageserver.shared.lsapi.CompletionItemDTO; import org.eclipse.che.api.languageserver.shared.lsapi.RangeDTO; import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentIdentifierDTO; 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.ide.api.editor.codeassist.Completion; import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; @@ -31,30 +31,36 @@ import org.eclipse.che.ide.api.editor.text.LinearRange; import org.eclipse.che.ide.api.editor.text.TextPosition; import org.eclipse.che.ide.api.icon.Icon; -import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources; import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient; +import java.util.List; + /** * @author Anatolii Bazko + * @author Kaloyan Raev */ public class CompletionItemBasedCompletionProposal implements CompletionProposal { - private final CompletionItemDTO completionItem; + private CompletionItemDTO completionItem; private final TextDocumentServiceClient documentServiceClient; private final TextDocumentIdentifierDTO documentId; private final LanguageServerResources resources; private final Icon icon; private final ServerCapabilities serverCapabilities; private final List highlights; + private final int offset; + private boolean resolved; CompletionItemBasedCompletionProposal(CompletionItemDTO completionItem, TextDocumentServiceClient documentServiceClient, TextDocumentIdentifierDTO documentId, - LanguageServerResources resources, Icon icon, + LanguageServerResources resources, + Icon icon, ServerCapabilities serverCapabilities, - List highlights) { + List highlights, + int offset) { this.completionItem = completionItem; this.documentServiceClient = documentServiceClient; this.documentId = documentId; @@ -62,18 +68,43 @@ public class CompletionItemBasedCompletionProposal implements CompletionProposal this.icon = icon; this.serverCapabilities = serverCapabilities; this.highlights = highlights; + this.offset = offset; + this.resolved = false; } @Override - public Widget getAdditionalProposalInfo() { - if (completionItem.getDocumentation() != null && !completionItem.getDocumentation().isEmpty()) { - Label label = new Label(completionItem.getDocumentation()); - label.setWordWrap(true); - label.getElement().getStyle().setFontSize(13, Style.Unit.PX); - label.setSize("100%", "100%"); - return label; + public void getAdditionalProposalInfo(final AsyncCallback callback) { + if (completionItem.getDocumentation() == null && canResolve()) { + resolve().then(new Operation() { + @Override + public void apply(CompletionItemDTO item) throws OperationException { + completionItem = item; + resolved = true; + callback.onSuccess(createAdditionalInfoWidget()); + } + }).catchError(new Operation() { + @Override + public void apply(PromiseError e) throws OperationException { + callback.onFailure(e.getCause()); + } + }); + } else { + callback.onSuccess(createAdditionalInfoWidget()); + } + } + + private Widget createAdditionalInfoWidget() { + String documentation = completionItem.getDocumentation(); + if (documentation == null || documentation.trim().isEmpty()) { + documentation = "No documentation found."; } - return null; + + Label label = new Label(documentation); + label.setWordWrap(true); + label.getElement().getStyle().setFontSize(13, Style.Unit.PX); + label.getElement().getStyle().setMarginLeft(4, Style.Unit.PX); + label.setSize("100%", "100%"); + return label; } @Override @@ -129,50 +160,43 @@ public Icon getIcon() { @Override public void getCompletion(final CompletionCallback callback) { + callback.onCompletion(new CompletionImpl(completionItem, offset)); + } - if (serverCapabilities.getCompletionProvider() != null && - serverCapabilities.getCompletionProvider().getResolveProvider() != null && - serverCapabilities.getCompletionProvider().getResolveProvider()) { - completionItem.setTextDocumentIdentifier(documentId); - documentServiceClient.resolveCompletionItem(completionItem).then(new Operation() { - @Override - public void apply(CompletionItemDTO arg) throws OperationException { - callback.onCompletion(new CompletionImpl(arg)); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - Log.error(getClass(), arg); - //try to apply with default text - callback.onCompletion(new CompletionImpl(completionItem)); - } - }); - } else { - callback.onCompletion(new CompletionImpl(completionItem)); - } + private boolean canResolve() { + return !resolved && + serverCapabilities.getCompletionProvider() != null && + serverCapabilities.getCompletionProvider().getResolveProvider() != null && + serverCapabilities.getCompletionProvider().getResolveProvider(); + } + + private Promise resolve() { + completionItem.setTextDocumentIdentifier(documentId); + return documentServiceClient.resolveCompletionItem(completionItem); } private static class CompletionImpl implements Completion { private CompletionItemDTO completionItem; + private int offset; - public CompletionImpl(CompletionItemDTO completionItem) { + public CompletionImpl(CompletionItemDTO completionItem, int offset) { this.completionItem = completionItem; + this.offset = offset; } @Override public void apply(Document document) { - //TODO in general resolve completion item may not provide getTextEdit, need to add checks if (completionItem.getTextEdit() != null) { RangeDTO range = completionItem.getTextEdit().getRange(); int startOffset = document.getIndexFromPosition( new TextPosition(range.getStart().getLine(), range.getStart().getCharacter())); - int endOffset = document - .getIndexFromPosition(new TextPosition(range.getEnd().getLine(), range.getEnd().getCharacter())); + int endOffset = offset + document.getIndexFromPosition( + new TextPosition(range.getEnd().getLine(), range.getEnd().getCharacter())); document.replace(startOffset, endOffset - startOffset, completionItem.getTextEdit().getNewText()); } else { String insertText = completionItem.getInsertText() == null ? completionItem.getLabel() : completionItem.getInsertText(); - document.replace(document.getCursorOffset(), 0, insertText); + document.replace(document.getCursorOffset() - offset, offset, insertText); } } diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java index a818a163172..25634740a60 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java @@ -16,6 +16,7 @@ import com.google.inject.assistedinject.Assisted; import org.eclipse.che.api.languageserver.shared.lsapi.CompletionItemDTO; +import org.eclipse.che.api.languageserver.shared.lsapi.CompletionListDTO; import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentIdentifierDTO; import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentPositionParamsDTO; import org.eclipse.che.api.promises.client.Operation; @@ -48,6 +49,7 @@ public class LanguageServerCodeAssistProcessor implements CodeAssistProcessor { private final TextDocumentServiceClient documentServiceClient; private final FuzzyMatches fuzzyMatches; private String lastErrorMessage; + private final LatestCompletionResult latestCompletionResult; @Inject public LanguageServerCodeAssistProcessor(TextDocumentServiceClient documentServiceClient, @@ -62,40 +64,35 @@ public LanguageServerCodeAssistProcessor(TextDocumentServiceClient documentServi this.imageProvider = imageProvider; this.serverCapabilities = serverCapabilities; this.fuzzyMatches = fuzzyMatches; + this.latestCompletionResult = new LatestCompletionResult(); } @Override - public void computeCompletionProposals(TextEditor editor, int offset, final CodeAssistCallback callback) { + public void computeCompletionProposals(TextEditor editor, final int offset, final boolean triggered, final CodeAssistCallback callback) { + this.lastErrorMessage = null; + TextDocumentPositionParamsDTO documentPosition = dtoBuildHelper.createTDPP(editor.getDocument(), offset); final TextDocumentIdentifierDTO documentId = documentPosition.getTextDocument(); String currentLine = editor.getDocument().getLineContent(documentPosition.getPosition().getLine()); - final String currentIdentifier = getCurrentIdentifier(currentLine, documentPosition.getPosition().getCharacter()); - this.lastErrorMessage = null; - documentServiceClient.completion(documentPosition).then(new Operation>() { - - @Override - public void apply(List items) throws OperationException { - List proposals = newArrayList(); - for (CompletionItemDTO item : items) { - List highlights = filter(currentIdentifier, item); - if (highlights != null ) { - proposals.add(new CompletionItemBasedCompletionProposal(item, - documentServiceClient, - documentId, - resources, - imageProvider.getIcon(item.getKind()), - serverCapabilities, - highlights)); - } + final String currentWord = getCurrentWord(currentLine, documentPosition.getPosition().getCharacter()); + + if (!triggered && latestCompletionResult.isGoodFor(documentId, offset, currentWord)) { + // no need to send new completion request + computeProposals(currentWord, offset - latestCompletionResult.getOffset(), callback); + } else { + documentServiceClient.completion(documentPosition).then(new Operation() { + @Override + public void apply(CompletionListDTO list) throws OperationException { + latestCompletionResult.update(documentId, offset, currentWord, list); + computeProposals(currentWord, 0, callback); } - callback.proposalComputed(proposals); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - lastErrorMessage = error.getMessage(); - } - }); + }).catchError(new Operation() { + @Override + public void apply(PromiseError error) throws OperationException { + lastErrorMessage = error.getMessage(); + } + }); + } } @Override @@ -103,15 +100,15 @@ public String getErrorMessage() { return lastErrorMessage; } - private String getCurrentIdentifier(String text, int offset) { + private String getCurrentWord(String text, int offset) { int i = offset - 1; - while (i >= 0 && isIdentifierChar(text.charAt(i))) { + while (i >= 0 && isWordChar(text.charAt(i))) { i--; } return text.substring(i + 1, offset); } - - private boolean isIdentifierChar(char c) { + + private boolean isWordChar(char c) { return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || @@ -120,11 +117,11 @@ private boolean isIdentifierChar(char c) { c == '_' || c == '-'; } - + private List filter(String word, CompletionItemDTO item) { return filter(word, item.getLabel(), item.getFilterText()); } - + private List filter(String word, String label, String filterText) { if (filterText == null || filterText.isEmpty()) { filterText = label; @@ -141,4 +138,22 @@ private List filter(String word, String label, String filterText) { return null; } + private void computeProposals(String currentWord, int offset, CodeAssistCallback callback) { + List proposals = newArrayList(); + for (CompletionItemDTO item : latestCompletionResult.getCompletionList().getItems()) { + List highlights = filter(currentWord, item); + if (highlights != null) { + proposals.add(new CompletionItemBasedCompletionProposal(item, + documentServiceClient, + latestCompletionResult.getDocumentId(), + resources, + imageProvider.getIcon(item.getKind()), + serverCapabilities, + highlights, + offset)); + } + } + callback.proposalComputed(proposals); + } + } diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LatestCompletionResult.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LatestCompletionResult.java new file mode 100644 index 00000000000..fbf35f7814d --- /dev/null +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LatestCompletionResult.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.languageserver.ide.editor.codeassist; + +import org.eclipse.che.api.languageserver.shared.lsapi.CompletionListDTO; +import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentIdentifierDTO; + +/** + * Contains the latest completion result retrieved from the completion service. + * + * @author Kaloyan Raev + */ +public class LatestCompletionResult { + + private TextDocumentIdentifierDTO documentId; + private int offset; + private String word; + private CompletionListDTO completionList; + + /** + * Returns the identifier of document used to compute the latest completion + * result. + * + * @return the document identifier + */ + public TextDocumentIdentifierDTO getDocumentId() { + return this.documentId; + } + + /** + * Returns the offset position in document used to compute the latest + * completion result. + * + * @return the offset + */ + public int getOffset() { + return this.offset; + } + + /** + * Returns the word at the cursor at the time of computing the latest + * completion result. + * + * @return the word + */ + public String getWord() { + return this.word; + } + + /** + * Returns the latest completion list DTO object. + * + * @return the completion list + */ + public CompletionListDTO getCompletionList() { + return this.completionList; + } + + /** + * Checks if the completion result is still good for the given document + * position. + * + *

+ * The following checks are executed: + *

    + *
  1. A completion result has been retrieved at least once.
  2. + *
  3. The latest completion result is "complete", i.e. the + * isIncomplete property is false. + *
  4. The given document id is the same as in the latest completion + * result.
  5. + *
  6. The given word starts with the one in the latest completion + * result.
  7. + *
  8. The difference between the given offset and the one in the latest + * completion result matches the respective difference between the + * words.
  9. + *
+ * Only if all checks are satisfied then the latest completion result can be + * reused for the given document position. + *

+ * + * @param documentId + * a text document identifier + * @param offset + * an offset position in the document + * @param word + * the word at the current position in the document + * + * @return true if the completion result can still be used for + * the given document position, false otherwise. + */ + public boolean isGoodFor(TextDocumentIdentifierDTO documentId, int offset, String word) { + return completionList != null && + !completionList.isIncomplete() && + this.documentId.getUri().equals(documentId.getUri()) && + word.startsWith(this.word) && + offset - this.offset == word.length() - this.word.length(); + } + + /** + * Updates the latest completion result. + * + * @param documentId + * a text document identifier + * @param offset + * an offset position in the document + * @param word + * the word at the current position in the document + * @param completionList + * a completion list + */ + public void update(TextDocumentIdentifierDTO documentId, int offset, String word, + CompletionListDTO completionList) { + this.documentId = documentId; + this.offset = offset; + this.word = word; + this.completionList = completionList; + } + +} diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java index 53dde2597aa..472063a01c0 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java @@ -16,6 +16,7 @@ import com.google.inject.Singleton; import org.eclipse.che.api.languageserver.shared.lsapi.CompletionItemDTO; +import org.eclipse.che.api.languageserver.shared.lsapi.CompletionListDTO; import org.eclipse.che.api.languageserver.shared.lsapi.DidChangeTextDocumentParamsDTO; import org.eclipse.che.api.languageserver.shared.lsapi.DidCloseTextDocumentParamsDTO; import org.eclipse.che.api.languageserver.shared.lsapi.DidOpenTextDocumentParamsDTO; @@ -95,10 +96,9 @@ public void apply(MessageBus arg) throws OperationException { * @param position * @return */ - public Promise> completion(TextDocumentPositionParamsDTO position) { + public Promise completion(TextDocumentPositionParamsDTO position) { String requestUrl = appContext.getDevMachine().getWsAgentBaseUrl() + "/languageserver/textDocument/completion"; - Unmarshallable> unmarshaller = unmarshallerFactory - .newListUnmarshaller(CompletionItemDTO.class); + Unmarshallable unmarshaller = unmarshallerFactory.newUnmarshaller(CompletionListDTO.class); return asyncRequestFactory.createPostRequest(requestUrl, null).header(ACCEPT, APPLICATION_JSON) .header(CONTENT_TYPE, APPLICATION_JSON).data(((JsonSerializable)position).toJson()).send(unmarshaller); } diff --git a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java index ed0e4166524..647f56edf67 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java +++ b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java @@ -18,6 +18,7 @@ import elemental.events.EventTarget; import elemental.events.KeyboardEvent; import elemental.events.MouseEvent; +import elemental.html.HTMLCollection; import elemental.html.SpanElement; import elemental.html.Window; @@ -25,24 +26,25 @@ import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.AssistedInject; +import org.eclipse.che.ide.api.editor.codeassist.Completion; +import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; +import org.eclipse.che.ide.api.editor.codeassist.CompletionProposalExtension; +import org.eclipse.che.ide.api.editor.events.CompletionRequestEvent; +import org.eclipse.che.ide.api.editor.text.LinearRange; import org.eclipse.che.ide.api.editor.texteditor.HandlesUndoRedo; import org.eclipse.che.ide.api.editor.texteditor.UndoableEditor; import org.eclipse.che.ide.editor.orion.client.jso.OrionKeyModeOverlay; import org.eclipse.che.ide.editor.orion.client.jso.OrionModelChangedEventOverlay; import org.eclipse.che.ide.editor.orion.client.jso.OrionPixelPositionOverlay; import org.eclipse.che.ide.editor.orion.client.jso.OrionTextViewOverlay; -import org.eclipse.che.ide.api.editor.codeassist.Completion; -import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; -import org.eclipse.che.ide.api.editor.codeassist.CompletionProposalExtension; -import org.eclipse.che.ide.api.editor.events.CompletionRequestEvent; import org.eclipse.che.ide.ui.popup.PopupResources; -import org.eclipse.che.ide.api.editor.text.LinearRange; import org.eclipse.che.ide.util.dom.Elements; import org.eclipse.che.ide.util.loging.Log; @@ -53,6 +55,7 @@ /** * @author Evgen Vidolob * @author Vitaliy Guliy + * @author Kaloyan Raev */ public class ContentAssistWidget implements EventListener { /** @@ -60,6 +63,7 @@ public class ContentAssistWidget implements EventListener { */ private static final String CUSTOM_EVT_TYPE_VALIDATE = "itemvalidate"; private static final String DOCUMENTATION = "documentation"; + private static final int DOM_ITEMS_SIZE = 50; private final PopupResources popupResources; @@ -77,6 +81,7 @@ public class ContentAssistWidget implements EventListener { private final EventListener popupListener; private boolean visible = false; + private boolean focused = false; private boolean insert = true; /** @@ -87,6 +92,8 @@ public class ContentAssistWidget implements EventListener { private OrionTextViewOverlay.EventHandler handler; + private List proposals; + @AssistedInject public ContentAssistWidget(final PopupResources popupResources, @Assisted final OrionEditorWidget textEditor, @@ -149,8 +156,8 @@ public void run() { } }; - public void validateItem(boolean replace) { - this.insert = replace; + public void validateItem(boolean insert) { + this.insert = insert; selectedElement.dispatchEvent(createValidateEvent(CUSTOM_EVT_TYPE_VALIDATE)); } @@ -163,12 +170,14 @@ private native CustomEvent createValidateEvent(String eventType) /*-{ }-*/; /** - * Appends new proposal item to the popup + * Creates a new proposal item. * * @param proposal */ - private void addProposalPopupItem(final CompletionProposal proposal) { + private Element createProposalPopupItem(int index) { + final CompletionProposal proposal = proposals.get(index); final Element element = Elements.createLiElement(popupResources.popupStyle().item()); + element.setId(Integer.toString(index)); final Element icon = Elements.createDivElement(popupResources.popupStyle().icon()); if (proposal.getIcon() != null && proposal.getIcon().getSVGImage() != null) { @@ -184,26 +193,10 @@ private void addProposalPopupItem(final CompletionProposal proposal) { element.setTabIndex(1); - // add item to the popup - listElement.appendChild(element); - final EventListener validateListener = new EventListener() { @Override public void handleEvent(final Event evt) { - CompletionProposal.CompletionCallback callback = new CompletionProposal.CompletionCallback() { - @Override - public void onCompletion(final Completion completion) { - applyCompletion(completion); - } - }; - - if (proposal instanceof CompletionProposalExtension) { - ((CompletionProposalExtension)proposal).getCompletion(insert, callback); - } else { - proposal.getCompletion(callback); - } - - hide(); + applyProposal(proposal); } }; @@ -212,31 +205,45 @@ public void onCompletion(final Completion completion) { element.addEventListener(Event.CLICK, new EventListener() { @Override public void handleEvent(Event event) { - selectElement(element); + select(element); } }, false); + element.addEventListener(Event.FOCUS, this, false); element.addEventListener(DOCUMENTATION, new EventListener() { @Override public void handleEvent(Event event) { - Widget info = proposal.getAdditionalProposalInfo(); - - if (info != null) { - docPopup.clear(); - docPopup.add(info); - - if (docPopup.isAttached()) { - return; + proposal.getAdditionalProposalInfo(new AsyncCallback() { + @Override + public void onSuccess(Widget info) { + if (info != null) { + docPopup.clear(); + docPopup.add(info); + + if (docPopup.isAttached()) { + return; + } + + docPopup.getElement().getStyle() + .setLeft(popupElement.getOffsetLeft() + popupElement.getOffsetWidth() + 3, Style.Unit.PX); + docPopup.getElement().getStyle().setTop(popupElement.getOffsetTop(), Style.Unit.PX); + RootPanel.get().add(docPopup); + docPopup.getElement().getStyle().setOpacity(1); + } else { + docPopup.getElement().getStyle().setOpacity(0); + } } - - docPopup.getElement().getStyle() - .setLeft(popupElement.getOffsetLeft() + popupElement.getOffsetWidth() + 3, Style.Unit.PX); - docPopup.getElement().getStyle().setTop(popupElement.getOffsetTop(), Style.Unit.PX); - RootPanel.get().add(docPopup); - docPopup.getElement().getStyle().setOpacity(1); - } + + @Override + public void onFailure(Throwable e) { + Log.error(getClass(), e); + docPopup.getElement().getStyle().setOpacity(0); + } + }); } }, false); + + return element; } private void addPopupEventListeners() { @@ -280,7 +287,7 @@ public boolean onAction() { textEditor.getTextView().setAction("cheContentAssistNextPage", new Action() { @Override public boolean onAction() { - selectNext(listElement.getParentElement().getOffsetHeight() / listElement.getFirstElementChild().getOffsetHeight() - 1); + selectNextPage(); return true; } }); @@ -288,7 +295,7 @@ public boolean onAction() { textEditor.getTextView().setAction("cheContentAssistPreviousPage", new Action() { @Override public boolean onAction() { - selectPrevious(listElement.getParentElement().getOffsetHeight() / listElement.getFirstElementChild().getOffsetHeight() - 1); + selectPreviousPage(); return true; } }); @@ -296,7 +303,7 @@ public boolean onAction() { textEditor.getTextView().setAction("cheContentAssistEnd", new Action() { @Override public boolean onAction() { - selectElement(listElement.getLastElementChild()); + selectLast(); return true; } }); @@ -304,7 +311,7 @@ public boolean onAction() { textEditor.getTextView().setAction("cheContentAssistHome", new Action() { @Override public boolean onAction() { - selectElement(listElement.getFirstElementChild()); + selectFirst(); return true; } }); @@ -319,6 +326,7 @@ public boolean onAction() { textEditor.getTextView().addEventListener("ModelChanging", handler); listElement.addEventListener(Event.KEYDOWN, this, false); + popupBodyElement.addEventListener(Event.SCROLL, this, false); } private void removePopupEventListeners() { @@ -329,73 +337,85 @@ private void removePopupEventListeners() { // remove the keyboard listener listElement.removeEventListener(Event.KEYDOWN, this, false); + // remove the scroll listener + popupBodyElement.removeEventListener(Event.SCROLL, this, false); + // remove the mouse listener Elements.getDocument().removeEventListener(Event.MOUSEDOWN, this.popupListener); } + private void selectFirst() { + scrollTo(0); + updateIfNecessary(); + select(getFirstItemInDOM()); + } + + private void selectLast() { + scrollTo(getTotalItems() - 1); + updateIfNecessary(); + select(getLastItemInDOM()); + } + + private void select(int index) { + select(getItem(index)); + } + private void selectPrevious() { Element previousElement = selectedElement.getPreviousElementSibling(); - if (previousElement != null) { - selectElement(previousElement); + if (previousElement != null && previousElement == getExtraTopRow() && getExtraTopRow().isHidden()) { + selectLast(); } else { - selectElement(listElement.getLastElementChild()); + selectOffset(-1); } } - private void selectPrevious(int offset) { - Element element = selectedElement; - - for (int i = 0; i < offset; i++) { - Element previousElement = element.getPreviousElementSibling(); - if (previousElement == null) { - break; - } - element = previousElement; - } - - selectElement(element); + private void selectPreviousPage() { + int offset = getItemsPerPage() - 1; + selectOffset(-offset); } private void selectNext() { Element nextElement = selectedElement.getNextElementSibling(); - if (nextElement != null) { - selectElement(nextElement); + if (nextElement != null && nextElement == getExtraBottomRow() && getExtraBottomRow().isHidden()) { + selectFirst(); } else { - selectElement(listElement.getFirstElementChild()); + selectOffset(1); } } - private void selectNext(int offset) { - Element element = selectedElement; + private void selectNextPage() { + int offset = getItemsPerPage() - 1; + selectOffset(offset); + } - for (int i = 0; i < offset; i++) { - Element nextElement = element.getNextElementSibling(); - if (nextElement == null) { - break; - } - element = nextElement; + private void selectOffset(int offset) { + int index = getItemId(selectedElement) + offset; + index = Math.max(index, 0); + index = Math.min(index, getTotalItems() - 1); + + if (!isItemInDOM(index)) { + scrollTo(index); + update(); } - selectElement(element); + select(index); } - private void selectElement(Element element) { - if (selectedElement != null) { - selectedElement.removeAttribute("selected"); + private void select(Element element) { + if (element == selectedElement) { + return; } - if (docPopup.isAttached()) { - if (element != selectedElement) { - element.dispatchEvent(createValidateEvent(DOCUMENTATION)); - } - } else { - showDocTimer.cancel(); - showDocTimer.schedule(1500); + if (selectedElement != null) { + selectedElement.removeAttribute("selected"); } - selectedElement = element; selectedElement.setAttribute("selected", "true"); + docPopup.clear(); + showDocTimer.cancel(); + showDocTimer.schedule(docPopup.isAttached() ? 100 : 1500); + if (selectedElement.getOffsetTop() < this.popupBodyElement.getScrollTop()) { selectedElement.scrollIntoView(true); } else if ((selectedElement.getOffsetTop() + selectedElement.getOffsetHeight()) > @@ -420,6 +440,8 @@ public void run() { * proposals to display */ public void show(final List proposals) { + this.proposals = proposals; + OrionTextViewOverlay textView = textEditor.getTextView(); OrionPixelPositionOverlay caretLocation = textView.getLocationAtOffset(textView.getCaretOffset()); caretLocation.setY(caretLocation.getY() + textView.getLineHeight()); @@ -429,46 +451,37 @@ public void show(final List proposals) { listElement.setInnerHTML(""); /* Display an empty popup when it is nothing to show. */ - if (proposals == null || proposals.isEmpty()) { + if (getTotalItems() == 0) { final Element emptyElement = Elements.createLiElement(popupResources.popupStyle().item()); emptyElement.setTextContent("No proposals"); listElement.appendChild(emptyElement); return; } - if (proposals.size() == 1) { - CompletionProposal.CompletionCallback callback = new CompletionProposal.CompletionCallback() { - @Override - public void onCompletion(Completion completion) { - applyCompletion(completion); - } - }; - - CompletionProposal proposal = proposals.get(0); - proposal.getCompletion(callback); - + /* Automatically apply the completion proposal if it only one. */ + if (getTotalItems() == 1) { + applyProposal(proposals.get(0)); return; } - /* Add new popup items. */ - for (CompletionProposal proposal : proposals) { - addProposalPopupItem(proposal); - } - /* Reset popup dimensions and show. */ popupElement.getStyle().setLeft(caretLocation.getX(), PX); popupElement.getStyle().setTop(caretLocation.getY(), PX); popupElement.getStyle().setWidth("400px"); popupElement.getStyle().setHeight("200px"); - popupElement.getStyle().setOpacity(0); + popupElement.getStyle().setOpacity(1); Elements.getDocument().getBody().appendChild(this.popupElement); - Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { - @Override - public void execute() { - popupElement.getStyle().setOpacity(1); - } - }); + /* Add the top extra row. */ + setExtraRowHeight(appendExtraRow(), 0); + + /* Add the popup items. */ + for (int i = 0; i < Math.min(DOM_ITEMS_SIZE, getTotalItems()); i++) { + listElement.appendChild(createProposalPopupItem(i)); + } + + /* Add the bottom extra row. */ + setExtraRowHeight(appendExtraRow(), Math.max(0, getTotalItems() - DOM_ITEMS_SIZE)); /* Correct popup position (wants to be refactored) */ final Window window = Elements.getWindow(); @@ -515,6 +528,7 @@ public void execute() { /* Indicates the codeassist is visible. */ visible = true; + focused = false; if (docPopup.isAttached()) { docPopup.getElement().getStyle().setOpacity(0); @@ -528,13 +542,15 @@ public void run() { } /* Select first row. */ - selectElement(listElement.getFirstElementChild()); + selectFirst(); } /** * Hides the popup and displaying javadoc. */ public void hide() { + textEditor.setFocus(); + if (docPopup.isAttached()) { docPopup.getElement().getStyle().setOpacity(0); new Timer() { @@ -565,7 +581,7 @@ public void run() { @Override public void handleEvent(Event evt) { - if (evt instanceof KeyboardEvent) { + if (Event.KEYDOWN.equalsIgnoreCase(evt.getType())) { final KeyboardEvent keyEvent = (KeyboardEvent)evt; switch (keyEvent.getKeyCode()) { case KeyCodes.KEY_ESCAPE: @@ -588,21 +604,21 @@ public void execute() { break; case KeyCodes.KEY_PAGEUP: - selectPrevious(listElement.getParentElement().getOffsetHeight() / listElement.getFirstElementChild().getOffsetHeight() - 1); + selectPreviousPage(); evt.preventDefault(); break; case KeyCodes.KEY_PAGEDOWN: - selectNext(listElement.getParentElement().getOffsetHeight() / listElement.getFirstElementChild().getOffsetHeight() - 1); + selectNextPage(); evt.preventDefault(); break; case KeyCodes.KEY_HOME: - selectElement(listElement.getFirstElementChild()); + selectFirst(); break; case KeyCodes.KEY_END: - selectElement(listElement.getLastElementChild()); + selectLast(); break; case KeyCodes.KEY_ENTER: @@ -617,6 +633,56 @@ public void execute() { validateItem(false); break; } + } else if (Event.SCROLL.equalsIgnoreCase(evt.getType())) { + updateIfNecessary(); + } else if (Event.FOCUS.equalsIgnoreCase(evt.getType())) { + focused = true; + } + } + + private void updateIfNecessary() { + int scrollTop = popupBodyElement.getScrollTop(); + int extraTopHeight = getExtraTopRow().getClientHeight(); + + if (scrollTop < extraTopHeight) { + // the scroll bar is above the buffered area + update(); + } else if (scrollTop + popupBodyElement.getClientHeight() > extraTopHeight + getItemHeight() * DOM_ITEMS_SIZE) { + // the scroll bar is below the buffered area + update(); + } + } + + private void update() { + int topVisibleItem = popupBodyElement.getScrollTop() / getItemHeight(); + int topDOMItem = Math.max(0, topVisibleItem - (DOM_ITEMS_SIZE - getItemsPerPage()) / 2); + int bottomDOMItem = Math.min(getTotalItems() - 1, topDOMItem + DOM_ITEMS_SIZE - 1); + if (bottomDOMItem == getTotalItems() - 1) { + topDOMItem = Math.max(0, bottomDOMItem - DOM_ITEMS_SIZE + 1); + } + + // resize the extra top row + setExtraRowHeight(getExtraTopRow(), topDOMItem); + + // replace the DOM items with new content based on the scroll position + HTMLCollection nodes = listElement.getChildren(); + for (int i = 0; i <= (bottomDOMItem - topDOMItem); i++) { + Element newNode = createProposalPopupItem(topDOMItem + i); + listElement.replaceChild(newNode, nodes.item(i + 1)); + + // check if the item is the selected + if (newNode.getId().equals(selectedElement.getId())) { + selectedElement = newNode; + selectedElement.setAttribute("selected", "true"); + } + } + + // resize the extra bottom row + setExtraRowHeight(getExtraBottomRow(), getTotalItems() - (bottomDOMItem + 1)); + + // ensure the keyboard focus is in the visible area + if (focused) { + getItem(topDOMItem + (bottomDOMItem - topDOMItem) / 2).focus(); } } @@ -635,6 +701,23 @@ public void showCompletionInfo() { } } + private void applyProposal(CompletionProposal proposal) { + CompletionProposal.CompletionCallback callback = new CompletionProposal.CompletionCallback() { + @Override + public void onCompletion(Completion completion) { + applyCompletion(completion); + } + }; + + if (proposal instanceof CompletionProposalExtension) { + ((CompletionProposalExtension) proposal).getCompletion(insert, callback); + } else { + proposal.getCompletion(callback); + } + + hide(); + } + private void applyCompletion(Completion completion) { textEditor.setFocus(); UndoableEditor undoableEditor = textEditor; @@ -658,4 +741,70 @@ private void applyCompletion(Completion completion) { } } + private Element getExtraTopRow() { + return (listElement == null) ? null : listElement.getFirstElementChild(); + } + + private Element getExtraBottomRow() { + return (listElement == null) ? null : listElement.getLastElementChild(); + } + + private Element getFirstItemInDOM() { + Element extraTopRow = getExtraTopRow(); + return (extraTopRow == null) ? null : extraTopRow.getNextElementSibling(); + } + + private Element getLastItemInDOM() { + Element extraBottomRow = getExtraBottomRow(); + return (extraBottomRow == null) ? null : extraBottomRow.getPreviousElementSibling(); + } + + private int getItemId(Element item) { + return Integer.parseInt(item.getId()); + } + + private Element getItem(int index) { + return (Element) listElement.getChildren().namedItem(Integer.toString(index)); + } + + private int getItemHeight() { + Element item = getFirstItemInDOM(); + return (item == null) ? 0 : item.getClientHeight(); + } + + private Element appendExtraRow() { + Element extraRow = Elements.createLiElement(); + listElement.appendChild(extraRow); + return extraRow; + } + + private void setExtraRowHeight(Element extraRow, int items) { + int height = items * getItemHeight(); + extraRow.getStyle().setHeight(height + "px"); + extraRow.setHidden(height <= 0); + } + + private int getItemsPerPage() { + return (int) Math.ceil((double) popupBodyElement.getClientHeight() / getItemHeight()); + } + + private int getTotalItems() { + return (proposals == null) ? 0 : proposals.size(); + } + + private boolean isItemInDOM(int index) { + return index >= getItemId(getFirstItemInDOM()) && index <= getItemId(getLastItemInDOM()); + } + + private void scrollTo(int index) { + int currentScrollTop = popupBodyElement.getScrollTop(); + int newScrollTop = index * getItemHeight(); + if (currentScrollTop < newScrollTop) { + // the scrolling direction is from top to bottom, so show the item + // at the bottom of the widget + newScrollTop -= popupBodyElement.getClientHeight(); + } + popupBodyElement.setScrollTop(newScrollTop); + } + } diff --git a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorInit.java b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorInit.java index 212e4a40446..c21b0472326 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorInit.java +++ b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorInit.java @@ -193,7 +193,7 @@ private void configureCodeAssist(final DocumentHandle documentHandle) { final KeyBindingAction action = new KeyBindingAction() { @Override public boolean action() { - showCompletion(codeAssistant); + showCompletion(codeAssistant, true); return true; } }; @@ -204,7 +204,7 @@ public boolean action() { documentHandle.getDocEventBus().addHandler(CompletionRequestEvent.TYPE, new CompletionRequestHandler() { @Override public void onCompletionRequest(final CompletionRequestEvent event) { - showCompletion(codeAssistant); + showCompletion(codeAssistant, false); } }); } else { @@ -236,8 +236,9 @@ public void onCompletionRequest(final CompletionRequestEvent event) { * Show the available completions. * * @param codeAssistant the code assistant + * @param triggered if triggered by the content assist key binding */ - private void showCompletion(final CodeAssistant codeAssistant) { + private void showCompletion(final CodeAssistant codeAssistant, final boolean triggered) { final int cursor = textEditor.getCursorOffset(); if (cursor < 0) { return; @@ -250,7 +251,7 @@ public void computeCompletions(final CompletionReadyCallback callback) { // cursor must be computed here again so it's original value is not baked in // the SMI instance closure - important for completion update when typing final int cursor = textEditor.getCursorOffset(); - codeAssistant.computeCompletionProposals(cursor, new CodeAssistCallback() { + codeAssistant.computeCompletionProposals(cursor, triggered, new CodeAssistCallback() { @Override public void proposalComputed(final List proposals) { callback.onCompletionReady(proposals); diff --git a/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/JsonExampleCodeAssistProcessor.java b/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/JsonExampleCodeAssistProcessor.java index 6e5950280ef..07ce93e3444 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/JsonExampleCodeAssistProcessor.java +++ b/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/JsonExampleCodeAssistProcessor.java @@ -47,7 +47,7 @@ public JsonExampleCodeAssistProcessor(final JsonExampleCodeAssistClient client) } @Override - public void computeCompletionProposals(final TextEditor editor, final int offset, final CodeAssistCallback callback) { + public void computeCompletionProposals(final TextEditor editor, final int offset, final boolean triggered, final CodeAssistCallback callback) { final List proposals = new ArrayList<>(); proposals.addAll(Arrays.asList( diff --git a/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/SimpleCompletionProposal.java b/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/SimpleCompletionProposal.java index f390515ed76..07e7616e976 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/SimpleCompletionProposal.java +++ b/samples/sample-plugin-json/che-sample-plugin-json-ide/src/main/java/org/eclipse/che/plugin/jsonexample/ide/editor/SimpleCompletionProposal.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.plugin.jsonexample.ide.editor; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Widget; import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; @@ -35,8 +36,8 @@ public SimpleCompletionProposal(String proposal) { } @Override - public Widget getAdditionalProposalInfo() { - return null; + public void getAdditionalProposalInfo(AsyncCallback callback) { + callback.onSuccess(null); } @Override diff --git a/wsagent/che-core-api-languageserver-shared/src/main/java/org/eclipse/che/api/languageserver/shared/lsapi/CompletionListDTO.java b/wsagent/che-core-api-languageserver-shared/src/main/java/org/eclipse/che/api/languageserver/shared/lsapi/CompletionListDTO.java new file mode 100644 index 00000000000..f8095276e48 --- /dev/null +++ b/wsagent/che-core-api-languageserver-shared/src/main/java/org/eclipse/che/api/languageserver/shared/lsapi/CompletionListDTO.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.languageserver.shared.lsapi; + +import io.typefox.lsapi.CompletionList; + +import org.eclipse.che.dto.shared.DTO; + +import java.util.List; + +/** + * Represents a collection of completion items to be presented in the editor. + * + * @author Kaloyan Raev + */ +@DTO +public interface CompletionListDTO extends CompletionList { + + /** + * This list it not complete. Further typing should result in recomputing + * this list. + */ + void setIncomplete(boolean incomplete); + + /** + * The completion items. Overridden to return the DTO type. + */ + List getItems(); + + /** + * The completion items. + */ + void setItems(List items); + +} diff --git a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/service/TextDocumentService.java b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/service/TextDocumentService.java index 0e514259369..98463f9db70 100644 --- a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/service/TextDocumentService.java +++ b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/service/TextDocumentService.java @@ -11,6 +11,7 @@ package org.eclipse.che.api.languageserver.service; import io.typefox.lsapi.CompletionItem; +import io.typefox.lsapi.CompletionList; import io.typefox.lsapi.Hover; import io.typefox.lsapi.Location; import io.typefox.lsapi.SignatureHelp; @@ -79,17 +80,17 @@ static String removePrefixUri(String uri) { @Path("completion") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public List completion(TextDocumentPositionParamsDTO textDocumentPositionParams) throws InterruptedException, - ExecutionException, - LanguageServerException { + public CompletionList completion(TextDocumentPositionParamsDTO textDocumentPositionParams) throws InterruptedException, + ExecutionException, + LanguageServerException { textDocumentPositionParams.getTextDocument().setUri(prefixURI(textDocumentPositionParams.getTextDocument().getUri())); textDocumentPositionParams.setUri(prefixURI(textDocumentPositionParams.getUri())); LanguageServer server = getServer(textDocumentPositionParams.getTextDocument().getUri()); if (server == null) { - return emptyList(); + return null; } return server.getTextDocumentService() - .completion(textDocumentPositionParams).get().getItems(); + .completion(textDocumentPositionParams).get(); } @POST @@ -161,7 +162,7 @@ public List definition(TextDocumentPositionParamsDTO params) public CompletionItem resolveCompletionItem(CompletionItemDTO unresolved) throws InterruptedException, ExecutionException, LanguageServerException { - LanguageServer server = getServer(unresolved.getTextDocumentIdentifier().getUri()); + LanguageServer server = getServer(prefixURI(unresolved.getTextDocumentIdentifier().getUri())); if (server != null) { return server.getTextDocumentService().resolveCompletionItem(unresolved).get(); } else { From 2339b0dd6eec1196bdc35fa468e4b067d15a9871 Mon Sep 17 00:00:00 2001 From: Roman Nikitenko Date: Tue, 8 Nov 2016 10:27:35 +0200 Subject: [PATCH 30/74] CHE-2937. Add ability to create batch of projects --- .../core/model/project/NewProjectConfig.java | 46 ++ .../api/core/model/project/ProjectConfig.java | 2 +- .../ide/api/project/MutableProjectConfig.java | 30 +- .../ide/api/project/NewProjectConfigImpl.java | 173 +++++ .../ide/api/project/ProjectServiceClient.java | 19 + .../api/project/ProjectServiceClientImpl.java | 14 +- .../project/type/ProjectTemplateRegistry.java | 2 +- .../ide/projecttype/wizard/ProjectWizard.java | 2 +- .../CategoriesPagePresenter.java | 35 +- .../presenter/ProjectWizardPresenter.java | 17 +- .../ide/resources/impl/ResourceManager.java | 101 ++- .../projecttype/wizard/ProjectWizardTest.java | 4 +- .../server/rest/ClasspathUpdaterService.java | 5 +- .../client/MavenLocalizationConstant.java | 6 + .../client/wizard/MavenPagePresenter.java | 21 +- .../MavenLocalizationConstant.properties | 3 + .../client/wizard/MavenPagePresenterTest.java | 15 +- .../che/api/project/shared/Constants.java | 25 +- .../project/shared/dto/SourceEstimation.java | 7 +- .../api/project/server/NewProjectConfig.java | 118 --- .../project/server/NewProjectConfigImpl.java | 178 +++++ .../api/project/server/ProjectManager.java | 353 ++++++--- .../api/project/server/ProjectRegistry.java | 21 +- .../api/project/server/ProjectService.java | 34 + .../che/api/project/server/ProjectTypes.java | 75 +- .../api/project/server/RegisteredProject.java | 47 +- .../server/WorkspaceProjectsSyncer.java | 15 +- .../project/server/type/ProjectTypeDef.java | 28 +- .../server/type/ProjectTypeResolution.java | 13 + .../server/ProjectManagerWriteTest.java | 709 ++++++++++++++---- .../project/server/ProjectServiceTest.java | 265 +++++-- .../api/project/server/WsAgentTestBase.java | 5 - .../server/batchNewProjectConfigs.json | 68 ++ .../shared/dto/ProjectTemplateDescriptor.java | 14 +- .../shared/dto/NewProjectConfigDto.java | 65 ++ 35 files changed, 1938 insertions(+), 597 deletions(-) create mode 100644 core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/NewProjectConfig.java create mode 100644 ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/NewProjectConfigImpl.java delete mode 100644 wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfig.java create mode 100644 wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfigImpl.java create mode 100644 wsagent/che-core-api-project/src/test/resources/org/eclipse/che/api/project/server/batchNewProjectConfigs.json create mode 100644 wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/NewProjectConfigDto.java diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/NewProjectConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/NewProjectConfig.java new file mode 100644 index 00000000000..b735b0c3d5a --- /dev/null +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/NewProjectConfig.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ + +package org.eclipse.che.api.core.model.project; + +import java.util.List; +import java.util.Map; + +/** + * Defines configuration for creating new project + * + * @author Roman Nikitenko + */ +public interface NewProjectConfig extends ProjectConfig { + /** Sets project name */ + void setName(String name); + + /** Sets project path */ + void setPath(String path); + + /** Sets project description */ + void setDescription(String description); + + /** Sets primary project type */ + void setType(String type); + + /** Sets mixin project types */ + void setMixins(List mixins); + + /** Sets project attributes */ + void setAttributes(Map> attributes); + + /** Sets options for generator to create project */ + void setOptions(Map options); + + /** Returns options for generator to create project */ + Map getOptions(); +} diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/ProjectConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/ProjectConfig.java index 7c311fffa5e..9b8f0bfe1e6 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/ProjectConfig.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/project/ProjectConfig.java @@ -33,4 +33,4 @@ public interface ProjectConfig { SourceStorage getSource(); -} \ No newline at end of file +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/MutableProjectConfig.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/MutableProjectConfig.java index 3419ea69ebe..979e3ce75cd 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/MutableProjectConfig.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/MutableProjectConfig.java @@ -12,11 +12,10 @@ import com.google.common.annotations.Beta; +import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.model.project.SourceStorage; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -37,6 +36,7 @@ public class MutableProjectConfig implements ProjectConfig { private Map> attributes; private MutableSourceStorage sourceStorage; private Map options; + private List projects; public MutableProjectConfig(ProjectConfig source) { name = source.getName(); @@ -90,7 +90,7 @@ public void setType(String type) { @Override public List getMixins() { if (mixins == null) { - mixins = new ArrayList<>(); + mixins = newArrayList(); } return mixins; @@ -128,7 +128,7 @@ public void setSource(SourceStorage sourceStorage) { public Map getOptions() { if (options == null) { - options = new HashMap<>(); + options = newHashMap(); } return options; } @@ -137,6 +137,28 @@ public void setOptions(Map options) { this.options = options; } + /** + * Returns the list of configurations to creating projects + * + * @return the list of {@link NewProjectConfig} to creating projects + */ + public List getProjects() { + if (projects == null) { + return newArrayList(); + } + return projects; + } + + /** + * Sets the list of configurations to creating projects + * + * @param projects + * the list of {@link NewProjectConfig} to creating projects + */ + public void setProjects(List projects) { + this.projects = projects; + } + public class MutableSourceStorage implements SourceStorage { private String type; private String location; diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/NewProjectConfigImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/NewProjectConfigImpl.java new file mode 100644 index 00000000000..8a383ef2029 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/NewProjectConfigImpl.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.api.project; + +import org.eclipse.che.api.core.model.project.NewProjectConfig; +import org.eclipse.che.api.core.model.project.SourceStorage; +import org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implementation of {@link NewProjectConfig} for creating project + * + * @author Roman Nikitenko + */ +public class NewProjectConfigImpl implements NewProjectConfig { + private String name; + private String path; + private String description; + private String type; + private SourceStorage sourceStorage; + private List mixins; + private Map> attributes; + private Map options; + + /** Constructor for creating project import configuration */ + public NewProjectConfigImpl(String name, + String path, + String description, + String type, + SourceStorage sourceStorage) { + this(name, path, description, type, sourceStorage, null, null, null); + } + + /** Constructor for creating project generator configuration */ + public NewProjectConfigImpl(String name, + String path, + String description, + String type, + Map> attributes, + Map options) { + this(name, path, description, type, null, null, attributes, options); + } + + /** Constructor for creating configuration from project template descriptor */ + public NewProjectConfigImpl(ProjectTemplateDescriptor descriptor) { + this(descriptor.getName(), + descriptor.getPath(), + descriptor.getDescription(), + descriptor.getProjectType(), + descriptor.getSource(), + descriptor.getMixins(), + descriptor.getAttributes(), + descriptor.getOptions()); + } + + /** Constructor for creating configuration from DTO object */ + public NewProjectConfigImpl(NewProjectConfigDto dto) { + this(dto.getName(), + dto.getPath(), + dto.getDescription(), + dto.getType(), + dto.getSource(), + dto.getMixins(), + dto.getAttributes(), + dto.getOptions()); + } + + public NewProjectConfigImpl(String name, + String path, + String description, + String type, + SourceStorage sourceStorage, + List mixins, + Map> attributes, + Map options) { + this.name = name; + this.path = path; + this.description = description; + this.type = type; + this.sourceStorage = sourceStorage; + this.mixins = mixins; + this.attributes = attributes != null ? attributes : new HashMap>(); + this.options = options != null ? options : new HashMap(); + } + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public String getPath() { + return path; + } + + @Override + public void setPath(String path) { + this.path = path; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public void setDescription(String description) { + this.description = description; + } + + @Override + public String getType() { + return type; + } + + @Override + public void setType(String type) { + this.type = type; + } + + @Override + public List getMixins() { + return mixins != null ? mixins : new ArrayList(); + } + + @Override + public void setMixins(List mixins) { + this.mixins = mixins; + } + + @Override + public Map> getAttributes() { + return attributes != null ? attributes : new HashMap>(); + } + + @Override + public void setAttributes(Map> attributes) { + this.attributes = attributes; + } + + @Override + public Map getOptions() { + return options != null ? options : new HashMap(); + } + + @Override + public void setOptions(Map options) { + this.options = options; + } + + @Override + public SourceStorage getSource() { + return sourceStorage; + } +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClient.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClient.java index 4580805df43..91c23e65781 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClient.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClient.java @@ -14,6 +14,7 @@ import org.eclipse.che.api.project.shared.dto.SourceEstimation; import org.eclipse.che.api.project.shared.dto.TreeElement; import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.ide.resource.Path; @@ -92,6 +93,24 @@ public interface ProjectServiceClient { */ Promise createProject(ProjectConfigDto configuration, Map options); + /** + * Create batch of projects according to their configurations. + *

+ * Notes: a project will be created by importing when project configuration contains {@link SourceStorageDto} + * object, otherwise this one will be created corresponding its {@link NewProjectConfigDto}: + *

  • - {@link NewProjectConfigDto} object contains only one mandatory {@link NewProjectConfigDto#setPath(String)} field. + * In this case Project will be created as project of "blank" type
  • + *
  • - a project will be created as project of "blank" type when declared primary project type is not registered,
  • + *
  • - a project will be created without mixin project type when declared mixin project type is not registered
  • + *
  • - for creating a project by generator {@link NewProjectConfigDto#getOptions()} should be specified.
  • + * + * @param configurations + * the list of configurations to creating projects + * @return {@link Promise} with the list of {@link ProjectConfigDto} + * @see ProjectConfigDto + */ + Promise> createBatchProjects(List configurations); + /** * Returns the item description by given {@code path}. * diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClientImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClientImpl.java index 3b52a42fd19..ead24c8972a 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClientImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/ProjectServiceClientImpl.java @@ -26,6 +26,7 @@ import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper; import org.eclipse.che.api.promises.client.callback.PromiseHelper; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.ide.MimeType; @@ -65,7 +66,8 @@ */ public class ProjectServiceClientImpl implements ProjectServiceClient { - private static final String PROJECT = "/project"; + private static final String PROJECT = "/project"; + private static final String BATCH_PROJECTS = "/batch"; private static final String ITEM = "/item"; private static final String TREE = "/tree"; @@ -213,6 +215,16 @@ public Promise createProject(ProjectConfigDto configuration, M .send(unmarshaller.newUnmarshaller(ProjectConfigDto.class)); } + @Override + public Promise> createBatchProjects(List configurations) { + final String url = getBaseUrl() + BATCH_PROJECTS; + final String loaderMessage = configurations.size() > 1 ? "Creating the batch of projects..." : "Creating project..."; + return reqFactory.createPostRequest(url, configurations) + .header(ACCEPT, MimeType.APPLICATION_JSON) + .loader(loaderFactory.newLoader(loaderMessage)) + .send(unmarshaller.newListUnmarshaller(ProjectConfigDto.class)); + } + /** {@inheritDoc} */ @Override public Promise createFile(Path path, String content) { diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/type/ProjectTemplateRegistry.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/type/ProjectTemplateRegistry.java index ed9343c935d..cb35ab357c6 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/type/ProjectTemplateRegistry.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/project/type/ProjectTemplateRegistry.java @@ -16,7 +16,7 @@ import java.util.List; /** - * Registry for {@link org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor}s. + * Registry for {@link ProjectTemplateDescriptor}s. * * @author Artem Zatsarynnyi */ diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java index 016118d9718..cac215c67ad 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java @@ -99,7 +99,7 @@ public void apply(Optional optContainer) throws OperationException { }); } else if (mode == IMPORT) { appContext.getWorkspaceRoot() - .importProject() + .newProject() .withBody(dataObject) .send() .thenPromise(new Function>() { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/categoriespage/CategoriesPagePresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/categoriespage/CategoriesPagePresenter.java index 3f7e54166d3..2b5f8519b5e 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/categoriespage/CategoriesPagePresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/categoriespage/CategoriesPagePresenter.java @@ -13,9 +13,13 @@ import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.inject.Inject; +import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.project.shared.dto.ProjectTypeDto; import org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.project.MutableProjectConfig; +import org.eclipse.che.ide.api.project.NewProjectConfigImpl; import org.eclipse.che.ide.api.project.type.ProjectTemplateRegistry; import org.eclipse.che.ide.api.project.type.ProjectTypeRegistry; import org.eclipse.che.ide.api.project.type.wizard.PreSelectedProjectTypeManager; @@ -23,12 +27,12 @@ import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistry; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.api.wizard.AbstractWizardPage; -import org.eclipse.che.ide.api.project.MutableProjectConfig; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.resources.selector.SelectPathPresenter; import org.eclipse.che.ide.resources.selector.SelectionPathHandler; import org.eclipse.che.ide.util.NameUtils; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -162,13 +166,20 @@ public void projectTemplateSelected(ProjectTemplateDescriptor templateDescriptor if (projectTemplateSelectionListener != null) { projectTemplateSelectionListener.onProjectTemplateSelected(templateDescriptor); } + + updateProjectConfigs(dataObject.getPath(), selectedProjectTemplate); updateDelegate.updateControls(); } @Override public void projectNameChanged(String name) { + final String newProjectPath = originParent.append(name).toString(); + if (selectedProjectTemplate != null) { + updateProjectConfigs(newProjectPath, selectedProjectTemplate); + } + dataObject.setName(name); - dataObject.setPath(originParent.append(name).toString()); + dataObject.setPath(newProjectPath); updateDelegate.updateControls(); if (NameUtils.checkProjectName(name)) { @@ -211,6 +222,26 @@ public void setProjectTemplateSelectionListener(ProjectTemplateSelectionListener projectTemplateSelectionListener = listener; } + private void updateProjectConfigs(String newProjectPath, ProjectTemplateDescriptor projectTemplate) { + final List configDtoList = projectTemplate.getProjects(); + if (newProjectPath.equals("/")) { + return; + } + + final String templatePath = projectTemplate.getPath(); + final List updatedConfigs = new ArrayList<>(configDtoList.size()); + for (NewProjectConfigDto configDto : configDtoList) { + final NewProjectConfig newConfig = new NewProjectConfigImpl(configDto); + final String projectPath = configDto.getPath(); + if (projectPath.startsWith(templatePath)) { + final String path = projectPath.replaceFirst(templatePath, newProjectPath); + newConfig.setPath(path); + } + updatedConfigs.add(newConfig); + } + dataObject.setProjects(updatedConfigs); + } + private void loadProjectTypesAndTemplates() { List projectTypes = projectTypeRegistry.getProjectTypes(); Map> typesByCategory = new HashMap<>(); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/presenter/ProjectWizardPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/presenter/ProjectWizardPresenter.java index 4f2ee61ce42..1d019156d03 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/presenter/ProjectWizardPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/presenter/ProjectWizardPresenter.java @@ -14,12 +14,14 @@ import com.google.inject.Provider; import com.google.inject.Singleton; +import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.project.shared.dto.AttributeDto; import org.eclipse.che.api.project.shared.dto.ProjectTypeDto; import org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.project.MutableProjectConfig; +import org.eclipse.che.ide.api.project.NewProjectConfigImpl; import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardMode; import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistrar; import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistry; @@ -181,7 +183,15 @@ public void onProjectTypeSelected(ProjectTypeDto projectType) { if (wizardMode == UPDATE) { newProject.setAttributes(prevData.getAttributes()); } else { - List attributes = projectType.getAttributes(); + final MutableProjectConfig.MutableSourceStorage sourceStorage = prevData.getSource(); + if (sourceStorage != null) { // some values should be cleared when user switch between categories + sourceStorage.setLocation(""); + sourceStorage.setType(""); + sourceStorage.getParameters().clear(); + } + prevData.getProjects().clear(); + + final List attributes = projectType.getAttributes(); Map> prevDataAttributes = prevData.getAttributes(); Map> newAttributes = new HashMap<>(); for (AttributeDto attribute : attributes) { @@ -203,8 +213,9 @@ public void onProjectTemplateSelected(ProjectTemplateDescriptor projectTemplate) wizard.navigateToFirst(); // set dataObject's values from projectTemplate - dataObject.setType(projectTemplate.getProjectType()); - dataObject.setSource(projectTemplate.getSource()); + final NewProjectConfig newProjectConfig = new NewProjectConfigImpl(projectTemplate); + dataObject.setType(newProjectConfig.getType()); + dataObject.setSource(newProjectConfig.getSource()); } /** Creates or returns project wizard for the specified projectType with the given dataObject. */ diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/ResourceManager.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/ResourceManager.java index 250913b4059..db3e404f1da 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/ResourceManager.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/impl/ResourceManager.java @@ -16,6 +16,7 @@ import com.google.inject.assistedinject.Assisted; import com.google.web.bindery.event.shared.EventBus; +import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.model.project.SourceStorage; import org.eclipse.che.api.core.rest.shared.dto.Link; @@ -27,6 +28,7 @@ import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseProvider; import org.eclipse.che.api.promises.client.js.Promises; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; @@ -56,6 +58,7 @@ import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.util.Arrays; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -263,22 +266,22 @@ public Container getWorkspaceRoot() { * @since 4.4.0 */ protected Promise update(final Path path, final ProjectRequest request) { - + final ProjectConfig projectConfig = request.getBody(); + final SourceStorage source = projectConfig.getSource(); final SourceStorageDto sourceDto = dtoFactory.createDto(SourceStorageDto.class); - - if (request.getBody().getSource() != null) { - sourceDto.setLocation(request.getBody().getSource().getLocation()); - sourceDto.setType(request.getBody().getSource().getType()); - sourceDto.setParameters(request.getBody().getSource().getParameters()); + if (source != null) { + sourceDto.setLocation(source.getLocation()); + sourceDto.setType(source.getType()); + sourceDto.setParameters(source.getParameters()); } final ProjectConfigDto dto = dtoFactory.createDto(ProjectConfigDto.class) - .withName(request.getBody().getName()) + .withName(projectConfig.getName()) .withPath(path.toString()) - .withDescription(request.getBody().getDescription()) - .withType(request.getBody().getType()) - .withMixins(request.getBody().getMixins()) - .withAttributes(request.getBody().getAttributes()) + .withDescription(projectConfig.getDescription()) + .withType(projectConfig.getType()) + .withMixins(projectConfig.getMixins()) + .withAttributes(projectConfig.getAttributes()) .withSource(sourceDto); return ps.updateProject(dto).thenPromise(new Function>() { @@ -410,21 +413,9 @@ Promise createProject(final Project.ProjectRequest createRequest) { checkArgument(typeRegistry.getProjectType(createRequest.getBody().getType()) != null, "Invalid project type"); final Path path = Path.valueOf(createRequest.getBody().getPath()); - return findResource(path, true).thenPromise(new Function, Promise>() { @Override public Promise apply(Optional resource) throws FunctionException { - - final MutableProjectConfig projectConfig = (MutableProjectConfig)createRequest.getBody(); - final ProjectConfigDto dto = dtoFactory.createDto(ProjectConfigDto.class) - .withName(projectConfig.getName()) - .withPath(path.toString()) - .withDescription(projectConfig.getDescription()) - .withType(projectConfig.getType()) - .withMixins(projectConfig.getMixins()) - .withAttributes(projectConfig.getAttributes()); - - if (resource.isPresent()) { if (resource.get().isProject()) { throw new IllegalStateException("Project already exists"); @@ -435,22 +426,32 @@ public Promise apply(Optional resource) throws FunctionExcept return update(path, createRequest); } - return ps.createProject(dto, projectConfig.getOptions()).thenPromise(new Function>() { + final MutableProjectConfig projectConfig = (MutableProjectConfig)createRequest.getBody(); + final List projectConfigList = projectConfig.getProjects(); + projectConfigList.add(asDto(projectConfig)); + final List configDtoList = asDto(projectConfigList); + + return ps.createBatchProjects(configDtoList).thenPromise(new Function, Promise>() { @Override - public Promise apply(ProjectConfigDto config) throws FunctionException { - final Project newResource = resourceFactory.newProjectImpl(config, ResourceManager.this); - store.register(newResource); + public Promise apply(final List configList) throws FunctionException { return ps.getProjects().then(new Function, Project>() { @Override public Project apply(List updatedConfiguration) throws FunctionException { - //cache new configs cachedConfigs = updatedConfiguration.toArray(new ProjectConfigDto[updatedConfiguration.size()]); - eventBus.fireEvent(new ResourceChangedEvent(new ResourceDeltaImpl(newResource, ADDED | DERIVED))); + for (ProjectConfigDto projectConfigDto : configList) { + if (projectConfigDto.getPath().equals(path.toString())) { + final Project newResource = resourceFactory.newProjectImpl(projectConfigDto, ResourceManager.this); + store.register(newResource); + eventBus.fireEvent(new ResourceChangedEvent(new ResourceDeltaImpl(newResource, ADDED | DERIVED))); - return newResource; + return newResource; + } + } + + throw new IllegalStateException("Created project is not found"); } }); } @@ -459,6 +460,46 @@ public Project apply(List updatedConfiguration) throws Functio }); } + private NewProjectConfigDto asDto(MutableProjectConfig config) { + final SourceStorage source = config.getSource(); + final SourceStorageDto sourceStorageDto = dtoFactory.createDto(SourceStorageDto.class) + .withType(source.getType()) + .withLocation(source.getLocation()) + .withParameters(source.getParameters()); + + return dtoFactory.createDto(NewProjectConfigDto.class) + .withName(config.getName()) + .withPath(config.getPath()) + .withDescription(config.getDescription()) + .withSource(sourceStorageDto) + .withType(config.getType()) + .withMixins(config.getMixins()) + .withAttributes(config.getAttributes()) + .withOptions(config.getOptions()); + } + + private List asDto(List configList) { + List result = new ArrayList<>(configList.size()); + for (NewProjectConfig config : configList) { + final SourceStorage source = config.getSource(); + final SourceStorageDto sourceStorageDto = dtoFactory.createDto(SourceStorageDto.class) + .withType(source.getType()) + .withLocation(source.getLocation()) + .withParameters(source.getParameters()); + + result.add(dtoFactory.createDto(NewProjectConfigDto.class) + .withName(config.getName()) + .withPath(config.getPath()) + .withDescription(config.getDescription()) + .withSource(sourceStorageDto) + .withType(config.getType()) + .withMixins(config.getMixins()) + .withAttributes(config.getAttributes()) + .withOptions(config.getOptions())); + } + return result; + } + protected Promise importProject(final Project.ProjectRequest importRequest) { checkArgument(checkProjectName(importRequest.getBody().getName()), "Invalid project name"); checkNotNull(importRequest.getBody().getSource(), "Null source configuration occurred"); diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java index 6588869e913..75f540b65ab 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java @@ -139,7 +139,7 @@ public void shouldInvokeCallbackWhenCreatingFailure() throws Exception { public void shouldImportProjectSuccessfully() throws Exception { prepareWizard(IMPORT); - when(workspaceRoot.importProject()).thenReturn(createProjectRequest); + when(workspaceRoot.newProject()).thenReturn(createProjectRequest); when(createProjectRequest.withBody(any(ProjectConfig.class))).thenReturn(createProjectRequest); when(createProjectRequest.send()).thenReturn(createProjectPromise); when(createProjectPromise.then(any(Operation.class))).thenReturn(createProjectPromise); @@ -159,7 +159,7 @@ public void shouldImportProjectSuccessfully() throws Exception { public void shouldFailOnImportProject() throws Exception { prepareWizard(IMPORT); - when(workspaceRoot.importProject()).thenReturn(createProjectRequest); + when(workspaceRoot.newProject()).thenReturn(createProjectRequest); when(createProjectRequest.withBody(any(ProjectConfig.class))).thenReturn(createProjectRequest); when(createProjectRequest.send()).thenReturn(createProjectPromise); when(createProjectPromise.then(any(Operation.class))).thenReturn(createProjectPromise); diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/main/java/org/eclipse/che/plugin/java/plain/server/rest/ClasspathUpdaterService.java b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/main/java/org/eclipse/che/plugin/java/plain/server/rest/ClasspathUpdaterService.java index 1d575a42e03..64513fdbbbe 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/main/java/org/eclipse/che/plugin/java/plain/server/rest/ClasspathUpdaterService.java +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/src/main/java/org/eclipse/che/plugin/java/plain/server/rest/ClasspathUpdaterService.java @@ -16,7 +16,8 @@ import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.project.server.NewProjectConfig; +import org.eclipse.che.api.core.model.project.NewProjectConfig; +import org.eclipse.che.api.project.server.NewProjectConfigImpl; import org.eclipse.che.api.project.server.ProjectManager; import org.eclipse.che.api.project.server.ProjectRegistry; import org.eclipse.che.api.project.server.RegisteredProject; @@ -104,7 +105,7 @@ private void updateProjectConfig(String projectPath) throws IOException, ServerException { RegisteredProject project = projectRegistry.getProject(projectPath); - NewProjectConfig projectConfig = new NewProjectConfig(projectPath, + NewProjectConfig projectConfig = new NewProjectConfigImpl(projectPath, project.getName(), project.getType(), project.getSource()); diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.java b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.java index e45c49ef7a2..3be0207de9b 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.java +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.java @@ -61,4 +61,10 @@ public interface MavenLocalizationConstant extends Messages { @Key("window.loader.title") String windowLoaderTitle(); + + @Key("maven.page.estimate.errorMessage") + String mavenPageEstimateErrorMessage(); + + @Key("maven.page.errorDialog.title") + String mavenPageErrorDialogTitle(); } diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenter.java b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenter.java index 8a34d04a227..43d3fd4e5ea 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenter.java +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenter.java @@ -27,6 +27,7 @@ import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.plugin.maven.client.MavenArchetype; import org.eclipse.che.plugin.maven.client.MavenExtension; +import org.eclipse.che.plugin.maven.client.MavenLocalizationConstant; import javax.validation.constraints.NotNull; import java.util.Arrays; @@ -62,18 +63,21 @@ */ public class MavenPagePresenter extends AbstractWizardPage implements MavenPageView.ActionDelegate { - private final MavenPageView view; - private final DialogFactory dialogFactory; - private final AppContext appContext; + private final MavenPageView view; + private final DialogFactory dialogFactory; + private final AppContext appContext; + private final MavenLocalizationConstant localization; @Inject public MavenPagePresenter(MavenPageView view, DialogFactory dialogFactory, - AppContext appContext) { + AppContext appContext, + MavenLocalizationConstant localization) { super(); this.view = view; this.dialogFactory = dialogFactory; this.appContext = appContext; + this.localization = localization; view.setDelegate(this); } @@ -104,6 +108,13 @@ public void apply(Optional container) throws OperationException { container.get().estimate(MAVEN_ID).then(new Operation() { @Override public void apply(SourceEstimation estimation) throws OperationException { + if (!estimation.isMatched()) { + final String resolution = estimation.getResolution(); + final String errorMessage = resolution.isEmpty() ? localization.mavenPageEstimateErrorMessage() : resolution; + dialogFactory.createMessageDialog(localization.mavenPageErrorDialogTitle(), errorMessage, null).show(); + return; + } + Map> estimatedAttributes = estimation.getAttributes(); List artifactIdValues = estimatedAttributes.get(ARTIFACT_ID); if (artifactIdValues != null && !artifactIdValues.isEmpty()) { @@ -136,7 +147,7 @@ public void apply(SourceEstimation estimation) throws OperationException { }).catchError(new Operation() { @Override public void apply(PromiseError arg) throws OperationException { - dialogFactory.createMessageDialog("Not valid Maven project", arg.getMessage(), null).show(); + dialogFactory.createMessageDialog(localization.mavenPageErrorDialogTitle(), arg.getMessage(), null).show(); Log.error(MavenPagePresenter.class, arg); } }); diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/main/resources/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.properties b/plugins/plugin-maven/che-plugin-maven-ide/src/main/resources/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.properties index 51bf92a9a09..84a5d69c97c 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/main/resources/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.properties +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/main/resources/org/eclipse/che/plugin/maven/client/MavenLocalizationConstant.properties @@ -36,3 +36,6 @@ loader.action.name=Dependencies resolver loader.action.description=Maven Dependencies Resolver window.loader.title=Resolving dependencies +##### Wizard Maven Page ##### +maven.page.errorDialog.title=Not valid Maven project +maven.page.estimate.errorMessage=Source code not matches Maven project type requirements diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenterTest.java b/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenterTest.java index 4fe2d31cc10..09492665fd8 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenterTest.java +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/test/java/org/eclipse/che/plugin/maven/client/wizard/MavenPagePresenterTest.java @@ -22,6 +22,7 @@ import org.eclipse.che.ide.api.dialogs.MessageDialog; import org.eclipse.che.ide.api.project.MutableProjectConfig; import org.eclipse.che.ide.api.resources.Container; +import org.eclipse.che.plugin.maven.client.MavenLocalizationConstant; import org.eclipse.che.plugin.maven.shared.MavenAttributes; import org.junit.Before; import org.junit.Test; @@ -52,13 +53,15 @@ public class MavenPagePresenterTest { private final static String TEXT = "to be or not to be"; @Mock - private MavenPageView view; + private MavenPageView view; @Mock - private EventBus eventBus; + private EventBus eventBus; @Mock - private DialogFactory dialogFactory; + private DialogFactory dialogFactory; @Mock - private AppContext appContext; + private AppContext appContext; + @Mock + private MavenLocalizationConstant localization; @InjectMocks private MavenPagePresenter mavenPagePresenter; @@ -106,11 +109,13 @@ public void constructorShouldBePerformed() throws Exception { @Test public void warningWindowShouldBeShowedIfProjectEstimationHasSomeError() throws Exception { + final String dialogTitle = "Not valid Maven project"; PromiseError promiseError = mock(PromiseError.class); MessageDialog messageDialog = mock(MessageDialog.class); context.put(WIZARD_MODE_KEY, UPDATE.toString()); when(promiseError.getMessage()).thenReturn(TEXT); + when(localization.mavenPageErrorDialogTitle()).thenReturn(dialogTitle); when(dialogFactory.createMessageDialog(anyString(), anyString(), anyObject())).thenReturn(messageDialog); when(sourceEstimationPromise.then(Matchers.>anyObject())).thenReturn(sourceEstimationPromise); when(sourceEstimationPromise.catchError(Matchers.>anyObject())).thenReturn(sourceEstimationPromise); @@ -124,7 +129,7 @@ public void warningWindowShouldBeShowedIfProjectEstimationHasSomeError() throws containerArgumentErrorCapture.getValue().apply(promiseError); verify(promiseError).getMessage(); - verify(dialogFactory).createMessageDialog("Not valid Maven project", TEXT, null); + verify(dialogFactory).createMessageDialog(dialogTitle, TEXT, null); verify(messageDialog).show(); } diff --git a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java index 1a8b8f617fc..5ff457b76bc 100644 --- a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java +++ b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java @@ -15,19 +15,20 @@ */ public class Constants { - public static final String BLANK_ID = "blank"; - public static final String ZIP_IMPORTER_ID = "zip"; - public static final String VCS_PROVIDER_NAME = "vcs.provider.name"; + public static final String BLANK_ID = "blank"; + public static final String ZIP_IMPORTER_ID = "zip"; + public static final String VCS_PROVIDER_NAME = "vcs.provider.name"; // rels for known project links - public static final String LINK_REL_GET_PROJECTS = "get projects"; - public static final String LINK_REL_CREATE_PROJECT = "create project"; - public static final String LINK_REL_UPDATE_PROJECT = "update project"; - public static final String LINK_REL_EXPORT_ZIP = "zipball sources"; - public static final String LINK_REL_CHILDREN = "children"; - public static final String LINK_REL_TREE = "tree"; - public static final String LINK_REL_DELETE = "delete"; - public static final String LINK_REL_GET_CONTENT = "get content"; - public static final String LINK_REL_UPDATE_CONTENT = "update content"; + public static final String LINK_REL_GET_PROJECTS = "get projects"; + public static final String LINK_REL_CREATE_PROJECT = "create project"; + public static final String LINK_REL_CREATE_BATCH_PROJECTS = "create batch of projects"; + public static final String LINK_REL_UPDATE_PROJECT = "update project"; + public static final String LINK_REL_EXPORT_ZIP = "zipball sources"; + public static final String LINK_REL_CHILDREN = "children"; + public static final String LINK_REL_TREE = "tree"; + public static final String LINK_REL_DELETE = "delete"; + public static final String LINK_REL_GET_CONTENT = "get content"; + public static final String LINK_REL_UPDATE_CONTENT = "update content"; public static final String LINK_REL_PROJECT_TYPES = "project types"; diff --git a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/SourceEstimation.java b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/SourceEstimation.java index d2054f131d8..b7f2fd10001 100644 --- a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/SourceEstimation.java +++ b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/dto/SourceEstimation.java @@ -24,7 +24,6 @@ @DTO public interface SourceEstimation { - /** Gets unique id of type of project. */ @ApiModelProperty(value = "type ID", position = 1) String getType(); @@ -44,4 +43,10 @@ public interface SourceEstimation { SourceEstimation withMatched(boolean matched); + + /** Gets resolution - the reason that source code not matches project type requirements. */ + @ApiModelProperty(value = "Resolution", position = 4) + String getResolution(); + + SourceEstimation withResolution(String resolution); } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfig.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfig.java deleted file mode 100644 index d7036ca7610..00000000000 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfig.java +++ /dev/null @@ -1,118 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.project.server; - -import org.eclipse.che.api.core.model.project.ProjectConfig; -import org.eclipse.che.api.core.model.project.SourceStorage; -import org.eclipse.che.api.project.server.type.BaseProjectType; -import org.eclipse.che.api.vfs.Path; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author gazarenkov - */ -public class NewProjectConfig implements ProjectConfig { - - private final String path; - private final String type; - private final List mixins; - private final String name; - private final String description; - private final Map> attributes; - private final SourceStorage origin; - - /** - * Full qualified constructor - * - * @param path - * @param type - * @param mixins - * @param name - * @param description - * @param attributes - * @param origin - */ - public NewProjectConfig(String path, - String type, - List mixins, - String name, - String description, - Map> attributes, - SourceStorage origin) { - this.path = path; - this.type = (type == null) ? BaseProjectType.ID : type; - this.mixins = (mixins == null) ? new ArrayList<>() : mixins; - this.name = name; - this.description = description; - this.attributes = (attributes == null) ? new HashMap<>() : attributes; - this.origin = origin; - } - - /** - * Constructor for project import - * - * @param path - * @param name - * @param type - * @param origin - */ - public NewProjectConfig(String path, String name, String type, SourceStorage origin) { - this(path, type, null, name, null, null, origin); - } - - /** - * Constructor for reinit - * - * @param path - */ - public NewProjectConfig(Path path) { - this(path.toString(), null, null, path.getName(), null, null, null); - } - - @Override - public String getName() { - return name; - } - - @Override - public String getPath() { - return path; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public String getType() { - return type; - } - - @Override - public List getMixins() { - return mixins; - } - - @Override - public Map> getAttributes() { - return attributes; - } - - @Override - public SourceStorage getSource() { - return origin; - } -} diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfigImpl.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfigImpl.java new file mode 100644 index 00000000000..8bb56351c18 --- /dev/null +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/NewProjectConfigImpl.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.project.server; + +import org.eclipse.che.api.core.model.project.NewProjectConfig; +import org.eclipse.che.api.core.model.project.SourceStorage; +import org.eclipse.che.api.project.server.type.BaseProjectType; +import org.eclipse.che.api.vfs.Path; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Maps.newHashMap; + +/** + * Implementation of {@link NewProjectConfig} for creating project + * + * @author gazarenkov + */ +public class NewProjectConfigImpl implements NewProjectConfig { + + private String path; + private String type; + private List mixins; + private String name; + private String description; + private Map> attributes; + private Map options; + private SourceStorage origin; + + /** + * Full qualified constructor + * + * @param path + * project path + * @param type + * project type + * @param mixins + * mixin project types + * @param name + * project name + * @param description + * project description + * @param attributes + * project attributes + * @param options + * options for generator for creating project + * @param origin + * source configuration + */ + public NewProjectConfigImpl(String path, + String type, + List mixins, + String name, + String description, + Map> attributes, + Map options, + SourceStorage origin) { + this.path = path; + this.type = (type == null) ? BaseProjectType.ID : type; + this.mixins = (mixins == null) ? new ArrayList<>() : mixins; + this.name = name; + this.description = description; + this.attributes = (attributes == null) ? newHashMap() : attributes; + this.options = (options == null) ? newHashMap() : options; + this.origin = origin; + } + + /** + * Constructor for project import + * + * @param path + * project path + * @param name + * project name + * @param type + * project type + * @param origin + * source configuration + */ + public NewProjectConfigImpl(String path, String name, String type, SourceStorage origin) { + this(path, type, null, name, null, null, null, origin); + } + + /** + * Constructor for reinit + * + * @param path + */ + public NewProjectConfigImpl(Path path) { + this(path.toString(), null, null, path.getName(), null, null, null, null); + } + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public String getPath() { + return path; + } + + @Override + public void setPath(String path) { + this.path = path; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public void setDescription(String description) { + this.description = description; + } + + @Override + public String getType() { + return type; + } + + @Override + public void setType(String type) { + this.type = type; + } + + @Override + public List getMixins() { + return mixins != null ? mixins : newArrayList(); + } + + @Override + public void setMixins(List mixins) { + this.mixins = mixins; + } + + @Override + public Map> getAttributes() { + return attributes != null ? attributes : newHashMap(); + } + + @Override + public void setAttributes(Map> attributes) { + this.attributes = attributes; + } + + @Override + public SourceStorage getSource() { + return origin; + } + + @Override + public void setOptions(Map options) { + this.options = options; + } + + @Override + public Map getOptions() { + return options != null ? options : newHashMap(); + } +} diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java index 66495bedbd1..5c771b59074 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java @@ -12,16 +12,19 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.eclipse.che.api.core.BadRequestException; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.UnauthorizedException; +import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.model.project.SourceStorage; import org.eclipse.che.api.core.model.project.type.ProjectType; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.core.util.LineConsumerFactory; +import org.eclipse.che.api.project.server.RegisteredProject.Problem; import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.project.server.handlers.CreateProjectHandler; import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry; @@ -33,7 +36,6 @@ import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.project.server.type.ProjectTypeResolution; -import org.eclipse.che.api.project.server.type.ValueStorageException; import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType; import org.eclipse.che.api.vfs.Path; import org.eclipse.che.api.vfs.VirtualFile; @@ -61,6 +63,10 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.lang.String.format; /** * Facade for all project related operations. @@ -196,7 +202,7 @@ public List getProjects() throws ServerException { public RegisteredProject getProject(String projectPath) throws ServerException, NotFoundException { final RegisteredProject project = projectRegistry.getProject(projectPath); if (project == null) { - throw new NotFoundException(String.format("Project '%s' doesn't exist.", projectPath)); + throw new NotFoundException(format("Project '%s' doesn't exist.", projectPath)); } return project; @@ -229,67 +235,179 @@ public RegisteredProject createProject(ProjectConfig projectConfig, Map valueMap = new HashMap<>(); - Map> attributes = projectConfig.getAttributes(); - if (attributes != null) { - for (Map.Entry> entry : attributes.entrySet()) { - valueMap.put(entry.getKey(), new AttributeValue(entry.getValue())); - } - } - if (options == null) { - options = new HashMap<>(); + return doCreateProject(projectConfig, options); + } finally { + projectTreeChangesDetector.resume(); + } + } + + /** Note: Use {@link ProjectTreeChangesDetector#suspend()} and {@link ProjectTreeChangesDetector#resume()} while creating a project */ + private RegisteredProject doCreateProject(ProjectConfig projectConfig, Map options) throws ConflictException, + ForbiddenException, + ServerException, + NotFoundException { + final String path = ProjectRegistry.absolutizePath(projectConfig.getPath()); + final CreateProjectHandler generator = handlers.getCreateProjectHandler(projectConfig.getType()); + FolderEntry projectFolder; + if (generator != null) { + Map valueMap = new HashMap<>(); + Map> attributes = projectConfig.getAttributes(); + if (attributes != null) { + for (Map.Entry> entry : attributes.entrySet()) { + valueMap.put(entry.getKey(), new AttributeValue(entry.getValue())); } - Path projectPath = Path.of(path); - generator.onCreateProject(projectPath, valueMap, options); - projectFolder = new FolderEntry(vfs.getRoot().getChild(projectPath), projectRegistry); - } else { - projectFolder = new FolderEntry(vfs.getRoot().createFolder(path), projectRegistry); } + if (options == null) { + options = new HashMap<>(); + } + Path projectPath = Path.of(path); + generator.onCreateProject(projectPath, valueMap, options); + projectFolder = new FolderEntry(vfs.getRoot().getChild(projectPath), projectRegistry); + } else { + projectFolder = new FolderEntry(vfs.getRoot().createFolder(path), projectRegistry); + } - final RegisteredProject project; - try { - project = projectRegistry.putProject(projectConfig, projectFolder, true, false); - } catch (Exception e) { - // rollback project folder + final RegisteredProject project = projectRegistry.putProject(projectConfig, projectFolder, true, false); + workspaceProjectsHolder.sync(projectRegistry); + projectRegistry.fireInitHandlers(project); - projectFolder.getVirtualFile().delete(); - throw e; - } + return project; + } - // unlike imported it is not appropriate for newly created project to have problems - if(!project.getProblems().isEmpty()) { + /** + * Create batch of projects according to their configurations. + *

    + * Notes: - a project will be created by importing when project configuration contains {@link SourceStorage} object, + * otherwise this one will be created corresponding its {@link NewProjectConfig}: + *

  • - {@link NewProjectConfig} object contains only one mandatory {@link NewProjectConfig#setPath(String)} field. + * In this case Project will be created as project of {@link BaseProjectType} type
  • + *
  • - a project will be created as project of {@link BaseProjectType} type with {@link Problem#code} = 12 + * when declared primary project type is not registered,
  • + *
  • - a project will be created with {@link Problem#code} = 12 and without mixin project type + * when declared mixin project type is not registered
  • + *
  • - for creating a project by generator {@link NewProjectConfig#getOptions()} should be specified.
  • + * + * @param projectConfigList + * the list of configurations to create projects + * @param rewrite + * whether rewrite or not (throw exception otherwise) if such a project exists + * @return the list of new projects + * @throws BadRequestException + * when {@link NewProjectConfig} object not contains mandatory {@link NewProjectConfig#setPath(String)} field. + * @throws ConflictException + * when the same path project exists and {@code rewrite} is {@code false} + * @throws ForbiddenException + * when trying to overwrite the project and this one contains at least one locked file + * @throws NotFoundException + * when parent folder does not exist + * @throws UnauthorizedException + * if user isn't authorized to access to location at importing source code + * @throws ServerException + * if other error occurs + */ + public List createBatchProjects(List projectConfigList, boolean rewrite) + throws BadRequestException, ConflictException, ForbiddenException, NotFoundException, ServerException, UnauthorizedException, + IOException { + projectTreeChangesDetector.suspend(); + try { + final List projects = new ArrayList<>(projectConfigList.size()); + validateProjectConfigurations(projectConfigList, rewrite); - // rollback project folder - projectFolder.getVirtualFile().delete(); - // remove project entry - projectRegistry.removeProjects(projectConfig.getPath()); - throw new ServerException("Problems occured: " + project.getProblemsStr()); - } + final List sortedConfigList = projectConfigList + .stream() + .sorted((config1, config2) -> config1.getPath().compareTo(config2.getPath())) + .collect(Collectors.toList()); + + for (NewProjectConfig projectConfig : sortedConfigList) { + RegisteredProject registeredProject; + final String pathToProject = projectConfig.getPath(); + + //creating project(by config or by importing source code) + try { + final SourceStorage sourceStorage = projectConfig.getSource(); + if (sourceStorage != null && !isNullOrEmpty(sourceStorage.getLocation())) { + doImportProject(pathToProject, sourceStorage, rewrite); + } else if (!isVirtualFileExist(pathToProject)) { + registeredProject = doCreateProject(projectConfig, projectConfig.getOptions()); + projects.add(registeredProject); + continue; + } + } catch (Exception e) { + if (!isVirtualFileExist(pathToProject)) {//project folder is absent + rollbackCreatingBatchProjects(projects); + throw e; + } + } + //update project + if (isVirtualFileExist(pathToProject)) { + try { + registeredProject = updateProject(projectConfig); + } catch (Exception e) { + registeredProject = projectRegistry.putProject(projectConfig, asFolder(pathToProject), true, false); + registeredProject.getProblems().add(new Problem(14, "The project is not updated, caused by " + e.getLocalizedMessage())); + } + } else { + registeredProject = projectRegistry.putProject(projectConfig, null, true, false); + } - workspaceProjectsHolder.sync(projectRegistry); + projects.add(registeredProject); + } - projectRegistry.fireInitHandlers(project); + return projects; - return project; } finally { projectTreeChangesDetector.resume(); } } + private void rollbackCreatingBatchProjects(List projects) { + for (RegisteredProject project : projects) { + try { + final FolderEntry projectFolder = project.getBaseFolder(); + if (projectFolder != null) { + projectFolder.getVirtualFile().delete(); + } + projectRegistry.removeProjects(project.getPath()); + } catch (Exception e) { + LOG.warn(e.getLocalizedMessage()); + } + } + } + + private void validateProjectConfigurations(List projectConfigList, boolean rewrite) + throws NotFoundException, ServerException, ConflictException, ForbiddenException, BadRequestException { + + for (NewProjectConfig projectConfig : projectConfigList) { + final String pathToProject = projectConfig.getPath(); + if (isNullOrEmpty(pathToProject)) { + throw new BadRequestException("Path for new project should be defined"); + } + + final String path = ProjectRegistry.absolutizePath(pathToProject); + final RegisteredProject registeredProject = projectRegistry.getProject(path); + if (registeredProject != null && rewrite) { + delete(path); + } else if (registeredProject != null) { + throw new ConflictException(format("Project config already exists for %s", path)); + } + + final String projectTypeId = projectConfig.getType(); + if (isNullOrEmpty(projectTypeId)) { + projectConfig.setType(BaseProjectType.ID); + } + } + } + /** * Updating project means: * - getting the project (should exist) @@ -311,31 +429,17 @@ public RegisteredProject updateProject(ProjectConfig newConfig) throws Forbidden ServerException, NotFoundException, ConflictException { - String path = newConfig.getPath(); - + final String path = newConfig.getPath(); if (path == null) { throw new ConflictException("Project path is not defined"); } final FolderEntry baseFolder = asFolder(path); - - // If a project does not exist in the target path, create a new one if (baseFolder == null) { - throw new NotFoundException(String.format("Folder '%s' doesn't exist.", path)); + throw new NotFoundException(format("Folder '%s' doesn't exist.", path)); } - ProjectConfig oldConfig = projectRegistry.getProject(path); - final RegisteredProject project = projectRegistry.putProject(newConfig, baseFolder, true, false); - - // unlike imported it is not appropriate for updated project to have problems - if(!project.getProblems().isEmpty()) { - - // rollback project folder - projectRegistry.putProject(oldConfig, baseFolder, false, false); - throw new ServerException("Problems occured: " + project.getProblemsStr()); - } - workspaceProjectsHolder.sync(projectRegistry); projectRegistry.fireInitHandlers(project); @@ -371,55 +475,65 @@ public RegisteredProject importProject(String path, SourceStorage sourceStorage, NotFoundException { projectTreeChangesDetector.suspend(); try { - final ProjectImporter importer = importers.getImporter(sourceStorage.getType()); - if (importer == null) { - throw new NotFoundException(String.format("Unable import sources project from '%s'. Sources type '%s' is not supported.", - sourceStorage.getLocation(), sourceStorage.getType())); - } + return doImportProject(path, sourceStorage, rewrite); + } finally { + projectTreeChangesDetector.resume(); + } + } - // Preparing websocket output publisher to broadcast output of import process to the ide clients while importing - final LineConsumerFactory outputOutputConsumerFactory = - () -> new ProjectImportOutputWSLineConsumer(path, workspaceProjectsHolder.getWorkspaceId(), 300); + /** Note: Use {@link ProjectTreeChangesDetector#suspend()} and {@link ProjectTreeChangesDetector#resume()} while importing source code */ + private RegisteredProject doImportProject(String path, SourceStorage sourceStorage, boolean rewrite) throws ServerException, + IOException, + ForbiddenException, + UnauthorizedException, + ConflictException, + NotFoundException { + final ProjectImporter importer = importers.getImporter(sourceStorage.getType()); + if (importer == null) { + throw new NotFoundException(format("Unable import sources project from '%s'. Sources type '%s' is not supported.", + sourceStorage.getLocation(), sourceStorage.getType())); + } - String normalizePath = (path.startsWith("/")) ? path : "/".concat(path); - FolderEntry folder = asFolder(normalizePath); - if (folder != null && !rewrite) { - throw new ConflictException(String.format("Project %s already exists ", path)); - } + // Preparing websocket output publisher to broadcast output of import process to the ide clients while importing + final LineConsumerFactory outputOutputConsumerFactory = + () -> new ProjectImportOutputWSLineConsumer(path, workspaceProjectsHolder.getWorkspaceId(), 300); - if (folder == null) { - folder = getProjectsRoot().createFolder(normalizePath); - } + String normalizePath = (path.startsWith("/")) ? path : "/".concat(path); + FolderEntry folder = asFolder(normalizePath); + if (folder != null && !rewrite) { + throw new ConflictException(format("Project %s already exists ", path)); + } - try { - importer.importSources(folder, sourceStorage, outputOutputConsumerFactory); - } catch (final Exception e) { - folder.remove(); - throw e; - } + if (folder == null) { + folder = getProjectsRoot().createFolder(normalizePath); + } - final String name = folder.getPath().getName(); - for (ProjectConfig project : workspaceProjectsHolder.getProjects()) { - if (normalizePath.equals(project.getPath())) { - // TODO Needed for factory project importing with keepDir. It needs to find more appropriate solution - List innerProjects = projectRegistry.getProjects(normalizePath); - for (String innerProject : innerProjects) { - RegisteredProject registeredProject = projectRegistry.getProject(innerProject); - projectRegistry.putProject(registeredProject, asFolder(registeredProject.getPath()), true, false); - } - RegisteredProject rp = projectRegistry.putProject(project, folder, true, false); - workspaceProjectsHolder.sync(projectRegistry); - return rp; + try { + importer.importSources(folder, sourceStorage, outputOutputConsumerFactory); + } catch (final Exception e) { + folder.remove(); + throw e; + } + + final String name = folder.getPath().getName(); + for (ProjectConfig project : workspaceProjectsHolder.getProjects()) { + if (normalizePath.equals(project.getPath())) { + // TODO Needed for factory project importing with keepDir. It needs to find more appropriate solution + List innerProjects = projectRegistry.getProjects(normalizePath); + for (String innerProject : innerProjects) { + RegisteredProject registeredProject = projectRegistry.getProject(innerProject); + projectRegistry.putProject(registeredProject, asFolder(registeredProject.getPath()), true, false); } + RegisteredProject rp = projectRegistry.putProject(project, folder, true, false); + workspaceProjectsHolder.sync(projectRegistry); + return rp; } - - RegisteredProject rp = projectRegistry - .putProject(new NewProjectConfig(normalizePath, name, BaseProjectType.ID, sourceStorage), folder, true, false); - workspaceProjectsHolder.sync(projectRegistry); - return rp; - } finally { - projectTreeChangesDetector.resume(); } + + RegisteredProject rp = projectRegistry + .putProject(new NewProjectConfigImpl(normalizePath, name, BaseProjectType.ID, sourceStorage), folder, true, false); + workspaceProjectsHolder.sync(projectRegistry); + return rp; } /** @@ -431,11 +545,9 @@ public RegisteredProject importProject(String path, SourceStorage sourceStorage, * @return resolution object * @throws ServerException * @throws NotFoundException - * @throws ValueStorageException */ public ProjectTypeResolution estimateProject(String path, String projectTypeId) throws ServerException, - NotFoundException, - ValueStorageException { + NotFoundException { final ProjectTypeDef projectType = projectTypeRegistry.getProjectType(projectTypeId); if (projectType == null) { throw new NotFoundException("Project Type to estimate needed."); @@ -468,13 +580,9 @@ public List resolveSources(String path, boolean transient continue; } - try { - final ProjectTypeResolution resolution = estimateProject(path, type.getId()); - if (resolution.matched()) { - resolutions.add(resolution); - } - } catch (ValueStorageException e) { - LOG.warn(e.getLocalizedMessage(), e); + final ProjectTypeResolution resolution = estimateProject(path, type.getId()); + if (resolution.matched()) { + resolutions.add(resolution); } } @@ -606,13 +714,14 @@ public VirtualFileEntry moveTo(String itemPath, String newParentPath, String new if (move.isProject()) { final RegisteredProject project = projectRegistry.getProject(itemPath); - NewProjectConfig projectConfig = new NewProjectConfig(newItem.getPath().toString(), - project.getType(), - project.getMixins(), - newName, - project.getDescription(), - project.getAttributes(), - project.getSource()); + NewProjectConfig projectConfig = new NewProjectConfigImpl(newItem.getPath().toString(), + project.getType(), + project.getMixins(), + newName, + project.getDescription(), + project.getAttributes(), + null, + project.getSource()); if (move instanceof FolderEntry) { projectRegistry.removeProjects(project.getPath()); @@ -623,6 +732,10 @@ public VirtualFileEntry moveTo(String itemPath, String newParentPath, String new return move; } + boolean isVirtualFileExist(String path) throws ServerException { + return asVirtualFileEntry(path) != null; + } + FolderEntry asFolder(String path) throws NotFoundException, ServerException { final VirtualFileEntry entry = asVirtualFileEntry(path); if (entry == null) { @@ -630,13 +743,13 @@ FolderEntry asFolder(String path) throws NotFoundException, ServerException { } if (!entry.isFolder()) { - throw new NotFoundException(String.format("Item '%s' isn't a folder. ", path)); + throw new NotFoundException(format("Item '%s' isn't a folder. ", path)); } return (FolderEntry)entry; } - VirtualFileEntry asVirtualFileEntry(String path) throws NotFoundException, ServerException { + VirtualFileEntry asVirtualFileEntry(String path) throws ServerException { final String apath = ProjectRegistry.absolutizePath(path); final FolderEntry root = getProjectsRoot(); return root.getChild(apath); @@ -649,7 +762,7 @@ FileEntry asFile(String path) throws NotFoundException, ServerException { } if (!entry.isFile()) { - throw new NotFoundException(String.format("Item '%s' isn't a file. ", path)); + throw new NotFoundException(format("Item '%s' isn't a file. ", path)); } return (FileEntry)entry; @@ -676,7 +789,7 @@ private void reindexProject(final RegisteredProject project) throws ServerExcept } searcher.add(file); } catch (Exception e) { - LOG.warn(String.format("Project: %s", project.getPath()), e.getMessage()); + LOG.warn(format("Project: %s", project.getPath()), e.getMessage()); } }); } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectRegistry.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectRegistry.java index 00916233e0d..486dea86429 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectRegistry.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectRegistry.java @@ -14,6 +14,7 @@ import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry; @@ -181,15 +182,12 @@ public RegisteredProject getParentProject(String path) { * whether this is automatically detected or explicitly defined project * @return project * @throws ServerException - * @throws ConflictException - * @throws NotFoundException + * when path for project is undefined */ RegisteredProject putProject(ProjectConfig config, FolderEntry folder, boolean updated, - boolean detected) throws ServerException, - ConflictException, - NotFoundException { + boolean detected) throws ServerException { final RegisteredProject project = new RegisteredProject(folder, config, updated, detected, this.projectTypeRegistry); projects.put(project.getPath(), project); @@ -223,8 +221,7 @@ void removeProjects(String path) throws ServerException { * Attributes defined with particular Project Type * If incoming Project Type is primary and: * - If the folder located on projectPath is a Project, its Primary PT will be converted to incoming PT - * - If the folder located on projectPath is NOT a Project the folder will be converted to "detected" Project - * with incoming Primary PT + * - If the folder located on projectPath is NOT a Project the folder will be converted to "detected" Project with incoming Primary PT * If incoming Project Type is mixin and: * - If the folder located on projectPath is a Project, this PT will be added (if not already there) to its Mixin PTs * - If the folder located on projectPath is NOT a Project - ConflictException will be thrown @@ -268,7 +265,7 @@ public RegisteredProject setProjectType(String projectPath, final String path = absolutizePath(projectPath); final String name = Path.of(projectPath).getName(); - conf = new NewProjectConfig(path, type, newMixins, name, name, null, null); + conf = new NewProjectConfigImpl(path, type, newMixins, name, name, null, null, null); return putProject(conf, root.getChildFolder(path), true, true); } @@ -283,12 +280,13 @@ public RegisteredProject setProjectType(String projectPath, newType = type; } - conf = new NewProjectConfig(project.getPath(), + conf = new NewProjectConfigImpl(project.getPath(), newType, newMixins, project.getName(), project.getDescription(), project.getAttributes(), + null, project.getSource()); return putProject(conf, project.getBaseFolder(), true, project.isDetected()); @@ -339,12 +337,13 @@ public RegisteredProject removeProjectType(String projectPath, String type) thro newType = BaseProjectType.ID; } - final NewProjectConfig conf = new NewProjectConfig(project.getPath(), + final NewProjectConfig conf = new NewProjectConfigImpl(project.getPath(), newType, newMixins, project.getName(), project.getDescription(), project.getAttributes(), + null, project.getSource()); return putProject(conf, project.getBaseFolder(), true, project.isDetected()); @@ -367,7 +366,7 @@ private void initUnconfiguredFolders() { putProject(null, folder, true, false); } } - } catch (ServerException | ConflictException | NotFoundException e) { + } catch (ServerException e) { LOG.warn(e.getLocalizedMessage()); } } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java index 45bacf07b45..a6f98a2fd0a 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java @@ -43,6 +43,7 @@ import org.eclipse.che.api.vfs.search.SearchResult; import org.eclipse.che.api.vfs.search.SearchResultEntry; import org.eclipse.che.api.vfs.search.Searcher; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.commons.env.EnvironmentContext; @@ -90,6 +91,7 @@ import static org.eclipse.che.api.core.util.LinksHelper.createLink; import static org.eclipse.che.api.project.server.DtoConverter.asDto; import static org.eclipse.che.api.project.shared.Constants.LINK_REL_CHILDREN; +import static org.eclipse.che.api.project.shared.Constants.LINK_REL_CREATE_BATCH_PROJECTS; import static org.eclipse.che.api.project.shared.Constants.LINK_REL_CREATE_PROJECT; import static org.eclipse.che.api.project.shared.Constants.LINK_REL_DELETE; import static org.eclipse.che.api.project.shared.Constants.LINK_REL_GET_CONTENT; @@ -206,6 +208,37 @@ public ProjectConfigDto createProject(@ApiParam(value = "Add to this project as return injectProjectLinks(configDto); } + @POST + @Path("/batch") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Creates batch of projects according to their configurations", + notes = "A project will be created by importing when project configuration contains source object. " + + "For creating a project by generator options should be specified.", + response = ProjectConfigDto.class) + @ApiResponses({@ApiResponse(code = 200, message = "OK"), + @ApiResponse(code = 400, message = "Path for new project should be defined"), + @ApiResponse(code = 403, message = "Operation is forbidden"), + @ApiResponse(code = 409, message = "Project with specified name already exist in workspace"), + @ApiResponse(code = 500, message = "Server error")}) + @GenerateLink(rel = LINK_REL_CREATE_BATCH_PROJECTS) + public List createBatchProjects( + @Description("list of descriptors for projects") List projectConfigList, + @ApiParam(value = "Force rewrite existing project", allowableValues = "true,false") + @QueryParam("force") boolean rewrite) + throws ConflictException, ForbiddenException, ServerException, NotFoundException, IOException, UnauthorizedException, + BadRequestException { + + List result = new ArrayList<>(projectConfigList.size()); + for (RegisteredProject registeredProject : projectManager.createBatchProjects(projectConfigList, rewrite)) { + ProjectConfigDto projectConfig = injectProjectLinks(asDto(registeredProject)); + result.add(projectConfig); + + eventService.publish(new ProjectCreatedEvent(workspace, registeredProject.getPath())); + } + return result; + } + @PUT @Path("/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) @@ -271,6 +304,7 @@ public SourceEstimation estimateProject(@ApiParam(value = "Path to requested pro return DtoFactory.newDto(SourceEstimation.class) .withType(projectType) .withMatched(resolution.matched()) + .withResolution(resolution.getResolution()) .withAttributes(attributes); } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java index 270efb459e0..8338fa66040 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java @@ -11,13 +11,10 @@ package org.eclipse.che.api.project.server; import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.project.type.Attribute; import org.eclipse.che.api.project.server.RegisteredProject.Problem; -import org.eclipse.che.api.project.server.type.ProjectTypeConstraintException; import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; -import org.eclipse.che.api.project.server.type.ValueStorageException; import java.util.ArrayList; import java.util.HashMap; @@ -26,6 +23,9 @@ import java.util.Map; import java.util.Set; +import static com.google.common.collect.Lists.newArrayList; +import static java.lang.String.format; + /** * @author gazarenkov */ @@ -33,37 +33,40 @@ public class ProjectTypes { private final String projectPath; private final ProjectTypeRegistry projectTypeRegistry; - private ProjectTypeDef primary; + private ProjectTypeDef primary; private final Map mixins; private final Map all; private final Map attributeDefs; + private final List problems; ProjectTypes(String projectPath, - String type, - List mixinTypes, - ProjectTypeRegistry projectTypeRegistry, - List problems) throws ProjectTypeConstraintException, NotFoundException { + String type, + List mixinTypes, + ProjectTypeRegistry projectTypeRegistry, + List problems) { mixins = new HashMap<>(); all = new HashMap<>(); attributeDefs = new HashMap<>(); + this.problems = problems != null ? problems : newArrayList(); this.projectTypeRegistry = projectTypeRegistry; this.projectPath = projectPath; ProjectTypeDef tmpPrimary; if (type == null) { - problems.add(new Problem(12, "No primary type defined for " + projectPath + " Base Project Type assigned.")); + this.problems.add(new Problem(12, "No primary type defined for " + projectPath + " Base Project Type assigned.")); tmpPrimary = ProjectTypeRegistry.BASE_TYPE; } else { try { tmpPrimary = projectTypeRegistry.getProjectType(type); } catch (NotFoundException e) { - problems.add(new Problem(12, "Primary type " + type + " defined for " + projectPath + " is not registered. Base Project Type assigned.")); + this.problems.add(new Problem(12, "Primary type " + type + " defined for " + projectPath + + " is not registered. Base Project Type assigned.")); tmpPrimary = ProjectTypeRegistry.BASE_TYPE; } if (!tmpPrimary.isPrimaryable()) { - problems.add(new Problem(12, "Project type " + tmpPrimary.getId() + " is not allowable to be primary type. Base Project Type assigned.")); + this.problems.add(new Problem(12, "Project type " + tmpPrimary.getId() + " is not allowable to be primary type. Base Project Type assigned.")); tmpPrimary = ProjectTypeRegistry.BASE_TYPE; } } @@ -90,12 +93,12 @@ public class ProjectTypes { try { mixin = projectTypeRegistry.getProjectType(mixinFromConfig); } catch (NotFoundException e) { - problems.add(new Problem(12, "Project type " + mixinFromConfig + " is not registered. Skipped.")); + this.problems.add(new Problem(12, "Project type " + mixinFromConfig + " is not registered. Skipped.")); continue; } if (!mixin.isMixable()) { - problems.add(new Problem(12, "Project type " + mixin + " is not allowable to be mixin. It not mixable. Skipped.")); + this.problems.add(new Problem(12, "Project type " + mixin + " is not allowable to be mixin. It not mixable. Skipped.")); continue; } @@ -105,14 +108,15 @@ public class ProjectTypes { // detect duplicated attributes for (Attribute attr : mixin.getAttributes()) { - if (attributeDefs.containsKey(attr.getName())) { - - problems.add(new Problem(13, "Attribute name conflict. Duplicated attributes detected " + projectPath + - " Attribute " + attr.getName() + " declared in " + mixin.getId() + " already declared in " + - attributeDefs.get(attr.getName()).getProjectType()+" Skipped.")); + final String attrName = attr.getName(); + if (attributeDefs.containsKey(attrName)) { + this.problems.add(new Problem(13, + format("Attribute name conflict. Duplicated attributes detected for %s. " + + "Attribute %s declared in %s already declared in %s. Skipped.", + projectPath, attrName, mixin.getId(), attributeDefs.get(attrName).getProjectType()))); continue; } - attributeDefs.put(attr.getName(), attr); + attributeDefs.put(attrName, attr); } // Silently remove repeated items from mixins if any @@ -147,22 +151,22 @@ public Map getAll() { void reset(Set attributesToDel) { Set ptsToDel = new HashSet<>(); - for(Attribute attr : attributesToDel) { + for (Attribute attr : attributesToDel) { ptsToDel.add(attr.getProjectType()); } - Set attrNamesToDel = new HashSet<>(); - for(String pt : ptsToDel) { + Set attrNamesToDel = new HashSet<>(); + for (String pt : ptsToDel) { ProjectTypeDef typeDef = all.get(pt); - for(Attribute attrDef: typeDef.getAttributes()) { + for (Attribute attrDef : typeDef.getAttributes()) { attrNamesToDel.add(attrDef.getName()); } } // remove project types - for(String typeId : ptsToDel) { + for (String typeId : ptsToDel) { this.all.remove(typeId); - if(this.primary.getId().equals(typeId)) { + if (this.primary.getId().equals(typeId)) { this.primary = ProjectTypeRegistry.BASE_TYPE; this.all.put(ProjectTypeRegistry.BASE_TYPE.getId(), ProjectTypeRegistry.BASE_TYPE); } else { @@ -171,30 +175,27 @@ void reset(Set attributesToDel) { } // remove attributes - for(String attr : attrNamesToDel) { + for (String attr : attrNamesToDel) { this.attributeDefs.remove(attr); } } - void addTransient(FolderEntry projectFolder) throws ServerException, - NotFoundException, - ProjectTypeConstraintException, - ValueStorageException { + void addTransient(FolderEntry projectFolder) { for (ProjectTypeDef pt : projectTypeRegistry.getProjectTypes()) { // NOTE: Only mixable types allowed if (pt.isMixable() && !pt.isPersisted() && pt.resolveSources(projectFolder).matched()) { all.put(pt.getId(), pt); mixins.put(pt.getId(), pt); for (Attribute attr : pt.getAttributes()) { - if (attributeDefs.containsKey(attr.getName())) { - throw new ProjectTypeConstraintException( - "Attribute name conflict. Duplicated attributes detected " + projectPath + - " Attribute " + attr.getName() + " declared in " + pt.getId() + " already declared in " + - attributeDefs.get(attr.getName()).getProjectType() - ); + final String attrName = attr.getName(); + if (attributeDefs.containsKey(attrName)) { + problems.add(new Problem(13, + format("Attribute name conflict. Duplicated attributes detected for %s. " + + "Attribute %s declared in %s already declared in %s. Skipped.", + projectPath, attrName, pt.getId(), attributeDefs.get(attrName).getProjectType()))); } - attributeDefs.put(attr.getName(), attr); + attributeDefs.put(attrName, attr); } } } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/RegisteredProject.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/RegisteredProject.java index 641e4f0afbf..d3d60fdc61b 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/RegisteredProject.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/RegisteredProject.java @@ -10,14 +10,12 @@ *******************************************************************************/ package org.eclipse.che.api.project.server; -import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.model.project.SourceStorage; import org.eclipse.che.api.core.model.project.type.Attribute; import org.eclipse.che.api.core.model.project.type.Value; import org.eclipse.che.api.project.server.type.AttributeValue; -import org.eclipse.che.api.project.server.type.ProjectTypeConstraintException; import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.project.server.type.ValueProvider; @@ -27,12 +25,12 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; +import static java.lang.String.format; + /** * Internal Project implementation. * It is supposed that it is object always consistent. @@ -63,15 +61,14 @@ public class RegisteredProject implements ProjectConfig { * if this project was detected, initialized when "parent" project initialized * @param projectTypeRegistry * project type registry + * @throws ServerException + * when path for project is undefined */ RegisteredProject(FolderEntry folder, ProjectConfig config, boolean updated, boolean detected, - ProjectTypeRegistry projectTypeRegistry) throws NotFoundException, - ProjectTypeConstraintException, - ServerException, - ValueStorageException { + ProjectTypeRegistry projectTypeRegistry) throws ServerException { problems = new ArrayList<>(); attributes = new HashMap<>(); @@ -85,7 +82,7 @@ public class RegisteredProject implements ProjectConfig { } this.folder = folder; - this.config = (config == null) ? new NewProjectConfig(path) : config; + this.config = config == null ? new NewProjectConfigImpl(path) : config; this.updated = updated; this.detected = detected; @@ -97,6 +94,7 @@ public class RegisteredProject implements ProjectConfig { problems.add(new Problem(11, "No project configured in workspace " + this.config.getPath())); } + // 1. init project types this.types = new ProjectTypes(this.config.getPath(), this.config.getType(), this.config.getMixins(), projectTypeRegistry, problems); @@ -110,15 +108,9 @@ public class RegisteredProject implements ProjectConfig { /** * Initialize project attributes. - * - * @throws ValueStorageException - * @throws ProjectTypeConstraintException - * @throws ServerException - * @throws NotFoundException + * Note: the problem with {@link Problem#code} = 13 will be added when a value for some attribute is not initialized */ - private void initAttributes() throws ValueStorageException, ProjectTypeConstraintException, ServerException, NotFoundException { - - Set invalidAttributes = new HashSet<>(); + private void initAttributes() { // we take only defined attributes, others ignored for (Map.Entry entry : types.getAttributeDefs().entrySet()) { @@ -140,12 +132,17 @@ private void initAttributes() throws ValueStorageException, ProjectTypeConstrain if (folder != null) { - if (!valueProvider.isSettable() || value.isEmpty()) { - // get provided value - value = new AttributeValue(valueProvider.getValues(name)); - } else { - // set provided (not empty) value - valueProvider.setValues(name, value.getList()); + try { + if (!valueProvider.isSettable() || value.isEmpty()) { + // get provided value + value = new AttributeValue(valueProvider.getValues(name)); + } else { + // set provided (not empty) value + valueProvider.setValues(name, value.getList()); + } + } catch (ValueStorageException e) { + this.problems.add(new Problem(13, format("Value for attribute %s is not initialized, caused by: %s", + variable.getId(), e.getLocalizedMessage()))); } } else { @@ -155,7 +152,6 @@ private void initAttributes() throws ValueStorageException, ProjectTypeConstrain if (value.isEmpty() && variable.isRequired()) { this.problems.add(new Problem(13, "Value for required attribute is not initialized " + variable.getId())); - invalidAttributes.add(variable); //throw new ProjectTypeConstraintException("Value for required attribute is not initialized " + variable.getId()); } @@ -164,9 +160,6 @@ private void initAttributes() throws ValueStorageException, ProjectTypeConstrain } } } - - types.reset(invalidAttributes); - } /** diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/WorkspaceProjectsSyncer.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/WorkspaceProjectsSyncer.java index 48bfe61c9cb..390b561f597 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/WorkspaceProjectsSyncer.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/WorkspaceProjectsSyncer.java @@ -48,13 +48,14 @@ public final void sync(ProjectRegistry projectRegistry) throws ServerException { if(!project.isSynced() && !project.isDetected()) { - final ProjectConfig config = new NewProjectConfig(project.getPath(), - project.getType(), - project.getMixins(), - project.getName(), - project.getDescription(), - project.getPersistableAttributes(), - project.getSource()); + final ProjectConfig config = new NewProjectConfigImpl(project.getPath(), + project.getType(), + project.getMixins(), + project.getName(), + project.getDescription(), + project.getPersistableAttributes(), + null, + project.getSource()); boolean found = false; for(ProjectConfig r : remote) { diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeDef.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeDef.java index 44b262383b3..f665dd8a8a5 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeDef.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeDef.java @@ -20,6 +20,9 @@ import java.util.List; import java.util.Map; +import static com.google.common.collect.Maps.newHashMap; +import static java.lang.String.format; + /** * @author gazarenkov */ @@ -169,7 +172,7 @@ void addAncestor(String ancestor) { this.ancestors.add(ancestor); } - public ProjectTypeResolution resolveSources(FolderEntry projectFolder) throws ValueStorageException { + public ProjectTypeResolution resolveSources(FolderEntry projectFolder) { Map matchAttrs = new HashMap<>(); for (Map.Entry entry : attributes.entrySet()) { Attribute attr = entry.getValue(); @@ -178,11 +181,22 @@ public ProjectTypeResolution resolveSources(FolderEntry projectFolder) throws Va Variable var = (Variable)attr; ValueProviderFactory factory = var.getValueProviderFactory(); if (factory != null) { - Value value = new AttributeValue(factory.newInstance(projectFolder).getValues(name)); - if (value.isEmpty()) { + + Value value; + String errorMessage = ""; + try { + value = new AttributeValue(factory.newInstance(projectFolder).getValues(name)); + } catch (ValueStorageException e) { + value = null; + errorMessage = e.getLocalizedMessage(); + } + + if (value == null || value.isEmpty()) { if (var.isRequired()) { // this PT is not match - return new DefaultResolution(id, new HashMap<>(), false); + errorMessage = errorMessage.isEmpty() ? format("Value for required attribute %s is not initialized", name) + : errorMessage; + return new DefaultResolution(id, errorMessage); } } else { // add one more matched attribute @@ -204,6 +218,12 @@ public DefaultResolution(String type, Map attributes, boolean mat this.match = match; } + /** Use this one when source code not matches project type requirements */ + public DefaultResolution(String type, String resolution) { + super(type, newHashMap(), resolution); + this.match = false; + } + @Override public boolean matched() { return match; diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeResolution.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeResolution.java index ea448ffba91..6c154a27e4e 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeResolution.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/ProjectTypeResolution.java @@ -21,10 +21,16 @@ public abstract class ProjectTypeResolution { private String type; private Map attributes; + private String resolution; public ProjectTypeResolution(String type, Map attributes) { + this(type, attributes, ""); + } + + public ProjectTypeResolution(String type, Map attributes, String resolution) { this.type = type; this.attributes = attributes; + this.resolution = resolution; } /** @@ -34,6 +40,13 @@ public String getType() { return type; } + /** + * @return the reason that current source code NOT matches project type requirements + */ + public String getResolution() { + return resolution; + } + /** * @return true if current source code in generally matches project type requirements * by default (but not necessarily) it may check if there are all required provided attributes diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java index 55005265d97..d3a61e6eed9 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java @@ -10,21 +10,25 @@ *******************************************************************************/ package org.eclipse.che.api.project.server; +import org.eclipse.che.api.core.BadRequestException; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.model.project.SourceStorage; import org.eclipse.che.api.core.notification.EventSubscriber; import org.eclipse.che.api.core.util.LineConsumerFactory; import org.eclipse.che.api.core.util.ValueHolder; +import org.eclipse.che.api.project.server.RegisteredProject.Problem; import org.eclipse.che.api.project.server.handlers.CreateProjectHandler; import org.eclipse.che.api.project.server.importer.ProjectImporter; import org.eclipse.che.api.project.server.type.AttributeValue; import org.eclipse.che.api.project.server.type.BaseProjectType; import org.eclipse.che.api.project.server.type.Variable; import org.eclipse.che.api.vfs.Path; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.dto.server.DtoFactory; @@ -33,8 +37,10 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -43,6 +49,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -52,7 +59,7 @@ * @author gazarenkov */ public class ProjectManagerWriteTest extends WsAgentTestBase { - + private static final String FILE_CONTENT = "to be or not to be"; @Before public void setUp() throws Exception { @@ -66,14 +73,412 @@ public void setUp() throws Exception { projectTypeRegistry.registerProjectType(new PTsettableVP()); projectHandlerRegistry.register(new SrcGenerator()); + } + + @Test + public void testCreateBatchProjectsByConfigs() throws Exception { + final String projectPath1 = "/testProject1"; + final String projectPath2 = "/testProject2"; + final NewProjectConfig config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, null); + final NewProjectConfig config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, null); + + final List configs = new ArrayList<>(2); + configs.add(config1); + configs.add(config2); + + pm.createBatchProjects(configs, false); + + checkProjectExist(projectPath1); + checkProjectExist(projectPath2); + assertEquals(2, projectRegistry.getProjects().size()); } + @Test + public void testCreateBatchProjectsByImportingSourceCode() throws Exception { + final String projectPath1 = "/testProject1"; + final String projectPath2 = "/testProject2"; + final String importType1 = "importType1"; + final String importType2 = "importType2"; + + final String [] paths1 = {"folder1/", "folder1/file1.txt"}; + final List children1 = new ArrayList<>(Arrays.asList(paths1)); + registerImporter(importType1, prepareZipArchiveBasedOn(children1)); + + final String [] paths2 = {"folder2/", "folder2/file2.txt"}; + final List children2 = new ArrayList<>(Arrays.asList(paths2)); + registerImporter(importType2, prepareZipArchiveBasedOn(children2)); + + final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1); + final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, source1); + + final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2); + final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, source2); + + final List configs = new ArrayList<>(2); + configs.add(config1); + configs.add(config2); + + pm.createBatchProjects(configs, false); + + final RegisteredProject project1 = projectRegistry.getProject(projectPath1); + final FolderEntry projectFolder1 = project1.getBaseFolder(); + checkProjectExist(projectPath1); + checkChildrenFor(projectFolder1, children1); + + final RegisteredProject project2 = projectRegistry.getProject(projectPath2); + final FolderEntry projectFolder2 = project2.getBaseFolder(); + checkProjectExist(projectPath2); + checkChildrenFor(projectFolder2, children2); + } @Test - public void testCreateProject() throws Exception { + public void testCreateProjectWhenSourceCodeIsNotReachable() throws Exception { + final String projectPath = "/testProject"; + final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType"); + final NewProjectConfigDto config = createProjectConfigObject("testProject1", projectPath, BaseProjectType.ID, source); + + final List configs = new ArrayList<>(1); + configs.add(config); + + try { + pm.createBatchProjects(configs, false); + fail("Exception should be thrown when source code is not reachable"); + } catch (Exception e) { + assertEquals(0, projectRegistry.getProjects().size()); + assertNull(projectRegistry.getProject(projectPath)); + assertNull(pm.getProjectsRoot().getChild(projectPath)); + } + } + + @Test + public void shouldRollbackCreatingBatchProjects() throws Exception { + // we should rollback operation of creating batch projects when we have not source code for at least one project + // For example: two projects were success created, but we could not get source code for third configuration + // At this use case we should rollback the operation and clean up all created projects + + final String projectPath1 = "/testProject1"; + final String projectPath2 = "/testProject2"; + final String projectPath3 = "/testProject3"; + final String importType1 = "importType1"; + final String importType2 = "importType2"; + + final String [] paths1 = {"folder1/", "folder1/file1.txt"}; + final List children1 = new ArrayList<>(Arrays.asList(paths1)); + registerImporter(importType1, prepareZipArchiveBasedOn(children1)); + + final String [] paths2 = {"folder2/", "folder2/file2.txt"}; + final List children2 = new ArrayList<>(Arrays.asList(paths2)); + registerImporter(importType2, prepareZipArchiveBasedOn(children2)); + + final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1); + final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, source1); + + final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2); + final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, source2); + + final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType"); + final NewProjectConfigDto config3 = createProjectConfigObject("testProject3", projectPath3, BaseProjectType.ID, source); + + final List configs = new ArrayList<>(2); + configs.add(config1); //will be success created + configs.add(config2); //will be success created + configs.add(config3); //we be failed - we have not registered importer - source code will not be imported + + try { + pm.createBatchProjects(configs, false); + fail("We should rollback operation of creating batch projects when we could not get source code for at least one project"); + } catch (Exception e) { + assertEquals(0, projectRegistry.getProjects().size()); + + assertNull(projectRegistry.getProject(projectPath1)); + assertNull(pm.getProjectsRoot().getChild(projectPath1)); + + assertNull(projectRegistry.getProject(projectPath2)); + assertNull(pm.getProjectsRoot().getChild(projectPath2)); + + assertNull(projectRegistry.getProject(projectPath3)); + assertNull(pm.getProjectsRoot().getChild(projectPath3)); + } + } + + @Test + public void testCreateBatchProjectsWithInnerProject() throws Exception { + final String rootProjectPath = "/testProject1"; + final String innerProjectPath = "/testProject1/innerProject"; + final String importType = "importType1"; + final String innerProjectType = "pt2"; + + Map> attributes = new HashMap<>(); + attributes.put("pt2-var2", new AttributeValue("test").getList()); + + final String [] paths1 = {"folder1/", "folder1/file1.txt"}; + final String [] paths2 = {"innerProject/", "innerProject/folder2/", "innerProject/folder2/file2.txt"}; + final List children1 = Arrays.asList(paths1); + final List children2 = Arrays.asList(paths2); + final List children = new ArrayList<>(children1); + children.addAll(children2); + registerImporter(importType, prepareZipArchiveBasedOn(children)); + + SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType); + NewProjectConfigDto config1 = createProjectConfigObject("testProject1", rootProjectPath, BaseProjectType.ID, source); + NewProjectConfigDto config2 = createProjectConfigObject("innerProject", innerProjectPath, innerProjectType, null); + config2.setAttributes(attributes); + + List configs = new ArrayList<>(2); + configs.add(config1); + configs.add(config2); + + pm.createBatchProjects(configs, false); + + RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath); + FolderEntry rootProjectFolder = rootProject.getBaseFolder(); + RegisteredProject innerProject = projectRegistry.getProject(innerProjectPath); + FolderEntry innerProjectFolder = innerProject.getBaseFolder(); + + + assertNotNull(rootProject); + assertTrue(rootProjectFolder.getVirtualFile().exists()); + assertEquals(rootProjectPath, rootProject.getPath()); + checkChildrenFor(rootProjectFolder, children1); + + assertNotNull(innerProject); + assertTrue(innerProjectFolder.getVirtualFile().exists()); + assertEquals(innerProjectPath, innerProject.getPath()); + assertEquals(innerProjectType, innerProject.getType()); + checkChildrenFor(rootProjectFolder, children2); + } + + @Test + public void testCreateBatchProjectsWithInnerProjectWhenInnerProjectContainsSource() throws Exception { + final String rootProjectPath = "/rootProject"; + final String innerProjectPath = "/rootProject/innerProject"; + final String rootImportType = "rootImportType"; + final String innerImportType = "innerImportType"; + + final String innerProjectType = "pt2"; + + Map> attributes = new HashMap<>(); + attributes.put("pt2-var2", new AttributeValue("test").getList()); + + final String [] paths1 = {"folder1/", "folder1/file1.txt"}; + final List children1 = new ArrayList<>(Arrays.asList(paths1)); + registerImporter(rootImportType, prepareZipArchiveBasedOn(children1)); + + final String [] paths2 = {"folder2/", "folder2/file2.txt"}; + final List children2 = new ArrayList<>(Arrays.asList(paths2)); + registerImporter(innerImportType, prepareZipArchiveBasedOn(children2)); + + final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(rootImportType); + final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", rootProjectPath, BaseProjectType.ID, source1); + + final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(innerImportType); + final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", innerProjectPath, innerProjectType, source2); + config2.setAttributes(attributes); + + final List configs = new ArrayList<>(2); + configs.add(config2); + configs.add(config1); + + pm.createBatchProjects(configs, false); + + RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath); + FolderEntry rootProjectFolder = rootProject.getBaseFolder(); + checkProjectExist(rootProjectPath); + checkChildrenFor(rootProjectFolder, children1); + + RegisteredProject innerProject = projectRegistry.getProject(innerProjectPath); + FolderEntry innerProjectFolder = innerProject.getBaseFolder(); + assertNotNull(innerProject); + assertTrue(innerProjectFolder.getVirtualFile().exists()); + assertEquals(innerProjectPath, innerProject.getPath()); + assertEquals(innerProjectType, innerProject.getType()); + checkChildrenFor(innerProjectFolder, children2); + } + + @Test + public void testCreateBatchProjectsWithMixInnerProjects() throws Exception { // Projects should be sorted by path before creating + final String [] paths = {"/1/z", "/2/z", "/1/d", "/2", "/1", "/1/a"}; + final List projectsPaths = new ArrayList<>(Arrays.asList(paths)); + + final List configs = new ArrayList<>(projectsPaths.size()); + for (String path : projectsPaths) { + configs.add(createProjectConfigObject(path.substring(path.length() - 1, path.length()), path, BaseProjectType.ID, null)); + } + + pm.createBatchProjects(configs, false); + + for (String path : projectsPaths) { + checkProjectExist(path); + } + } + + @Test + public void testCreateBatchProjectsWhenConfigContainsOnlyPath() + throws Exception { // NewProjectConfig object contains only one mandatory Project Path field + + final String projectPath1 = "/testProject1"; + final String projectPath2 = "/testProject2"; + + final NewProjectConfig config1 = createProjectConfigObject(null, projectPath1, null, null); + final NewProjectConfig config2 = createProjectConfigObject(null, projectPath2, null, null); + + final List configs = new ArrayList<>(2); + configs.add(config1); + configs.add(config2); + + pm.createBatchProjects(configs, false); + + checkProjectExist(projectPath1); + checkProjectExist(projectPath2); + assertEquals(2, projectRegistry.getProjects().size()); + } + + @Test + public void shouldThrowBadRequestExceptionAtCreatingBatchProjectsWhenConfigNotContainsPath() + throws Exception { //Path is mandatory field for NewProjectConfig + final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType"); + final NewProjectConfig config = createProjectConfigObject("project", null, BaseProjectType.ID, source); + + final List configs = new ArrayList<>(1); + configs.add(config); + + try { + pm.createBatchProjects(configs, false); + fail("BadRequestException should be thrown : path field is mandatory"); + } catch (BadRequestException e) { + assertEquals(0, projectRegistry.getProjects().size()); + } + } + + @Test + public void shouldThrowConflictExceptionAtCreatingBatchProjectsWhenProjectWithPathAlreadyExist() throws Exception { + final String path = "/somePath"; + final NewProjectConfig config = createProjectConfigObject("project", path, BaseProjectType.ID, null); + + final List configs = new ArrayList<>(1); + configs.add(config); + + pm.createBatchProjects(configs, false); + checkProjectExist(path); + assertEquals(1, projectRegistry.getProjects().size()); + + try { + pm.createBatchProjects(configs, false); + fail("ConflictException should be thrown : Project config with the same path is already exists"); + } catch (ConflictException e) { + assertEquals(1, projectRegistry.getProjects().size()); + } + } + + @Test + public void shouldCreateParentFolderAtCreatingProjectWhenParentDoesNotExist() throws Exception { + final String nonExistentParentPath = "/rootProject"; + final String innerProjectPath = "/rootProject/innerProject"; + + final NewProjectConfig config = createProjectConfigObject(null, innerProjectPath, null, null); + + final List configs = new ArrayList<>(2); + configs.add(config); + + pm.createBatchProjects(configs, false); + + checkProjectExist(nonExistentParentPath); + checkProjectExist(innerProjectPath); + assertEquals(2, projectRegistry.getProjects().size()); + } + + @Test + public void shouldRewriteProjectAtCreatingBatchProjectsWhenProjectAlreadyExist() throws Exception { + final String projectPath = "/testProject"; + final String importType1 = "importType1"; + final String importType2 = "importType2"; + + final String [] paths1 = {"folder1/", "folder1/file1.txt"}; + final List children1 = new ArrayList<>(Arrays.asList(paths1)); + registerImporter(importType1, prepareZipArchiveBasedOn(children1)); + + final String [] paths2 = {"folder2/", "folder2/file2.txt"}; + final List children2 = new ArrayList<>(Arrays.asList(paths2)); + registerImporter(importType2, prepareZipArchiveBasedOn(children2)); + + final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1); + final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath, "blank", source1); + + final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2); + final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath, "blank", source2); + + final List configs = new ArrayList<>(1); + configs.add(config1); + + pm.createBatchProjects(configs, false); + + final FolderEntry projectFolder1 = projectRegistry.getProject(projectPath).getBaseFolder(); + checkProjectExist(projectPath); + checkChildrenFor(projectFolder1, children1); + assertEquals(1, projectRegistry.getProjects().size()); + configs.clear(); + configs.add(config2); + pm.createBatchProjects(configs, true); + final FolderEntry projectFolder2 = projectRegistry.getProject(projectPath).getBaseFolder(); + checkProjectExist(projectPath); + checkChildrenFor(projectFolder2, children2); + assertEquals(1, projectRegistry.getProjects().size()); + assertNull(projectFolder2.getChild("folder1/")); + assertNull(projectFolder2.getChild("folder1/file1.txt")); + } + + @Test + public void shouldSetBlankTypeAtCreatingBatchProjectsWhenConfigContainsUnregisteredProjectType() + throws Exception {// If declared primary PT is not registered, project is created as Blank, with Problem 12 + + final String projectPath = "/testProject"; + final String projectType = "unregisteredProjectType"; + + final NewProjectConfig config = createProjectConfigObject("projectName", projectPath, projectType, null); + + final List configs = new ArrayList<>(1); + configs.add(config); + + pm.createBatchProjects(configs, false); + + final RegisteredProject project = projectRegistry.getProject(projectPath); + final List problems = project.getProblems(); + checkProjectExist(projectPath); + assertNotEquals(projectType, project.getType()); + assertEquals(1, problems.size()); + assertEquals(12, problems.get(0).code); + assertEquals(1, projectRegistry.getProjects().size()); + } + + @Test + public void shouldCreateBatchProjectsWithoutMixinPTWhenThisOneIsUnregistered() + throws Exception {// If declared mixin PT is not registered, project is created w/o it, with Problem 12 + + final String projectPath = "/testProject"; + final String mixinPType = "unregistered"; + + final NewProjectConfig config = createProjectConfigObject("projectName", projectPath, BaseProjectType.ID, null); + config.getMixins().add(mixinPType); + + final List configs = new ArrayList<>(1); + configs.add(config); + + pm.createBatchProjects(configs, false); + + final RegisteredProject project = projectRegistry.getProject(projectPath); + final List problems = project.getProblems(); + checkProjectExist(projectPath); + assertEquals(1, problems.size()); + assertEquals(12, problems.get(0).code); + assertTrue(project.getMixins().isEmpty()); + assertEquals(1, projectRegistry.getProjects().size()); + } + + @Test + public void testCreateProject() throws Exception { Map> attrs = new HashMap<>(); List v = new ArrayList<>(); v.add("meV"); @@ -95,74 +500,85 @@ public void testCreateProject() throws Exception { assertEquals("/createProject", project.getPath()); assertEquals(2, project.getAttributeEntries().size()); assertEquals("meV", project.getAttributeEntries().get("var1").getString()); - } @Test - public void testCreateProjectInvalidAttribute() throws Exception { - - ProjectConfig pc = new NewProjectConfig("/testCreateProjectInvalidAttributes", "pt2", null, "name", "descr", null, null); + public void testCreateProjectWithInvalidAttribute() throws Exception { + // SPECS: + // Project will be created with problem code = 13(Value for required attribute is not initialized) + // when required attribute is not initialized + final String path = "/testCreateProjectInvalidAttributes"; + final String projectType = "pt2"; + final NewProjectConfig config = new NewProjectConfigImpl(path, projectType, null, "name", "descr", null, null, null); - try { - pm.createProject(pc, null); - fail("ProjectTypeConstraintException should be thrown : pt-var2 attribute is mandatory"); - } catch (ServerException e) { - // - } + pm.createProject(config, null); + RegisteredProject project = projectRegistry.getProject(path); + assertNotNull(project); + assertNotNull(pm.getProjectsRoot().getChild(path)); + assertEquals(projectType, project.getType()); + + List problems = project.getProblems(); + assertNotNull(problems); + assertFalse(problems.isEmpty()); + assertEquals(1, problems.size()); + assertEquals(13, problems.get(0).code); } @Test - public void testCreateProjectWithRequiredProvidedAttribute() throws Exception { - - // SPECS: - // If project type has provided required attributes, - // respective CreateProjectHandler MUST be provided - - Map> attributes = new HashMap<>(); + public void testCreateProjectWithRequiredProvidedAttributeWhenGivenProjectTypeHasGenerator() throws Exception { + final String path = "/testCreateProjectWithRequiredProvidedAttribute"; + final String projectTypeId = "pt3"; + final Map> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test").getList()); - ProjectConfig pc = - new NewProjectConfig("/testCreateProjectWithRequiredProvidedAttribute", "pt3", null, "name", "descr", attributes, null); + final ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, null, "name", "descr", attributes, null, null); pm.createProject(pc, null); - RegisteredProject project = projectRegistry.getProject("testCreateProjectWithRequiredProvidedAttribute"); - assertEquals("pt3", project.getType()); + final RegisteredProject project = projectRegistry.getProject(path); + assertEquals(projectTypeId, project.getType()); assertNotNull(project.getBaseFolder().getChild("file1")); assertEquals("pt2-provided1", project.getAttributes().get("pt2-provided1").get(0)); - } @Test - public void testFailCreateProjectWithNoRequiredGenerator() throws Exception { - + public void testCreateProjectWithRequiredProvidedAttributeWhenGivenProjectTypeHasNotGenerator() throws Exception { // SPECS: - // If there are no respective CreateProjectHandler ServerException will be thrown - - ProjectConfig pc = new NewProjectConfig("/testFailCreateProjectWithNoRequiredGenerator", "pt4", null, "name", "descr", null, null); + // Project will be created with problem code = 13 (Value for required attribute is not initialized) + // when project type has provided required attributes + // but have not respective generator(CreateProjectHandler) - try { - pm.createProject(pc, null); - fail("ProjectTypeConstraintException: Value for required attribute is not initialized pt4:pt4-provided1"); - } catch (ServerException e) { - } + final String path = "/testCreateProjectWithRequiredProvidedAttribute"; + final String projectTypeId = "pt4"; + final ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, null, "name", "descr", null, null, null); + pm.createProject(pc, null); + final RegisteredProject project = projectRegistry.getProject(path); + final List children = project.getBaseFolder().getChildren(); + final List problems = project.getProblems(); + assertNotNull(project); + assertNotNull(pm.getProjectsRoot().getChild(path)); + assertEquals(projectTypeId, project.getType()); + assertTrue(children.isEmpty()); + assertTrue(project.getAttributes().isEmpty()); + assertFalse(problems.isEmpty()); + assertEquals(1, problems.size()); + assertEquals(13, problems.get(0).code); } @Test public void testSamePathProjectCreateFailed() throws Exception { - // SPECS: // If there is a project with the same path ConflictException will be thrown on create project - ProjectConfig pc = new NewProjectConfig("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null, null); pm.createProject(pc, null); - pc = new NewProjectConfig("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null); + pc = new NewProjectConfigImpl("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null, null); try { pm.createProject(pc, null); @@ -171,94 +587,109 @@ public void testSamePathProjectCreateFailed() throws Exception { } assertNotNull(projectRegistry.getProject("/testSamePathProjectCreateFailed")); - } @Test public void testInvalidPTProjectCreateFailed() throws Exception { - // SPECS: - // If either primary or some mixin project type is not registered in PT registry - // project creation failed with NotFoundException + // project will be created as project of "blank" type + // with problem code 12(Primary type "someType" is not registered. Base Project Type assigned.) + // when primary project type is not registered in PT registry + final String path = "/testInvalidPTProjectCreateFailed"; + ProjectConfig pc = new NewProjectConfigImpl(path, "invalid", null, "name", "descr", null, null, null); - ProjectConfig pc = new NewProjectConfig("/testInvalidPTProjectCreateFailed", "invalid", null, "name", "descr", null, null); + pm.createProject(pc, null); - try { - pm.createProject(pc, null); - fail("NotFoundException: Project Type not found: invalid"); - } catch (ServerException e) { - } + RegisteredProject project = projectRegistry.getProject(path); + assertNotNull(project); + assertNotNull(pm.getProjectsRoot().getChild(path)); + assertEquals(BaseProjectType.ID, project.getType()); - assertNull(projectRegistry.getProject("/testInvalidPTProjectCreateFailed")); - assertNull(pm.getProjectsRoot().getChild("/testInvalidPTProjectCreateFailed")); - //assertNull(projectRegistry.folder("/testInvalidPTProjectCreateFailed")); + List problems = project.getProblems(); + assertNotNull(problems); + assertFalse(problems.isEmpty()); + assertEquals(1, problems.size()); + assertEquals(12, problems.get(0).code); - // check mixin as well - List ms = new ArrayList<>(); - ms.add("invalid"); + //clean up + project.getBaseFolder().getVirtualFile().delete(); + projectRegistry.removeProjects(path); + assertNull(projectRegistry.getProject(path)); - pc = new NewProjectConfig("/testInvalidPTProjectCreateFailed", "blank", ms, "name", "descr", null, null); - try { - pm.createProject(pc, null); - fail("NotFoundException: Project Type not found: invalid"); - } catch (ServerException e) { - } + // SPECS: + // project will be created without mixin project type and + // with problem code 12(Project type "someType" is not registered. Skipped.) + // when mixin project type is not registered in PT registry + List ms = new ArrayList<>(); + ms.add("invalid"); + pc = new NewProjectConfigImpl(path, "blank", ms, "name", "descr", null, null, null); + pm.createProject(pc, null); + project = projectRegistry.getProject(path); + assertNotNull(project); + assertNotNull(pm.getProjectsRoot().getChild(path)); + assertTrue(project.getMixins().isEmpty()); + + problems = project.getProblems(); + assertNotNull(problems); + assertFalse(problems.isEmpty()); + assertEquals(1, problems.size()); + assertEquals(12, problems.get(0).code); } @Test public void testConflictAttributesProjectCreateFailed() throws Exception { - // SPECS: - // If there are attributes with the same name in primary and mixin PT or between mixins - // Project creation failed with ProjectTypeConstraintException + // project will be created with problem code 13(Attribute name conflict) + // when there are attributes with the same name in primary and mixin PT or between mixins + final String path = "/testConflictAttributesProjectCreateFailed"; + final String projectTypeId = "pt2"; + final String mixin = "m2"; + final List ms = new ArrayList<>(1); + ms.add(mixin); - List ms = new ArrayList<>(); - ms.add("m2"); - - ProjectConfig pc = new NewProjectConfig("/testConflictAttributesProjectCreateFailed", "pt2", ms, "name", "descr", null, null); - try { - pm.createProject(pc, null); - fail("ProjectTypeConstraintException: Attribute name conflict. Duplicated attributes detected /testConflictAttributesProjectCreateFailed Attribute pt2-const1 declared in m2 already declared in pt2"); - } catch (ServerException e) { - } + ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, ms, "name", "descr", null, null, null); + pm.createProject(pc, null); - //assertNull(projectRegistry.folder("/testConflictAttributesProjectCreateFailed")); + final RegisteredProject project = projectRegistry.getProject(path); + assertNotNull(project); + assertNotNull(pm.getProjectsRoot().getChild(path)); - assertNull(pm.getProjectsRoot().getChild("/testConflictAttributesProjectCreateFailed")); + final List mixins = project.getMixins(); + assertFalse(mixins.isEmpty()); + assertEquals(mixin, mixins.get(0)); + final List problems = project.getProblems(); + assertNotNull(problems); + assertFalse(problems.isEmpty()); + assertEquals(13, problems.get(0).code); } @Test public void testInvalidConfigProjectCreateFailed() throws Exception { - // SPECS: // If project path is not defined // Project creation failed with ConflictException - ProjectConfig pc = new NewProjectConfig(null, "pt2", null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl(null, "pt2", null, "name", "descr", null, null, null); try { pm.createProject(pc, null); fail("ConflictException: Path for new project should be defined "); } catch (ConflictException e) { } - - } @Test public void testCreateInnerProject() throws Exception { - - - ProjectConfig pc = new NewProjectConfig("/testCreateInnerProject", BaseProjectType.ID, null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl("/testCreateInnerProject", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); - pc = new NewProjectConfig("/testCreateInnerProject/inner", BaseProjectType.ID, null, "name", "descr", null, null); + pc = new NewProjectConfigImpl("/testCreateInnerProject/inner", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); assertNotNull(projectRegistry.getProject("/testCreateInnerProject/inner")); @@ -267,13 +698,12 @@ public void testCreateInnerProject() throws Exception { // If there are no parent folder it will be created - pc = new NewProjectConfig("/nothing/inner", BaseProjectType.ID, null, "name", "descr", null, null); + pc = new NewProjectConfigImpl("/nothing/inner", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); assertNotNull(projectRegistry.getProject("/nothing/inner")); assertNotNull(projectRegistry.getProject("/nothing")); assertNotNull(pm.getProjectsRoot().getChildFolder("/nothing")); - } @@ -281,14 +711,14 @@ public void testCreateInnerProject() throws Exception { public void testUpdateProjectWithPersistedAttributes() throws Exception { Map> attributes = new HashMap<>(); - ProjectConfig pc = new NewProjectConfig("/testUpdateProject", BaseProjectType.ID, null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProject", BaseProjectType.ID, null, "name", "descr", null, null, null); RegisteredProject p = pm.createProject(pc, null); assertEquals(BaseProjectType.ID, p.getType()); assertEquals("name", p.getName()); attributes.put("pt2-var2", new AttributeValue("updated").getList()); - ProjectConfig pc1 = new NewProjectConfig("/testUpdateProject", "pt2", null, "updatedName", "descr", attributes, null); + ProjectConfig pc1 = new NewProjectConfigImpl("/testUpdateProject", "pt2", null, "updatedName", "descr", attributes, null, null); p = pm.updateProject(pc1); @@ -301,38 +731,30 @@ public void testUpdateProjectWithPersistedAttributes() throws Exception { @Test public void testUpdateProjectWithProvidedAttributes() throws Exception { + // SPECS: Project should be updated with problem code = 13 when value for required attribute is not initialized Map> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test").getList()); - ProjectConfig pc = new NewProjectConfig("/testUpdateProject", "pt2", null, "name", "descr", attributes, null); - RegisteredProject p = pm.createProject(pc, null); - - // SPECS: - // If project type is updated with one required provided attributes - // those attributes should be provided before update - - pc = new NewProjectConfig("/testUpdateProject", "pt3", null, "updatedName", "descr", attributes, null); - - try { - pm.updateProject(pc); - fail("ProjectTypeConstraintException: Value for required attribute is not initialized pt3:pt2-provided1 "); - } catch (ServerException e) { - } + ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProject", "pt2", null, "name", "descr", attributes, null, null); + pm.createProject(pc, null); + pc = new NewProjectConfigImpl("/testUpdateProject", "pt3", null, "updatedName", "descr", attributes, null, null); - p.getBaseFolder().createFolder("file1"); - p = pm.updateProject(pc); - assertEquals(new AttributeValue("pt2-provided1"), p.getAttributeEntries().get("pt2-provided1")); + RegisteredProject project = pm.updateProject(pc); + final List problems = project.getProblems(); + assertNotNull(problems); + assertFalse(problems.isEmpty()); + assertEquals(1, problems.size()); + assertEquals(13, problems.get(0).code); } @Test public void testUpdateProjectOnRawFolder() throws Exception { - - ProjectConfig pc = new NewProjectConfig("/testUpdateProjectOnRawFolder", BaseProjectType.ID, null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProjectOnRawFolder", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); String folderPath = "/testUpdateProjectOnRawFolder/folder"; pm.getProjectsRoot().createFolder(folderPath); @@ -340,18 +762,15 @@ public void testUpdateProjectOnRawFolder() throws Exception { // SPECS: // If update is called on raw folder new project should be created - pc = new NewProjectConfig(folderPath, BaseProjectType.ID, null, "raw", "descr", null, null); + pc = new NewProjectConfigImpl(folderPath, BaseProjectType.ID, null, "raw", "descr", null, null, null); pm.updateProject(pc); assertEquals(BaseProjectType.ID, pm.getProject(folderPath).getType()); - - } @Test public void testInvalidUpdateConfig() throws Exception { - - ProjectConfig pc = new NewProjectConfig(null, BaseProjectType.ID, null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl(null, BaseProjectType.ID, null, "name", "descr", null, null, null); try { pm.updateProject(pc); @@ -359,7 +778,7 @@ public void testInvalidUpdateConfig() throws Exception { } catch (ConflictException e) { } - pc = new NewProjectConfig("/nothing", BaseProjectType.ID, null, "name", "descr", null, null); + pc = new NewProjectConfigImpl("/nothing", BaseProjectType.ID, null, "name", "descr", null, null, null); try { pm.updateProject(pc); fail("NotFoundException: Project '/nothing' doesn't exist."); @@ -371,9 +790,9 @@ public void testInvalidUpdateConfig() throws Exception { @Test public void testDeleteProject() throws Exception { - ProjectConfig pc = new NewProjectConfig("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); - pc = new NewProjectConfig("/testDeleteProject/inner", BaseProjectType.ID, null, "name", "descr", null, null); + pc = new NewProjectConfigImpl("/testDeleteProject/inner", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); assertNotNull(projectRegistry.getProject("/testDeleteProject/inner")); @@ -384,13 +803,11 @@ public void testDeleteProject() throws Exception { assertNull(projectRegistry.getProject("/testDeleteProject")); assertNull(pm.getProjectsRoot().getChild("/testDeleteProject/inner")); //assertNull(projectRegistry.folder("/testDeleteProject/inner")); - } @Test public void testDeleteProjectEvent() throws Exception { - - ProjectConfig pc = new NewProjectConfig("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null); + ProjectConfig pc = new NewProjectConfigImpl("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); String[] deletedPath = new String[1]; @@ -401,13 +818,11 @@ public void testDeleteProjectEvent() throws Exception { pm.delete("/testDeleteProject"); assertEquals("/testDeleteProject", deletedPath[0]); - } @Test public void testImportProject() throws Exception { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); String fileContent = "to be or not to be"; ZipOutputStream zipOut = new ZipOutputStream(bout); @@ -433,7 +848,6 @@ public void testImportProject() throws Exception { assertNotNull(project.getBaseFolder().getChild("file1")); assertEquals(fileContent, project.getBaseFolder().getChild("file1").getVirtualFile().getContentAsString()); - } @Test @@ -467,11 +881,11 @@ public void testImportProjectWithoutImporterFailed() throws Exception { @Test public void testProvidedAttributesNotSerialized() throws Exception { - Map> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test2").getList()); attributes.put("pt2-var1", new AttributeValue("test1").getList()); - ProjectConfig pc = new NewProjectConfig("/testProvidedAttributesNotSerialized", "pt3", null, "name", "descr", attributes, null); + ProjectConfig pc = + new NewProjectConfigImpl("/testProvidedAttributesNotSerialized", "pt3", null, "name", "descr", attributes, null, null); pm.createProject(pc, null); @@ -493,10 +907,9 @@ public void testProvidedAttributesNotSerialized() throws Exception { @Test public void testSettableValueProvider() throws Exception { - assertTrue(((Variable)projectTypeRegistry.getProjectType("settableVPPT").getAttribute("my")).isValueProvided()); - ProjectConfig pc = new NewProjectConfig("/testSettableValueProvider", "settableVPPT", null, "", "", new HashMap<>(), null); + ProjectConfig pc = new NewProjectConfigImpl("/testSettableValueProvider", "settableVPPT", null, "", "", new HashMap<>(), null, null); pm.createProject(pc, null); @@ -507,18 +920,64 @@ public void testSettableValueProvider() throws Exception { Map> attributes = new HashMap<>(); attributes.put("my", new AttributeValue("set").getList()); - pc = new NewProjectConfig("/testSettableValueProvider", "settableVPPT", null, "", "", attributes, null); + pc = new NewProjectConfigImpl("/testSettableValueProvider", "settableVPPT", null, "", "", attributes, null, null); pm.updateProject(pc); project = pm.getProject("/testSettableValueProvider"); assertEquals("set", project.getAttributes().get("my").get(0)); - } /* ---------------------------------- */ /* private */ /* ---------------------------------- */ + private void checkProjectExist(String projectPath) { + RegisteredProject project = projectRegistry.getProject(projectPath); + FolderEntry projectFolder = project.getBaseFolder(); + assertNotNull(project); + assertTrue(projectFolder.getVirtualFile().exists()); + assertEquals(projectPath, project.getPath()); + assertEquals(BaseProjectType.ID, project.getType()); + } + + private void checkChildrenFor(FolderEntry projectFolder, List children) throws ServerException, ForbiddenException { + for (String path : children) { + assertNotNull(projectFolder.getChild(path)); + if (path.contains("file")) { + String fileContent = projectFolder.getChild(path).getVirtualFile().getContentAsString(); + assertEquals(FILE_CONTENT, fileContent); + } + } + } + + private InputStream prepareZipArchiveBasedOn(List paths) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ZipOutputStream zipOut = new ZipOutputStream(bout); + + for (String path : paths) { + zipOut.putNextEntry(new ZipEntry(path)); + + if (path.contains("file")) { + zipOut.write(FILE_CONTENT.getBytes()); + } + } + zipOut.close(); + return new ByteArrayInputStream(bout.toByteArray()); + } + + private NewProjectConfigDto createProjectConfigObject(String projectName, + String projectPath, + String projectType, + SourceStorageDto sourceStorage) { + return DtoFactory.newDto(NewProjectConfigDto.class) + .withPath(projectPath) + .withName(projectName) + .withType(projectType) + .withDescription("description") + .withSource(sourceStorage) + .withAttributes(new HashMap<>()); + } + private void registerImporter(String importType, InputStream zip) throws Exception { final ValueHolder folderHolder = new ValueHolder<>(); importerRegistry.register(new ProjectImporter() { @@ -570,7 +1029,6 @@ public void onCreateProject(Path projectPath, Map attrib throws ForbiddenException, ConflictException, ServerException { FolderEntry baseFolder = new FolderEntry(vfsProvider.getVirtualFileSystem().getRoot().createFolder(projectPath.toString())); baseFolder.createFolder("file1"); - } @Override @@ -578,5 +1036,4 @@ public String getProjectType() { return "pt3"; } } - } diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java index 37e9da38d2a..3cc0599621d 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.che.api.project.server; +import com.google.common.io.ByteStreams; + import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; @@ -29,6 +31,7 @@ import org.eclipse.che.api.project.server.importer.ProjectImporter; import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry; import org.eclipse.che.api.project.server.type.AttributeValue; +import org.eclipse.che.api.project.server.type.ProjectTypeConstraintException; import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.project.server.type.ReadonlyValueProvider; @@ -52,7 +55,6 @@ import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; -import org.eclipse.che.commons.json.JsonHelper; import org.eclipse.che.commons.lang.IoUtil; import org.eclipse.che.commons.lang.ws.rs.ExtMediaType; import org.eclipse.che.commons.subject.SubjectImpl; @@ -81,6 +83,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.charset.Charset; @@ -106,6 +109,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import static java.lang.String.format; import static java.util.Collections.singletonList; import static javax.ws.rs.HttpMethod.DELETE; import static javax.ws.rs.HttpMethod.GET; @@ -115,6 +119,7 @@ import static javax.ws.rs.core.MediaType.TEXT_PLAIN; import static org.eclipse.che.commons.lang.ws.rs.ExtMediaType.APPLICATION_ZIP; import static org.everrest.core.ApplicationContext.anApplicationContext; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; @@ -414,24 +419,9 @@ public void testGetProjectInvalidPath() throws Exception { @Test public void testCreateProject() throws Exception { - - - - phRegistry.register(new CreateProjectHandler() { - @Override - public void onCreateProject(Path projectPath, Map attributes, Map options) - throws ForbiddenException, ConflictException, ServerException { - FolderEntry projectFolder = new FolderEntry(vfsProvider.getVirtualFileSystem().getRoot().createFolder("new_project")); - projectFolder.createFolder("a"); - projectFolder.createFolder("b"); - projectFolder.createFile("test.txt", "test".getBytes(Charset.defaultCharset())); - } - - @Override - public String getProjectType() { - return "testCreateProject"; - } - }); + final String projectName = "new_project"; + final String projectType = "testCreateProject"; + phRegistry.register(createProjectHandlerFor(projectName, projectType)); Map> headers = new HashMap<>(); headers.put("Content-Type", singletonList(APPLICATION_JSON)); @@ -450,9 +440,9 @@ public String getProjectType() { final ProjectConfigDto newProjectConfig = DtoFactory.getInstance().createDto(ProjectConfigDto.class) .withPath("/new_project") - .withName("new_project") + .withName(projectName) .withDescription("new project") - .withType("testCreateProject") + .withType(projectType) .withAttributes(attributeValues) .withSource(DtoFactory.getInstance().createDto(SourceStorageDto.class)); projects.add(newProjectConfig); @@ -467,11 +457,11 @@ public String getProjectType() { assertEquals(response.getStatus(), 200, "Error: " + response.getEntity()); ProjectConfigDto result = (ProjectConfigDto)response.getEntity(); assertNotNull(result); - assertEquals(result.getName(), "new_project"); + assertEquals(result.getName(), projectName); assertEquals(result.getPath(), "/new_project"); assertEquals(result.getDescription(), newProjectConfig.getDescription()); assertEquals(result.getType(), newProjectConfig.getType()); - assertEquals(result.getType(), "testCreateProject"); + assertEquals(result.getType(), projectType); Map> attributes = result.getAttributes(); assertNotNull(attributes); assertEquals(attributes.size(), 1); @@ -492,11 +482,63 @@ public String getProjectType() { assertNotNull(project.getBaseFolder().getChild("a")); assertNotNull(project.getBaseFolder().getChild("b")); assertNotNull(project.getBaseFolder().getChild("test.txt")); + } + @Test + public void testCreateBatchProjects() throws Exception { + //prepare first project + final String projectName1 = "testProject1"; + final String projectTypeId1 = "testProjectType1"; + final String projectPath1 = "/testProject1"; + + createTestProjectType(projectTypeId1); + phRegistry.register(createProjectHandlerFor(projectName1, projectTypeId1)); + + //prepare inner project + final String innerProjectName = "innerProject"; + final String innerProjectTypeId = "testProjectType2"; + final String innerProjectPath = "/testProject1/innerProject"; + + createTestProjectType(innerProjectTypeId); + phRegistry.register(createProjectHandlerFor(innerProjectName, innerProjectTypeId)); + + //prepare project to import + final String importProjectName = "testImportProject"; + final String importProjectTypeId = "testImportProjectType"; + final String importProjectPath = "/testImportProject"; + final String importType = "importType"; + final String [] paths = {"a", "b", "test.txt"}; + + final List children = new ArrayList<>(Arrays.asList(paths)); + registerImporter(importType, prepareZipArchiveBasedOn(children)); + createTestProjectType(importProjectTypeId); - } + Map> headers = new HashMap<>(); + headers.put("Content-Type", singletonList(APPLICATION_JSON)); + + try (InputStream content = getClass().getResourceAsStream("batchNewProjectConfigs.json")) { + ContainerResponse response = launcher.service(POST, + "http://localhost:8080/api/project/batch", + "http://localhost:8080/api", + headers, + ByteStreams.toByteArray(content), null); + + assertEquals(response.getStatus(), 200, "Error: " + response.getEntity()); + + final List result = (List)response.getEntity(); + assertNotNull(result); + assertEquals(result.size(), 3); + final ProjectConfigDto importProjectConfig = result.get(0); + checkProjectIsCreated(importProjectName, importProjectPath, importProjectTypeId, importProjectConfig); + final ProjectConfigDto config1 = result.get(1); + checkProjectIsCreated(projectName1, projectPath1, projectTypeId1, config1); + + final ProjectConfigDto innerProjectConfig = result.get(2); + checkProjectIsCreated(innerProjectName, innerProjectPath, innerProjectTypeId, innerProjectConfig); + } + } @Test public void testUpdateProject() throws Exception { @@ -636,10 +678,9 @@ public List getValues(String attributeName) throws ValueStorageException ptRegistry.registerProjectType(pt); - ContainerResponse response = - launcher.service(GET, String.format("http://localhost:8080/api/project/estimate/%s?type=%s", - "testEstimateProjectGood", "testEstimateProjectPT"), - "http://localhost:8080/api", null, null, null); + ContainerResponse response = launcher.service(GET, format("http://localhost:8080/api/project/estimate/%s?type=%s", + "testEstimateProjectGood", "testEstimateProjectPT"), + "http://localhost:8080/api", null, null, null); assertEquals(response.getStatus(), 200, "Error: " + response.getEntity()); //noinspection unchecked SourceEstimation result = (SourceEstimation)response.getEntity(); @@ -648,14 +689,15 @@ public List getValues(String attributeName) throws ValueStorageException assertEquals(result.getAttributes().get("calculated_attribute").get(0), "checked"); // if project not matched - response = launcher.service(GET, String.format("http://localhost:8080/api/project/estimate/%s?type=%s", - "testEstimateProjectBad", "testEstimateProjectPT"), + response = launcher.service(GET, format("http://localhost:8080/api/project/estimate/%s?type=%s", + "testEstimateProjectBad", "testEstimateProjectPT"), "http://localhost:8080/api", null, null, null); - assertEquals(response.getStatus(), 409, "Error: " + response.getEntity()); - String msg = JsonHelper.parseJson(response.getEntity().toString()).getElement("message").getStringValue(); - assertEquals(errMessage, msg); - + assertEquals(response.getStatus(), 200, "Error: " + response.getEntity()); + //noinspection unchecked + result = (SourceEstimation)response.getEntity(); + assertFalse(result.isMatched()); + assertEquals(result.getAttributes().size(), 0); } @@ -697,8 +739,8 @@ public List getValues(String attributeName) throws ValueStorageException ptRegistry.registerProjectType(pt); ContainerResponse response = - launcher.service(GET, String.format("http://localhost:8080/api/project/resolve/%s", - "testEstimateProjectGood"), + launcher.service(GET, format("http://localhost:8080/api/project/resolve/%s", + "testEstimateProjectGood"), "http://localhost:8080/api", null, null, null); assertEquals(response.getStatus(), 200, "Error: " + response.getEntity()); List result = (List) response.getEntity(); @@ -746,7 +788,7 @@ public void testImportProject() throws Exception { " \"type\": \"%s\"\n" + "}"; - byte[] b = String.format(json, importType).getBytes(Charset.defaultCharset()); + byte[] b = format(json, importType).getBytes(Charset.defaultCharset()); ContainerResponse response = launcher.service(POST, "http://localhost:8080/api/project/import/new_project", "http://localhost:8080/api", headers, b, null); @@ -878,7 +920,7 @@ public void testCreateFolder() throws Exception { public void testCreateFolderInRoot() throws Exception { String folder = "my_folder"; ContainerResponse response = launcher.service(POST, - String.format("http://localhost:8080/api/project/folder/%s", folder), + format("http://localhost:8080/api/project/folder/%s", folder), "http://localhost:8080/api", null, null, null); assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); ItemReference fileItem = (ItemReference)response.getEntity(); @@ -887,7 +929,7 @@ public void testCreateFolderInRoot() throws Exception { assertEquals(fileItem.getPath(), "/" + folder); validateFolderLinks(fileItem); assertEquals(response.getHttpHeaders().getFirst("Location"), - URI.create(String.format("http://localhost:8080/api/project/children/%s", folder))); + URI.create(format("http://localhost:8080/api/project/children/%s", folder))); } @Test @@ -1052,7 +1094,8 @@ public void testCopyFileWithRenameAndOverwrite() throws Exception { String overwrittenContent = "that is the question"; ((FolderEntry)myProject.getBaseFolder().getChild("a/b")).createFile(originFileName, originContent.getBytes(Charset.defaultCharset())); - ((FolderEntry)myProject.getBaseFolder().getChild("a/b/c")).createFile(destinationFileName, overwrittenContent.getBytes(Charset.defaultCharset())); + ((FolderEntry)myProject.getBaseFolder().getChild("a/b/c")).createFile(destinationFileName, + overwrittenContent.getBytes(Charset.defaultCharset())); Map> headers = new HashMap<>(); headers.put(CONTENT_TYPE, singletonList(APPLICATION_JSON)); @@ -1127,9 +1170,9 @@ public void testCopyFolderWithRename() throws Exception { assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), URI.create( - String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); + format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); assertNotNull(myProject.getBaseFolder().getChild("a/b/test.txt")); - assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder))); + assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder))); } @Test @@ -1165,11 +1208,11 @@ public void testCopyFolderWithRenameAndOverwrite() throws Exception { assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), URI.create( - String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); + format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); assertNotNull(myProject.getBaseFolder().getChild("a/b/test.txt")); - assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder))); + assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder))); assertEquals(myProject.getBaseFolder().getChild("a/b/test.txt").getName(), - myProject.getBaseFolder().getChild(String.format("a/b/c/%s/%s", renamedFolder, originFileName)).getName()); + myProject.getBaseFolder().getChild(format("a/b/c/%s/%s", renamedFolder, originFileName)).getName()); } @Test @@ -1210,8 +1253,8 @@ public void testMoveFileWithRename() throws Exception { assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), URI.create( - String.format("http://localhost:8080/api/project/file/my_project/a/b/c/%s", destinationName))); - VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(String.format("a/b/c/%s", destinationName)); + format("http://localhost:8080/api/project/file/my_project/a/b/c/%s", destinationName))); + VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(format("a/b/c/%s", destinationName)); assertNotNull(theTargetFile); // new } @@ -1238,8 +1281,8 @@ public void testRenameFile() throws Exception { assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), URI.create( - String.format("http://localhost:8080/api/project/file/my_project/a/b/%s", destinationName))); - VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(String.format("a/b/%s", destinationName)); + format("http://localhost:8080/api/project/file/my_project/a/b/%s", destinationName))); + VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(format("a/b/%s", destinationName)); assertNotNull(theTargetFile); // new } @@ -1333,8 +1376,8 @@ public void testMoveFolderWithRename() throws Exception { assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), URI.create( - String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); - assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder))); + format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); + assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder))); } @Test @@ -1360,8 +1403,8 @@ public void testRenameFolder() throws Exception { assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), URI.create( - String.format("http://localhost:8080/api/project/children/my_project/a/%s", renamedFolder))); - assertNotNull(myProject.getBaseFolder().getChild(String.format("a/%s/test.txt", renamedFolder))); + format("http://localhost:8080/api/project/children/my_project/a/%s", renamedFolder))); + assertNotNull(myProject.getBaseFolder().getChild(format("a/%s/test.txt", renamedFolder))); } @Test @@ -1397,8 +1440,8 @@ public void testMoveFolderWithRenameAndOverwrite() throws Exception { assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), URI.create( - String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); - assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder))); + format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder))); + assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder))); } @Test @@ -1416,7 +1459,7 @@ public void testImportZip() throws Exception { Map> headers = new HashMap<>(); headers.put(CONTENT_TYPE, singletonList(ExtMediaType.APPLICATION_ZIP)); ContainerResponse response = launcher.service(POST, - String.format("http://localhost:8080/api/project/import/my_project/a/b"), + format("http://localhost:8080/api/project/import/my_project/a/b"), "http://localhost:8080/api", headers, zip, null); assertEquals(response.getStatus(), 201, "Error: " + response.getEntity()); assertEquals(response.getHttpHeaders().getFirst("Location"), @@ -1520,8 +1563,8 @@ public void testGetItemWithoutParentProject() throws Exception { @Test public void testGetMissingItem() throws Exception { ContainerResponse response = launcher.service(GET, - "http://localhost:8080/api/project/item/some_missing_project/a/b", - "http://localhost:8080/api", null, null, null); + "http://localhost:8080/api/project/item/some_missing_project/a/b", + "http://localhost:8080/api", null, null, null); assertEquals(response.getStatus(), 404, "Error: " + response.getEntity()); } @@ -1731,8 +1774,10 @@ public void testSearchParticularSequenceWords() throws Exception { "to" + URL_ENCODED_SPACE + "be" + URL_ENCODED_QUOTES; RegisteredProject myProject = pm.getProject("my_project"); - myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset())); - myProject.getBaseFolder().createFolder("a/b").createFile("test.txt", "Pay attention! To be or to be that is the question".getBytes(Charset.defaultCharset())); + myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes( + Charset.defaultCharset())); + myProject.getBaseFolder().createFolder("a/b").createFile("test.txt", "Pay attention! To be or to be that is the question".getBytes( + Charset.defaultCharset())); myProject.getBaseFolder().createFolder("c").createFile("_test", "Pay attention! To be or to not be that is the question".getBytes(Charset.defaultCharset())); ContainerResponse response = @@ -1755,11 +1800,14 @@ public void testSearchParticularSequenceWordsWithAnyEnding() throws Exception { "the" + URL_ENCODED_QUOTES + URL_ENCODED_SPACE + AND_OPERATOR + URL_ENCODED_SPACE + "question" + URL_ENCODED_ASTERISK; RegisteredProject myProject = pm.getProject("my_project"); - myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset())); + myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes( + Charset.defaultCharset())); myProject.getBaseFolder().createFolder("a/b") - .createFile("containsSearchTextAlso.txt", "Pay attention! To be or not to be that is the questionS".getBytes(Charset.defaultCharset())); + .createFile("containsSearchTextAlso.txt", + "Pay attention! To be or not to be that is the questionS".getBytes(Charset.defaultCharset())); myProject.getBaseFolder().createFolder("c") - .createFile("notContainsSearchText", "Pay attention! To be or to not be that is the questEon".getBytes(Charset.defaultCharset())); + .createFile("notContainsSearchText", + "Pay attention! To be or to not be that is the questEon".getBytes(Charset.defaultCharset())); ContainerResponse response = launcher.service(GET,"http://localhost:8080/api/project/search/my_project" + queryToSearch, @@ -1780,7 +1828,8 @@ public void testSearchWordWithAnyEnding() throws Exception { String queryToSearch = "?text=" + "question" + URL_ENCODED_ASTERISK; RegisteredProject myProject = pm.getProject("my_project"); - myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset())); + myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes( + Charset.defaultCharset())); myProject.getBaseFolder().createFolder("a/b") .createFile("containsSearchTextAlso.txt", "Pay attention! To be or not to be that is the questionS".getBytes(Charset.defaultCharset())); myProject.getBaseFolder().createFolder("c") @@ -1806,10 +1855,12 @@ public void testSearchTextWhenExcludeSomeText() throws Exception { "question" + URL_ENCODED_SPACE + NOT_OPERATOR + URL_ENCODED_SPACE + URL_ENCODED_QUOTES + "attention!" + URL_ENCODED_QUOTES; RegisteredProject myProject = pm.getProject("my_project"); - myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset())); + myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes( + Charset.defaultCharset())); myProject.getBaseFolder().createFolder("b") .createFile("notContainsSearchText", "Pay attention! To be or not to be that is the question".getBytes(Charset.defaultCharset())); - myProject.getBaseFolder().createFolder("c").createFile("alsoNotContainsSearchText", "To be or to not be that is the ...".getBytes(Charset.defaultCharset())); + myProject.getBaseFolder().createFolder("c").createFile("alsoNotContainsSearchText", + "To be or to not be that is the ...".getBytes(Charset.defaultCharset())); ContainerResponse response = launcher.service(GET, "http://localhost:8080/api/project/search/my_project" + queryToSearch, @@ -1838,7 +1889,8 @@ public void testSearchTextWithEscapedCharachters() throws Exception { URL_ENCODED_BACKSLASH + ':' + "projectName=test"; RegisteredProject myProject = pm.getProject("my_project"); myProject.getBaseFolder().createFolder("x/y") - .createFile("test.txt", "http://localhost:8080/ide/dev6?action=createProject:projectName=test".getBytes(Charset.defaultCharset())); + .createFile("test.txt", + "http://localhost:8080/ide/dev6?action=createProject:projectName=test".getBytes(Charset.defaultCharset())); ContainerResponse response = launcher.service(GET, "http://localhost:8080/api/project/search/my_project" + queryToSearch, "http://localhost:8080/api", null, null, null); @@ -1864,11 +1916,11 @@ public void testSearchByNameAndText() throws Exception { assertEquals(response.getStatus(), 200, "Error: " + response.getEntity()); List result = (List)response.getEntity(); assertEquals(result.size(), 2); - assertEqualsNoOrder(new Object[] { + assertEqualsNoOrder(new Object[]{ result.get(0).getPath(), result.get(1).getPath() }, - new Object[] { + new Object[]{ "/my_project/a/b/test.txt", "/my_project/x/y/test.txt" }); @@ -1895,12 +1947,12 @@ private void validateFileLinks(ItemReference item) { Link link = item.getLink("delete"); assertNotNull(link); assertEquals(link.getMethod(), DELETE); - assertEquals(link.getHref(), "http://localhost:8080/api/project" + item.getPath()); + assertEquals(link.getHref(), "http://localhost:8080/api/project" + item.getPath()); link = item.getLink("update content"); assertNotNull(link); assertEquals(link.getMethod(), PUT); assertEquals(link.getConsumes(), "*/*"); - assertEquals(link.getHref(), "http://localhost:8080/api/project" + "/file" + item.getPath()); + assertEquals(link.getHref(), "http://localhost:8080/api/project" + "/file" + item.getPath()); } private void validateFolderLinks(ItemReference item) { @@ -1974,6 +2026,77 @@ private void validateProjectLinks(ProjectConfigDto project) { } } + private InputStream prepareZipArchiveBasedOn(List paths) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ZipOutputStream zipOut = new ZipOutputStream(bout); + + for (String path : paths) { + zipOut.putNextEntry(new ZipEntry(path)); + } + zipOut.close(); + return new ByteArrayInputStream(bout.toByteArray()); + } + + private void checkProjectIsCreated(String expectedName, String expectedPath, String expectedType, ProjectConfigDto actualConfig) + throws ServerException, NotFoundException { + final String projectDescription = "someDescription"; + assertEquals(actualConfig.getName(), expectedName); + assertEquals(actualConfig.getPath(), expectedPath); + assertEquals(actualConfig.getDescription(), projectDescription); + assertEquals(actualConfig.getType(), expectedType); + + final String expectedAttribute = "new_test_attribute"; + final String expectedAttributeValue = "some_attribute_value"; + final Map> attributes = actualConfig.getAttributes(); + assertNotNull(attributes); + assertEquals(attributes.size(), 1); + assertEquals(attributes.get(expectedAttribute), singletonList(expectedAttributeValue)); + + validateProjectLinks(actualConfig); + + RegisteredProject project = pm.getProject(expectedPath); + assertNotNull(project); + assertEquals(project.getDescription(), projectDescription); + assertEquals(project.getProjectType().getId(), expectedType); + String attributeVal = project.getAttributeEntries().get(expectedAttribute).getString(); + assertNotNull(attributeVal); + assertEquals(attributeVal, expectedAttributeValue); + + assertNotNull(project.getBaseFolder().getChild("a")); + assertNotNull(project.getBaseFolder().getChild("b")); + assertNotNull(project.getBaseFolder().getChild("test.txt")); + } + + private void createTestProjectType(final String projectTypeId) throws ProjectTypeConstraintException { + final ProjectTypeDef pt = new ProjectTypeDef(projectTypeId, "my project type", true, false) { + { + addConstantDefinition("new_test_attribute", "attr description", "some_attribute_value"); + } + }; + ptRegistry.registerProjectType(pt); + } + + private CreateProjectHandler createProjectHandlerFor(final String projectName, final String projectTypeId) { + return new CreateProjectHandler() { + @Override + public void onCreateProject(Path projectPath, Map attributes, Map options) + throws ForbiddenException, ConflictException, ServerException { + final String pathToProject = projectPath.toString(); + final String pathToParent = pathToProject.substring(0, pathToProject.lastIndexOf("/")); + final FolderEntry projectFolder = new FolderEntry( + vfsProvider.getVirtualFileSystem().getRoot().getChild(Path.of(pathToParent)).createFolder(projectName)); + projectFolder.createFolder("a"); + projectFolder.createFolder("b"); + projectFolder.createFile("test.txt", "test".getBytes(Charset.defaultCharset())); + } + + @Override + public String getProjectType() { + return projectTypeId; + } + }; + } + private class LocalProjectType extends ProjectTypeDef { private LocalProjectType(String typeId, String typeName) { super(typeId, typeName, true, false); diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java index 45d969f6495..b9e2e1ca1fe 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/WsAgentTestBase.java @@ -10,15 +10,11 @@ *******************************************************************************/ package org.eclipse.che.api.project.server; -import org.eclipse.che.api.core.ConflictException; -import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.notification.EventService; -import org.eclipse.che.api.project.server.handlers.CreateProjectHandler; import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry; import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry; -import org.eclipse.che.api.project.server.type.AttributeValue; import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; import org.eclipse.che.api.project.server.type.ReadonlyValueProvider; @@ -26,7 +22,6 @@ import org.eclipse.che.api.project.server.type.ValueProvider; import org.eclipse.che.api.project.server.type.ValueProviderFactory; import org.eclipse.che.api.project.server.type.ValueStorageException; -import org.eclipse.che.api.vfs.Path; import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler; import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher; import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler; diff --git a/wsagent/che-core-api-project/src/test/resources/org/eclipse/che/api/project/server/batchNewProjectConfigs.json b/wsagent/che-core-api-project/src/test/resources/org/eclipse/che/api/project/server/batchNewProjectConfigs.json new file mode 100644 index 00000000000..ace7d2e43d1 --- /dev/null +++ b/wsagent/che-core-api-project/src/test/resources/org/eclipse/che/api/project/server/batchNewProjectConfigs.json @@ -0,0 +1,68 @@ +[ + { + "name": "innerProject", + "displayName": "innerProject", + "path": "/testProject1/innerProject", + "description": "someDescription", + "type": "testProjectType2", + "mixins": [], + "attributes": { + "new_test_attribute": [ + "some_attribute_value" + ] + }, + "modules": [], + "problems": [], + "source": { + "type": "", + "location": "", + "parameters": {} + }, + "commands": [], + "links": [] + }, + { + "name": "testProject1", + "displayName": "testProject1", + "path": "/testProject1", + "description": "someDescription", + "type": "testProjectType1", + "mixins": [], + "attributes": { + "new_test_attribute": [ + "some_attribute_value" + ] + }, + "modules": [], + "problems": [], + "source": { + "type": "", + "location": "", + "parameters": {} + }, + "commands": [], + "links": [] + }, + { + "name": "testImportProject", + "displayName": "testImportProject", + "path": "/testImportProject", + "description": "someDescription", + "type": "testImportProjectType", + "mixins": [], + "attributes": { + "new_test_attribute": [ + "some_attribute_value" + ] + }, + "modules": [], + "problems": [], + "source": { + "type": "importType", + "location": "someLocation", + "parameters": {} + }, + "commands": [], + "links": [] + } +] diff --git a/wsmaster/che-core-api-project-templates-shared/src/main/java/org/eclipse/che/api/project/templates/shared/dto/ProjectTemplateDescriptor.java b/wsmaster/che-core-api-project-templates-shared/src/main/java/org/eclipse/che/api/project/templates/shared/dto/ProjectTemplateDescriptor.java index 13428c26623..c3be0a03f76 100644 --- a/wsmaster/che-core-api-project-templates-shared/src/main/java/org/eclipse/che/api/project/templates/shared/dto/ProjectTemplateDescriptor.java +++ b/wsmaster/che-core-api-project-templates-shared/src/main/java/org/eclipse/che/api/project/templates/shared/dto/ProjectTemplateDescriptor.java @@ -12,7 +12,7 @@ import org.eclipse.che.api.core.rest.shared.dto.Link; import org.eclipse.che.api.machine.shared.dto.CommandDto; -import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; +import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.dto.shared.DTO; @@ -110,4 +110,16 @@ public interface ProjectTemplateDescriptor { void setTags(List tags); ProjectTemplateDescriptor withTags(List tags); + + List getProjects(); + + void setProjects(List projects); + + ProjectTemplateDescriptor withProjects(List projects); + + Map getOptions(); + + void setOptions(Map options); + + ProjectTemplateDescriptor withOptions(Map options); } diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/NewProjectConfigDto.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/NewProjectConfigDto.java new file mode 100644 index 00000000000..149c323bf49 --- /dev/null +++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/NewProjectConfigDto.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.workspace.shared.dto; + +import org.eclipse.che.api.core.factory.FactoryParameter; +import org.eclipse.che.api.core.model.project.NewProjectConfig; +import org.eclipse.che.api.core.rest.shared.dto.Link; +import org.eclipse.che.dto.shared.DTO; + +import java.util.List; +import java.util.Map; + +import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL; + +/** + * Data transfer object (DTO) for creating of project. + * + * @author Roman Nikitenko + */ +@DTO +public interface NewProjectConfigDto extends ProjectConfigDto, NewProjectConfig { + @Override + @FactoryParameter(obligation = OPTIONAL) + String getName(); + + @Override + @FactoryParameter(obligation = OPTIONAL) + String getType(); + + @Override + @FactoryParameter(obligation = OPTIONAL) + SourceStorageDto getSource(); + + @Override + @FactoryParameter(obligation = OPTIONAL) + Map getOptions(); + + NewProjectConfigDto withName(String name); + + NewProjectConfigDto withPath(String path); + + NewProjectConfigDto withDescription(String description); + + NewProjectConfigDto withType(String type); + + NewProjectConfigDto withMixins(List mixins); + + NewProjectConfigDto withAttributes(Map> attributes); + + NewProjectConfigDto withSource(SourceStorageDto source); + + NewProjectConfigDto withLinks(List links); + + NewProjectConfigDto withProblems(List problems); + + NewProjectConfigDto withOptions(Map options); +} From 676b744723d42b77d884522a689826f2bfe17eb3 Mon Sep 17 00:00:00 2001 From: Ann Shumilova Date: Thu, 10 Nov 2016 13:16:43 +0200 Subject: [PATCH 31/74] CHE-2937: add ability to import multi-projects from dashboard Signed-off-by: Ann Shumilova --- .../create-project.controller.ts | 29 +++++++++++++++++-- .../create-project-samples.controller.ts | 1 + .../project-details/project-details.html | 2 +- .../workspace-details-projects.controller.ts | 10 ++++++- dashboard/src/components/api/che-project.ts | 11 +++++++ 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/dashboard/src/app/projects/create-project/create-project.controller.ts b/dashboard/src/app/projects/create-project/create-project.controller.ts index d2def5274af..63cc87f9943 100755 --- a/dashboard/src/app/projects/create-project/create-project.controller.ts +++ b/dashboard/src/app/projects/create-project/create-project.controller.ts @@ -592,7 +592,8 @@ export class CreateProjectController { let deferredResolve = this.$q.defer(); let deferredResolvePromise = deferredResolve.promise; - let importPromise = this.cheAPI.getWorkspace().getWorkspaceAgent(workspaceId).getProject().importProject(projectName, projectData.source); + let projects = this.processMultiproject(projectData); + let importPromise = this.cheAPI.getWorkspace().getWorkspaceAgent(workspaceId).getProject().createProjects(projects); importPromise.then(() => { // add commands if there are some that have been defined @@ -643,7 +644,31 @@ export class CreateProjectController { } - resolveProjectType(workspaceId: string, projectName: string, projectData: any, deferredResolve: ng.IDeferred) { + /** + * Process multi-project and prepare batch of projects to be created. + * + * @param projectData project data to process + * @returns {Array|any} array of projects + */ + processMultiproject(projectData) { + let currentPath = '/' + projectData.project.name; + + let projects = projectData.projects; + let project = angular.copy(projectData.project); + project.path = currentPath; + project.source = projectData.source; + + //Update path of sub-projects: + projects.forEach((project : any) => { + let index = project.path.indexOf('/' + project.name); + project.path = currentPath + project.path.substr(index); + }); + + projects.push(project); + return projects; + } + + resolveProjectType(workspaceId, projectName, projectData, deferredResolve) { let projectDetails = projectData.project; if (!projectDetails.attributes) { projectDetails.source = projectData.source; diff --git a/dashboard/src/app/projects/create-project/samples/create-project-samples.controller.ts b/dashboard/src/app/projects/create-project/samples/create-project-samples.controller.ts index aa99c081522..47b48638d2b 100644 --- a/dashboard/src/app/projects/create-project/samples/create-project-samples.controller.ts +++ b/dashboard/src/app/projects/create-project/samples/create-project-samples.controller.ts @@ -50,6 +50,7 @@ export class CreateProjectSamplesController { createProjectCtrl.setProjectDescription(template.description); createProjectCtrl.importProjectData.project.type = template.projectType; createProjectCtrl.importProjectData.project.commands = template.commands; + createProjectCtrl.importProjectData.projects = template.projects; let name: string = template.displayName; // strip space diff --git a/dashboard/src/app/projects/project-details/project-details.html b/dashboard/src/app/projects/project-details/project-details.html index dd132e2fade..bfae1cfa64a 100644 --- a/dashboard/src/app/projects/project-details/project-details.html +++ b/dashboard/src/app/projects/project-details/project-details.html @@ -3,7 +3,7 @@ che-button-name="Open" che-button-href="#/ide/{{projectDetailsController.namespace}}/{{projectDetailsController.workspaceName}}" che-breadcrumb-title="All projects" - che-breadcrumb-href="#/workspace/{{projectDetailsController.namespace}}/{{projectDetailsController.workspaceName}}" + che-breadcrumb-href="#/workspace/{{projectDetailsController.namespace}}/{{projectDetailsController.workspaceName}}/projects" che-subheader-icon="chefont cheico-type-{{projectDetailsController.projectDetails.type}} cheico-type-blank" che-subheader-title="{{projectDetailsController.projectDetails.type}}"> diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts b/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts index 6bfea1bb7e3..a946433cc2d 100644 --- a/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts @@ -59,7 +59,15 @@ export class WorkspaceDetailsProjectsCtrl { updateProjectsData() { this.workspace = this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName); - this.projects = this.workspace.config.projects; + this.projects = []; + + // filter only root projects (do not show sub-projects of multi-project item): + this.workspace.config.projects.forEach((project : any) => { + let path = project.path.replace('/', ''); + if (path === project.name) { + this.projects.push(project); + } + }); this.workspaceId = this.workspace.id; } diff --git a/dashboard/src/components/api/che-project.ts b/dashboard/src/components/api/che-project.ts index c46d970b544..54ddf01e67b 100644 --- a/dashboard/src/components/api/che-project.ts +++ b/dashboard/src/components/api/che-project.ts @@ -43,6 +43,7 @@ export class CheProject { this.remoteProjectsAPI = this.$resource(wsagentPath + '/project', {}, { import: {method: 'POST', url: wsagentPath + '/project/import/:path'}, create: {method: 'POST', url: wsagentPath + '/project?name=:path'}, + batchCreate: {method: 'POST', url: wsagentPath + '/project/batch', isArray: true}, details: {method: 'GET', url: wsagentPath + '/project/:path'}, estimate: {method: 'GET', url: wsagentPath + '/project/estimate/:path?type=:type'}, rename: {method: 'POST', url: wsagentPath + '/project/rename/:path?name=:name'}, @@ -79,6 +80,16 @@ export class CheProject { return promise; } + /** + * Create a batch of projects. + * @param projects the list of projects to be created + * @returns {$promise|*|T.$promise} + */ + createProjects(projects) { + let promise = this.remoteProjectsAPI.batchCreate(projects).$promise; + return promise; + } + /** * Gets the fullname from a profile * @param profile the profile to analyze From 3946524297527eb936e66d6da9e036f4a5250ca2 Mon Sep 17 00:00:00 2001 From: Mihail Kuznyetsov Date: Fri, 1 Jul 2016 16:44:50 +0300 Subject: [PATCH 32/74] CODENVY-586 Remove position from model property --- .../eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java index 877cbc7b58a..3237892ba1b 100644 --- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java +++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java @@ -92,8 +92,7 @@ public interface ProjectConfigDto extends ProjectConfig { ProjectConfigDto withLinks(List links); /** Provides information about project errors. If project doesn't have any error this field is empty. */ - @ApiModelProperty(value = "Optional information about project errors. If project doesn't have any error this field is empty", - position = 17) + @ApiModelProperty(value = "Optional information about project errors. If project doesn't have any error this field is empty") List getProblems(); /** @see #getProblems */ From 6dd67154ece50a7bb2ba44af5f5936fd8e8fd925 Mon Sep 17 00:00:00 2001 From: Ann Shumilova Date: Thu, 1 Dec 2016 11:19:01 +0200 Subject: [PATCH 33/74] Fix import projects by URL, from GitHub Signed-off-by: Ann Shumilova --- .../app/projects/create-project/create-project.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard/src/app/projects/create-project/create-project.controller.ts b/dashboard/src/app/projects/create-project/create-project.controller.ts index 63cc87f9943..5f71d8e2799 100755 --- a/dashboard/src/app/projects/create-project/create-project.controller.ts +++ b/dashboard/src/app/projects/create-project/create-project.controller.ts @@ -653,7 +653,7 @@ export class CreateProjectController { processMultiproject(projectData) { let currentPath = '/' + projectData.project.name; - let projects = projectData.projects; + let projects = projectData.projects || []; let project = angular.copy(projectData.project); project.path = currentPath; project.source = projectData.source; From 56ddd584819f6ae70460588cc6cbe503e8067733 Mon Sep 17 00:00:00 2001 From: Florent BENOIT Date: Thu, 1 Dec 2016 10:54:17 +0100 Subject: [PATCH 34/74] Move eclipse/che-dockerfiles che-* images to this repository in /dockerfiles folder Change-Id: I4c258775a4a67a87cba3b3dbfbc1af2cc2f8416f Signed-off-by: Florent BENOIT --- dockerfiles/README.md | 39 + dockerfiles/action/Dockerfile | 15 + dockerfiles/action/README.md | 21 + dockerfiles/action/build.sh | 12 + dockerfiles/base-cli/Dockerfile | 36 + dockerfiles/base-cli/build.sh | 12 + .../scripts/base/cli/cli-functions.sh | 552 + .../scripts/base/commands/cmd_action.sh | 29 + .../scripts/base/commands/cmd_backup.sh | 60 + .../scripts/base/commands/cmd_config.sh | 115 + .../scripts/base/commands/cmd_debug.sh | 39 + .../scripts/base/commands/cmd_destroy.sh | 84 + .../scripts/base/commands/cmd_download.sh | 27 + .../scripts/base/commands/cmd_help.sh | 15 + .../scripts/base/commands/cmd_info.sh | 37 + .../scripts/base/commands/cmd_init.sh | 124 + .../scripts/base/commands/cmd_network.sh | 85 + .../scripts/base/commands/cmd_offline.sh | 39 + .../scripts/base/commands/cmd_restore.sh | 58 + .../base-cli/scripts/base/commands/cmd_rmi.sh | 34 + .../base-cli/scripts/base/commands/cmd_ssh.sh | 15 + .../scripts/base/commands/cmd_start.sh | 94 + .../scripts/base/commands/cmd_sync.sh | 50 + .../scripts/base/commands/cmd_upgrade.sh | 49 + .../scripts/base/commands/cmd_version.sh | 35 + dockerfiles/base-cli/scripts/base/curl.sh | 22 + dockerfiles/base-cli/scripts/base/docker.sh | 334 + dockerfiles/base-cli/scripts/base/paths.sh | 69 + dockerfiles/base-cli/scripts/base/startup.sh | 270 + dockerfiles/build-all.sh | 41 + dockerfiles/build.include | 31 + dockerfiles/cli/Dockerfile | 18 + dockerfiles/cli/build.sh | 12 + dockerfiles/cli/scripts/cli.sh | 15 + dockerfiles/cli/scripts/cmd_empty.sh | 7 + dockerfiles/cli/scripts/entrypoint.sh | 57 + dockerfiles/cli/version/4.7.2/images | 4 + dockerfiles/cli/version/5.0.0-M5/images | 4 + dockerfiles/cli/version/5.0.0-M6/images | 4 + dockerfiles/cli/version/5.0.0-M7/images | 4 + dockerfiles/cli/version/latest.ver | 1 + dockerfiles/cli/version/latest/images | 4 + dockerfiles/cli/version/nightly/images | 4 + dockerfiles/dev/Dockerfile | 70 + dockerfiles/dev/build.sh | 12 + dockerfiles/dir/Dockerfile | 15 + dockerfiles/dir/README.md | 33 + dockerfiles/dir/build.sh | 12 + dockerfiles/init/Dockerfile | 38 + dockerfiles/init/build.sh | 12 + dockerfiles/init/docs/DOCS.md | 0 dockerfiles/init/docs/README.md | 0 dockerfiles/init/entrypoint.sh | 17 + dockerfiles/init/manifests/che.env | 173 + dockerfiles/init/manifests/che.pp | 35 + .../init/modules/base/manifests/init.pp | 16 + .../init/modules/che/manifests/init.pp | 9 + .../init/modules/che/templates/che.env.erb | 24 + .../init/modules/compose/manifests/init.pp | 14 + .../docker-compose-container.yml.erb | 24 + .../compose/templates/docker-compose.yml.erb | 24 + .../lib/puppet/parser/functions/getValue.rb | 12 + dockerfiles/ip/Dockerfile | 16 + dockerfiles/ip/build.sh | 12 + dockerfiles/ip/entrypoint.sh | 45 + dockerfiles/launcher/Dockerfile | 39 + dockerfiles/launcher/build.sh | 12 + dockerfiles/launcher/launcher.sh | 160 + dockerfiles/launcher/launcher_cmds.sh | 163 + dockerfiles/launcher/launcher_funcs.sh | 496 + dockerfiles/launcher/launcher_test.bats | 184 + dockerfiles/lib-typescript/.babelrc | 3 + dockerfiles/lib-typescript/.dockerignore | 1 + dockerfiles/lib-typescript/.gitignore | 5 + dockerfiles/lib-typescript/Dockerfile | 32 + dockerfiles/lib-typescript/Dockerfile.dev | 30 + dockerfiles/lib-typescript/README.md | 8 + dockerfiles/lib-typescript/build.sh | 65 + dockerfiles/lib-typescript/dto-pom.xml | 123 + dockerfiles/lib-typescript/package.json | 33 + .../runtime-dependencies/package.json | 12 + .../lib-typescript/src/api/dto/che-dto.ts | 16543 ++++++++++++++++ .../src/api/wsmaster/auth/auth-data.ts | 191 + .../machine/machine-service-client.ts | 104 + .../machine/process-log-output-subscriber.ts | 30 + ...ess-terminated-event-promise-subscriber.ts | 54 + .../api/wsmaster/permissions/dto/domaindto.ts | 23 + .../wsmaster/permissions/dto/permissiondto.ts | 23 + .../api/wsmaster/permissions/permissions.ts | 100 + .../src/api/wsmaster/project/project.ts | 141 + .../src/api/wsmaster/ssh/ssh.ts | 54 + .../src/api/wsmaster/user/user.ts | 82 + .../workspace-log-output-subscriber.ts | 31 + ...orkspace-start-event-promise-subscriber.ts | 57 + ...workspace-stop-event-promise-subscriber.ts | 57 + .../src/api/wsmaster/workspace/workspace.ts | 289 + dockerfiles/lib-typescript/src/index.ts | 104 + .../src/internal/action/che-action.ts | 94 + .../internal/action/impl/add-user-action.ts | 77 + .../impl/create-start-workspace-action.ts | 74 + .../action/impl/execute-command-action.ts | 85 + .../internal/action/impl/get-ssh-action.ts | 115 + .../action/impl/list-workspaces-action.ts | 78 + .../action/impl/remove-user-action.ts | 60 + .../action/impl/workspace-ssh-action.ts | 152 + .../internal/dir/che-dir-constant.properties | 37 + .../src/internal/dir/che-dir.ts | 1235 ++ .../dir/chefile-struct/che-file-struct.ts | 154 + .../src/internal/test/che-test.ts | 85 + .../impl/post-flight-check-test.properties | 15 + .../test/impl/post-flight-check-test.ts | 87 + .../src/spi/ascii/ascii-array-info.ts | 21 + .../src/spi/ascii/ascii-array.ts | 91 + .../src/spi/ascii/ascii-form-entry.ts | 63 + .../src/spi/ascii/ascii-form-info.ts | 32 + .../src/spi/ascii/ascii-form.ts | 55 + .../src/spi/ascii/ascii-format.ts | 80 + .../src/spi/ascii/ascii-formatter.ts | 54 + .../src/spi/ascii/csv-formatter.ts | 81 + .../src/spi/ascii/default-ascii-array.spec.ts | 184 + .../src/spi/ascii/default-ascii-array.ts | 527 + .../src/spi/ascii/default-ascii-form.spec.ts | 51 + .../src/spi/ascii/default-ascii-form.ts | 179 + .../src/spi/ascii/formatter-mode.ts | 15 + .../src/spi/ascii/modern-formatter.ts | 82 + .../src/spi/decorator/argument-processor.ts | 188 + .../src/spi/decorator/message.ts | 61 + .../src/spi/decorator/parameter.ts | 83 + .../src/spi/docker/container-version.ts | 31 + .../src/spi/docker/recipebuilder.ts | 75 + .../lib-typescript/src/spi/docker/remoteip.ts | 34 + .../src/spi/docker/ssh-generator.ts | 84 + .../src/spi/http/default-http-json-request.ts | 177 + .../lib-typescript/src/spi/i18n/i18n.ts | 42 + dockerfiles/lib-typescript/src/spi/index.ts | 23 + dockerfiles/lib-typescript/src/spi/log/log.ts | 128 + .../src/spi/websocket/messagebuilder.ts | 77 + .../spi/websocket/messagebus-subscriber.ts | 20 + .../src/spi/websocket/messagebus.ts | 238 + .../src/spi/websocket/websocket.ts | 58 + dockerfiles/lib-typescript/src/utils/index.ts | 12 + .../lib-typescript/src/utils/product-name.ts | 25 + .../src/utils/string-utils.spec.ts | 24 + .../lib-typescript/src/utils/string-utils.ts | 16 + dockerfiles/lib-typescript/src/utils/uuid.ts | 26 + dockerfiles/lib-typescript/tsconfig.json | 22 + dockerfiles/mount/Dockerfile | 69 + dockerfiles/mount/build.sh | 12 + dockerfiles/mount/entrypoint.sh | 137 + dockerfiles/test/Dockerfile | 15 + dockerfiles/test/README.md | 22 + dockerfiles/test/build.sh | 12 + 152 files changed, 28013 insertions(+) create mode 100644 dockerfiles/README.md create mode 100644 dockerfiles/action/Dockerfile create mode 100644 dockerfiles/action/README.md create mode 100755 dockerfiles/action/build.sh create mode 100644 dockerfiles/base-cli/Dockerfile create mode 100755 dockerfiles/base-cli/build.sh create mode 100644 dockerfiles/base-cli/scripts/base/cli/cli-functions.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_action.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_backup.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_config.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_debug.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_destroy.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_download.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_help.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_info.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_init.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_network.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_offline.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_restore.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_rmi.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_ssh.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_start.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_sync.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_upgrade.sh create mode 100644 dockerfiles/base-cli/scripts/base/commands/cmd_version.sh create mode 100644 dockerfiles/base-cli/scripts/base/curl.sh create mode 100644 dockerfiles/base-cli/scripts/base/docker.sh create mode 100644 dockerfiles/base-cli/scripts/base/paths.sh create mode 100644 dockerfiles/base-cli/scripts/base/startup.sh create mode 100755 dockerfiles/build-all.sh create mode 100755 dockerfiles/build.include create mode 100644 dockerfiles/cli/Dockerfile create mode 100755 dockerfiles/cli/build.sh create mode 100644 dockerfiles/cli/scripts/cli.sh create mode 100644 dockerfiles/cli/scripts/cmd_empty.sh create mode 100755 dockerfiles/cli/scripts/entrypoint.sh create mode 100644 dockerfiles/cli/version/4.7.2/images create mode 100644 dockerfiles/cli/version/5.0.0-M5/images create mode 100644 dockerfiles/cli/version/5.0.0-M6/images create mode 100644 dockerfiles/cli/version/5.0.0-M7/images create mode 100644 dockerfiles/cli/version/latest.ver create mode 100644 dockerfiles/cli/version/latest/images create mode 100644 dockerfiles/cli/version/nightly/images create mode 100644 dockerfiles/dev/Dockerfile create mode 100755 dockerfiles/dev/build.sh create mode 100644 dockerfiles/dir/Dockerfile create mode 100644 dockerfiles/dir/README.md create mode 100755 dockerfiles/dir/build.sh create mode 100644 dockerfiles/init/Dockerfile create mode 100755 dockerfiles/init/build.sh create mode 100644 dockerfiles/init/docs/DOCS.md create mode 100644 dockerfiles/init/docs/README.md create mode 100644 dockerfiles/init/entrypoint.sh create mode 100644 dockerfiles/init/manifests/che.env create mode 100644 dockerfiles/init/manifests/che.pp create mode 100644 dockerfiles/init/modules/base/manifests/init.pp create mode 100644 dockerfiles/init/modules/che/manifests/init.pp create mode 100644 dockerfiles/init/modules/che/templates/che.env.erb create mode 100644 dockerfiles/init/modules/compose/manifests/init.pp create mode 100644 dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb create mode 100644 dockerfiles/init/modules/compose/templates/docker-compose.yml.erb create mode 100644 dockerfiles/init/modules/puppet_plugins/lib/puppet/parser/functions/getValue.rb create mode 100644 dockerfiles/ip/Dockerfile create mode 100755 dockerfiles/ip/build.sh create mode 100755 dockerfiles/ip/entrypoint.sh create mode 100644 dockerfiles/launcher/Dockerfile create mode 100755 dockerfiles/launcher/build.sh create mode 100755 dockerfiles/launcher/launcher.sh create mode 100644 dockerfiles/launcher/launcher_cmds.sh create mode 100644 dockerfiles/launcher/launcher_funcs.sh create mode 100644 dockerfiles/launcher/launcher_test.bats create mode 100644 dockerfiles/lib-typescript/.babelrc create mode 100644 dockerfiles/lib-typescript/.dockerignore create mode 100644 dockerfiles/lib-typescript/.gitignore create mode 100644 dockerfiles/lib-typescript/Dockerfile create mode 100644 dockerfiles/lib-typescript/Dockerfile.dev create mode 100644 dockerfiles/lib-typescript/README.md create mode 100755 dockerfiles/lib-typescript/build.sh create mode 100644 dockerfiles/lib-typescript/dto-pom.xml create mode 100644 dockerfiles/lib-typescript/package.json create mode 100644 dockerfiles/lib-typescript/runtime-dependencies/package.json create mode 100644 dockerfiles/lib-typescript/src/api/dto/che-dto.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/auth/auth-data.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/machine/machine-service-client.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/machine/process-log-output-subscriber.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/domaindto.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/permissiondto.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/permissions/permissions.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/project/project.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/user/user.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts create mode 100644 dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace.ts create mode 100644 dockerfiles/lib-typescript/src/index.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/che-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/impl/add-user-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/impl/create-start-workspace-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/impl/execute-command-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/impl/get-ssh-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/impl/list-workspaces-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/impl/remove-user-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/action/impl/workspace-ssh-action.ts create mode 100644 dockerfiles/lib-typescript/src/internal/dir/che-dir-constant.properties create mode 100644 dockerfiles/lib-typescript/src/internal/dir/che-dir.ts create mode 100644 dockerfiles/lib-typescript/src/internal/dir/chefile-struct/che-file-struct.ts create mode 100644 dockerfiles/lib-typescript/src/internal/test/che-test.ts create mode 100644 dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.properties create mode 100644 dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/ascii-array-info.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/ascii-array.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/ascii-form-entry.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/ascii-form-info.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/ascii-form.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/ascii-format.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/ascii-formatter.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/csv-formatter.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.spec.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.spec.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/formatter-mode.ts create mode 100644 dockerfiles/lib-typescript/src/spi/ascii/modern-formatter.ts create mode 100644 dockerfiles/lib-typescript/src/spi/decorator/argument-processor.ts create mode 100644 dockerfiles/lib-typescript/src/spi/decorator/message.ts create mode 100644 dockerfiles/lib-typescript/src/spi/decorator/parameter.ts create mode 100644 dockerfiles/lib-typescript/src/spi/docker/container-version.ts create mode 100644 dockerfiles/lib-typescript/src/spi/docker/recipebuilder.ts create mode 100644 dockerfiles/lib-typescript/src/spi/docker/remoteip.ts create mode 100644 dockerfiles/lib-typescript/src/spi/docker/ssh-generator.ts create mode 100644 dockerfiles/lib-typescript/src/spi/http/default-http-json-request.ts create mode 100644 dockerfiles/lib-typescript/src/spi/i18n/i18n.ts create mode 100644 dockerfiles/lib-typescript/src/spi/index.ts create mode 100644 dockerfiles/lib-typescript/src/spi/log/log.ts create mode 100644 dockerfiles/lib-typescript/src/spi/websocket/messagebuilder.ts create mode 100644 dockerfiles/lib-typescript/src/spi/websocket/messagebus-subscriber.ts create mode 100644 dockerfiles/lib-typescript/src/spi/websocket/messagebus.ts create mode 100644 dockerfiles/lib-typescript/src/spi/websocket/websocket.ts create mode 100644 dockerfiles/lib-typescript/src/utils/index.ts create mode 100644 dockerfiles/lib-typescript/src/utils/product-name.ts create mode 100644 dockerfiles/lib-typescript/src/utils/string-utils.spec.ts create mode 100644 dockerfiles/lib-typescript/src/utils/string-utils.ts create mode 100644 dockerfiles/lib-typescript/src/utils/uuid.ts create mode 100644 dockerfiles/lib-typescript/tsconfig.json create mode 100644 dockerfiles/mount/Dockerfile create mode 100755 dockerfiles/mount/build.sh create mode 100755 dockerfiles/mount/entrypoint.sh create mode 100644 dockerfiles/test/Dockerfile create mode 100644 dockerfiles/test/README.md create mode 100755 dockerfiles/test/build.sh diff --git a/dockerfiles/README.md b/dockerfiles/README.md new file mode 100644 index 00000000000..32cb50da319 --- /dev/null +++ b/dockerfiles/README.md @@ -0,0 +1,39 @@ +# Eclipse Che - Dockerfiles + +This `che-dockerfiles` repository is where all dockerfiles for Che Launcher, Che's CLI and Che's Stacks are hosted. + +# Eclipse Che +[![Join the chat at https://gitter.im/eclipse/che](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/eclipse/che?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Eclipse License](http://img.shields.io/badge/license-Eclipse-brightgreen.svg)](https://github.com/codenvy/che/blob/master/LICENSE) +[![Build Status](https://ci.codenvycorp.com/buildStatus/icon?job=che-ci-master)](https://ci.codenvycorp.com/job/che-ci-master) + +https://www.eclipse.org/che/. Next-generation Eclipse platform, developer workspace server and cloud IDE. Che defines workspaces that include their dependencies including embedded containerized runtimes, Web IDE, and project code. This makes workspaces distributed, collaborative, and portable to run anywhere on a desktop or a server ... [Read More](https://www.eclipse.org/che/features/) + +![Eclipse Che](https://www.eclipse.org/che/images/banner@2x.png "Eclipse Che") + +### Getting Started +You can run Che in the public cloud, a private cloud, or install it on any OS. Che has been tested on Ubuntu, Linux, MacOS and Windows. The [step by step guide](http://eclipse.org/che/getting-started/) will get you going. + +The `che` repository is where we do development and there are many ways you can participate, for example: + +- [Submit bugs and feature requests](http://github.com/eclipse/che/issues) and help us verify them +- Review [source code changes](http://github.com/eclipse/che/pulls) +- [Review the docs](https://eclipse-che.readme.io/docs/) and make improvements for anything from typos to new content + +### Customizing +There are many ways to customize Che out-of-the-box including [stacks, templates, commands, IDE extensions, server-side extensions plugins, assemblies, RESTful APIs, and editors](https://github.com/eclipse/che/blob/master/CUSTOMIZING.md). + +### Contributing +If you are interested in fixing issues and contributing directly to the code base, please see [How to Contribute](https://github.com/eclipse/che/wiki/How-To-Contribute). It covers: +- [Submitting bugs](https://github.com/eclipse/che/wiki/Submitting-Bugs-and-Suggestions) +- [Development workflow](https://github.com/eclipse/che/wiki/Development-Workflow) +- [Coding guidelines](https://github.com/eclipse/che/wiki/Coding-Guidelines) +- [Contributor license agreement](https://github.com/eclipse/che/wiki/Contributor-License-Agreement) + +### Feedback +* **Support:** You can ask questions, report bugs, and request features using [GitHub issues](http://github.com/eclipse/che/issues). +* **Roadmap:** We maintain [the roadmap](https://github.com/eclipse/che/wiki/Roadmap) on the wiki. +* **Weekly Meetings:** Join us on [a hangout](https://github.com/eclipse/che/wiki/Weekly-Planning-Meetings). + +### License +Che is open sourced under the Eclipse Public License 1.0. diff --git a/dockerfiles/action/Dockerfile b/dockerfiles/action/Dockerfile new file mode 100644 index 00000000000..712b9f1d548 --- /dev/null +++ b/dockerfiles/action/Dockerfile @@ -0,0 +1,15 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# build: +# docker build -t eclipse/che-action . +# +# use: +# docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action [command] + +FROM eclipse/che-lib-typescript:nightly + +ENTRYPOINT ["node", "/che-lib/index.js", "che-action"] diff --git a/dockerfiles/action/README.md b/dockerfiles/action/README.md new file mode 100644 index 00000000000..bc06f9b4ff6 --- /dev/null +++ b/dockerfiles/action/README.md @@ -0,0 +1,21 @@ +### Performing actions on a local or remote Eclipse Che instance with a Docker container + +## Build container +``` +$ build.sh (on Unix) +``` + +## Run container +``` +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action +``` + +## Get available actions +``` +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action +``` + +## Get help on a test +``` +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action --help +``` diff --git a/dockerfiles/action/build.sh b/dockerfiles/action/build.sh new file mode 100755 index 00000000000..07da185bfad --- /dev/null +++ b/dockerfiles/action/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-action" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/base-cli/Dockerfile b/dockerfiles/base-cli/Dockerfile new file mode 100644 index 00000000000..402e45621f3 --- /dev/null +++ b/dockerfiles/base-cli/Dockerfile @@ -0,0 +1,36 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# build: +# docker build -t eclipse/che-base . +# +# use: +# docker run eclipse/che-base + +FROM alpine:3.4 + +ENV DOCKER_BUCKET get.docker.com +ENV DOCKER_VERSION 1.11.2 +ENV DOCKER_SHA256 8c2e0c35e3cda11706f54b2d46c2521a6e9026a7b13c7d4b8ae1f3a706fc55e1 + +# install docker +RUN mkdir -p /version \ + && mkdir -p /cli \ + && mkdir /scripts/ \ + && apk add --no-cache ca-certificates curl openssl jq \ + && apk add --update bash \ + && rm -rf /var/cache/apk/* \ + && set -x \ + && curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz" -o docker.tgz \ + && echo "${DOCKER_SHA256} *docker.tgz" | sha256sum -c - \ + && tar -xzvf docker.tgz \ + && mv docker/docker /usr/local/bin/ \ + && rm -rf docker \ + && rm docker.tgz \ + && docker -v + +COPY scripts/base /scripts/base/ + diff --git a/dockerfiles/base-cli/build.sh b/dockerfiles/base-cli/build.sh new file mode 100755 index 00000000000..19ee6b28a00 --- /dev/null +++ b/dockerfiles/base-cli/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-base" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/base-cli/scripts/base/cli/cli-functions.sh b/dockerfiles/base-cli/scripts/base/cli/cli-functions.sh new file mode 100644 index 00000000000..81ef8f94e98 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/cli/cli-functions.sh @@ -0,0 +1,552 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + + + +cli_init() { + + # Constants + CHE_MANIFEST_DIR="/version" + CHE_CONTAINER_OFFLINE_FOLDER="/${CHE_MINI_PRODUCT_NAME}/backup" + CHE_VERSION_FILE="${CHE_MINI_PRODUCT_NAME}.ver.do_not_modify" + CHE_ENVIRONMENT_FILE="${CHE_MINI_PRODUCT_NAME}.env" + CHE_COMPOSE_FILE="docker-compose-container.yml" + + DEFAULT_CHE_SERVER_CONTAINER_NAME="${CHE_MINI_PRODUCT_NAME}" + CHE_SERVER_CONTAINER_NAME="${CHE_SERVER_CONTAINER_NAME:-${DEFAULT_CHE_SERVER_CONTAINER_NAME}}" + + CHE_BACKUP_FILE_NAME="${CHE_MINI_PRODUCT_NAME}_backup.tar.gz" + CHE_COMPOSE_STOP_TIMEOUT="180" + + grab_offline_images "$@" + grab_initial_images + + DEFAULT_CHE_CLI_ACTION="help" + CHE_CLI_ACTION=${CHE_CLI_ACTION:-${DEFAULT_CHE_CLI_ACTION}} + + DEFAULT_CHE_LICENSE=false + CHE_LICENSE=${CHE_LICENSE:-${DEFAULT_CHE_LICENSE}} + + CHE_HOST=$(eval "echo \$${CHE_PRODUCT_NAME}_HOST") + CHE_PORT=$(eval "echo \$${CHE_PRODUCT_NAME}_PORT") + + if [[ "$(eval "echo \$${CHE_PRODUCT_NAME}_HOST")" = "" ]]; then + info "Welcome to $CHE_FORMAL_PRODUCT_NAME!" + info "" + info "We did not auto-detect a valid HOST or IP address." + info "Pass ${CHE_PRODUCT_NAME}_HOST with your hostname or IP address." + info "" + info "Rerun the CLI:" + info " docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock" + info " -v :${CHE_CONTAINER_ROOT}" + info " -e ${CHE_PRODUCT_NAME}_HOST=" + info " $CHE_IMAGE_FULLNAME $*" + return 2; + fi + + REFERENCE_HOST_ENVIRONMENT_FILE="${CHE_HOST_CONFIG}/${CHE_ENVIRONMENT_FILE}" + REFERENCE_HOST_COMPOSE_FILE="${CHE_HOST_INSTANCE}/${CHE_COMPOSE_FILE}" + REFERENCE_CONTAINER_ENVIRONMENT_FILE="${CHE_CONTAINER_CONFIG}/${CHE_ENVIRONMENT_FILE}" + REFERENCE_CONTAINER_COMPOSE_FILE="${CHE_CONTAINER_INSTANCE}/${CHE_COMPOSE_FILE}" + + CHE_HOST_CONFIG_MANIFESTS_FOLDER="$CHE_HOST_INSTANCE/manifests" + CHE_CONTAINER_CONFIG_MANIFESTS_FOLDER="$CHE_CONTAINER_INSTANCE/manifests" + + CHE_HOST_CONFIG_MODULES_FOLDER="$CHE_HOST_INSTANCE/modules" + CHE_CONTAINER_CONFIG_MODULES_FOLDER="$CHE_CONTAINER_INSTANCE/modules" + + # TODO: Change this to use the current folder or perhaps ~? + if is_boot2docker && has_docker_for_windows_client; then + if [[ "${CHE_HOST_INSTANCE,,}" != *"${USERPROFILE,,}"* ]]; then + CHE_HOST_INSTANCE=$(get_mount_path "${USERPROFILE}/.${CHE_MINI_PRODUCT_NAME}/") + warning "Boot2docker for Windows - CHE_INSTANCE set to $CHE_HOST_INSTANCE" + fi + if [[ "${CHE_HOST_CONFIG,,}" != *"${USERPROFILE,,}"* ]]; then + CHE_HOST_CONFIG=$(get_mount_path "${USERPROFILE}/.${CHE_MINI_PRODUCT_NAME}/") + warning "Boot2docker for Windows - CHE_CONFIG set to $CHE_HOST_CONFIG" + fi + fi + + # Do not perform a version compatibility check if running upgrade command. + # The upgrade command has its own internal checks for version compatibility. + if [ $1 != "upgrade" ]; then + verify_version_compatibility + else + verify_version_upgrade_compatibility + fi +} + +cli_execute() { + + COMMAND="cmd_$1" + + # Need to load all files in advance so commands can invoke other commands. + for COMMAND_FILE in "${SCRIPTS_CONTAINER_SOURCE_DIR}"/cmd_*.sh + do + source "${COMMAND_FILE}" + done + + shift + eval $COMMAND "$@" + +} + +cli_parse () { + debug $FUNCNAME + COMMAND="cmd_$1" + + case $1 in + init|config|start|stop|restart|backup|restore|info|offline|destroy|download|rmi|upgrade|version|ssh|mount|action|test|compile|help) + ;; + *) + error "You passed an unknown command." + usage + return 2 + ;; + esac +} + + +cmd_init_reinit_pre_action() { + sed -i'.bak' "s|#CHE_HOST=.*|CHE_HOST=${CHE_HOST}|" "${REFERENCE_CONTAINER_ENVIRONMENT_FILE}" +} + + +get_boot_url() { + echo "$CHE_HOST:$CHE_PORT/api/" +} + + +get_display_url() { + if ! is_docker_for_mac; then + echo "http://${CHE_HOST}:${CHE_PORT}" + else + echo "http://localhost:${CHE_PORT}" + fi +} + + +check_if_booted() { + CURRENT_CHE_SERVER_CONTAINER_ID=$(get_server_container_id $CHE_SERVER_CONTAINER_NAME) + wait_until_container_is_running 20 ${CURRENT_CHE_SERVER_CONTAINER_ID} + if ! container_is_running ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + error "(${CHE_MINI_PRODUCT_NAME} start): Timeout waiting for ${CHE_MINI_PRODUCT_NAME} container to start." + return 2 + fi + + info "start" "Services booting..." + info "start" "Server logs at \"docker logs -f ${CHE_SERVER_CONTAINER_NAME}\"" + wait_until_server_is_booted 60 ${CURRENT_CHE_SERVER_CONTAINER_ID} + + DISPLAY_URL=$(get_display_url) + + if server_is_booted ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + info "start" "Booted and reachable" + info "start" "Ver: $(get_installed_version)" + info "start" "Use: ${DISPLAY_URL}" + info "start" "API: ${DISPLAY_URL}/swagger" + else + error "(${CHE_MINI_PRODUCT_NAME} start): Timeout waiting for server. Run \"docker logs ${CHE_SERVER_CONTAINER_NAME}\" to inspect the issue." + return 2 + fi +} + +server_is_booted() { + PING_URL=$(get_boot_url) + HTTP_STATUS_CODE=$(curl -I -k ${PING_URL} -s -o /dev/null --write-out "%{http_code}") + log "${HTTP_STATUS_CODE}" + if [[ "${HTTP_STATUS_CODE}" = "200" ]] || [[ "${HTTP_STATUS_CODE}" = "302" ]]; then + return 0 + else + return 1 + fi +} + + +grab_offline_images(){ + # If you are using ${CHE_FORMAL_PRODUCT_NAME} in offline mode, images must be loaded here + # This is the point where we know that docker is working, but before we run any utilities + # that require docker. + if [[ "$@" == *"--offline"* ]]; then + info "init" "Importing ${CHE_MINI_PRODUCT_NAME} Docker images from tars..." + + if [ ! -d ${CHE_CONTAINER_OFFLINE_FOLDER} ]; then + info "init" "You requested offline image loading, but '${CHE_CONTAINER_OFFLINE_FOLDER}' folder not found" + return 2; + fi + + IFS=$'\n' + for file in "${CHE_CONTAINER_OFFLINE_FOLDER}"/*.tar + do + if ! $(docker load < "${CHE_CONTAINER_OFFLINE_FOLDER}"/"${file##*/}" > /dev/null); then + error "Failed to restore ${CHE_MINI_PRODUCT_NAME} Docker images" + return 2; + fi + info "init" "Loading ${file##*/}..." + done + fi +} + +grab_initial_images() { + # Prep script by getting default image + if [ "$(docker images -q alpine:3.4 2> /dev/null)" = "" ]; then + info "cli" "Pulling image alpine:3.4" + log "docker pull alpine:3.4 >> \"${LOGS}\" 2>&1" + TEST="" + docker pull alpine:3.4 >> "${LOGS}" 2>&1 || TEST=$? + if [ "$TEST" = "1" ]; then + error "Image alpine:3.4 unavailable. Not on dockerhub or built locally." + return 2; + fi + fi + + if [ "$(docker images -q appropriate/curl 2> /dev/null)" = "" ]; then + info "cli" "Pulling image appropriate/curl:latest" + log "docker pull appropriate/curl:latest >> \"${LOGS}\" 2>&1" + TEST="" + docker pull appropriate/curl >> "${LOGS}" 2>&1 || TEST=$? + if [ "$TEST" = "1" ]; then + error "Image appropriate/curl:latest unavailable. Not on dockerhub or built locally." + return 2; + fi + fi + + if [ "$(docker images -q eclipse/che-ip:nightly 2> /dev/null)" = "" ]; then + info "cli" "Pulling image eclipse/che-ip:nightly" + log "docker pull eclipse/che-ip:nightly >> \"${LOGS}\" 2>&1" + TEST="" + docker pull eclipse/che-ip:nightly >> "${LOGS}" 2>&1 || TEST=$? + if [ "$TEST" = "1" ]; then + error "Image eclipse/che-ip:nightly unavailable. Not on dockerhub or built locally." + return 2; + fi + fi +} + + +has_env_variables() { + debug $FUNCNAME + PROPERTIES=$(env | grep "${CHE_PRODUCT_NAME}_") + + if [ "$PROPERTIES" = "" ]; then + return 1 + else + return 0 + fi +} + +update_image_if_not_found() { + debug $FUNCNAME + + text "${GREEN}INFO:${NC} (${CHE_MINI_PRODUCT_NAME} download): Checking for image '$1'..." + CURRENT_IMAGE=$(docker images -q "$1") + if [ "${CURRENT_IMAGE}" == "" ]; then + text "not found\n" + update_image $1 + else + text "found\n" + fi +} + +update_image() { + debug $FUNCNAME + + if [ "${1}" == "--force" ]; then + shift + info "download" "Removing image $1" + log "docker rmi -f $1 >> \"${LOGS}\"" + docker rmi -f $1 >> "${LOGS}" 2>&1 || true + fi + + if [ "${1}" == "--pull" ]; then + shift + fi + + info "download" "Pulling image $1" + text "\n" + log "docker pull $1 >> \"${LOGS}\" 2>&1" + TEST="" + docker pull $1 || TEST=$? + if [ "$TEST" = "1" ]; then + error "Image $1 unavailable. Not on dockerhub or built locally." + return 2; + fi + text "\n" +} + +is_initialized() { + debug $FUNCNAME + if [[ -d "${CHE_CONTAINER_INSTANCE}" ]] && \ + [[ -f "${CHE_CONTAINER_INSTANCE}"/$CHE_VERSION_FILE ]] && \ + [[ -f "${REFERENCE_CONTAINER_ENVIRONMENT_FILE}" ]]; then + return 0 + else + return 1 + fi +} + +is_configured() { + debug $FUNCNAME + if [[ -d "${CHE_CONTAINER_CONFIG_MANIFESTS_FOLDER}" ]] && \ + [[ -d "${CHE_CONTAINER_CONFIG_MODULES_FOLDER}" ]]; then + return 0 + else + return 1 + fi +} + +has_version_registry() { + if [ -d /version/$1 ]; then + return 0; + else + return 1; + fi +} + +list_versions(){ + # List all subdirectories and then print only the file name + for version in /version/* ; do + text " ${version##*/}\n" + done +} + +version_error(){ + text "\nWe could not find version '$1'. Available versions:\n" + list_versions + text "\nSet CHE_VERSION= and rerun.\n\n" +} + +### Returns the list of ${CHE_FORMAL_PRODUCT_NAME} images for a particular version of ${CHE_FORMAL_PRODUCT_NAME} +### Sets the images as environment variables after loading from file +get_image_manifest() { + info "cli" "Checking registry for version '$1' images" + if ! has_version_registry $1; then + version_error $1 + return 1; + fi + + IMAGE_LIST=$(cat /version/$1/images) + IFS=$'\n' + for SINGLE_IMAGE in $IMAGE_LIST; do + log "eval $SINGLE_IMAGE" + eval $SINGLE_IMAGE + done +} + +get_installed_version() { + if ! is_initialized; then + echo "" + else + cat "${CHE_CONTAINER_INSTANCE}"/$CHE_VERSION_FILE + fi +} + +get_image_version() { + echo "$CHE_IMAGE_VERSION" +} + +less_than() { + for (( i=0; i<${#1}; i++ )); do + if [[ ${1:$i:1} != ${2:$i:1} ]]; then + if [ ${1:$i:1} -lt ${2:$i:1} ]; then + return 0 + else + return 1 + fi + fi + done + return 1 +} + +compare_cli_version_to_installed_version() { + IMAGE_VERSION=$(get_image_version) + INSTALLED_VERSION=$(get_installed_version) + + if [[ "$INSTALLED_VERSION" = "$IMAGE_VERSION" ]]; then + echo "match" + elif [ "$INSTALLED_VERSION" = "nightly" ] || + [ "$IMAGE_VERSION" = "nightly" ]; then + echo "nightly" + elif less_than $INSTALLED_VERSION $IMAGE_VERSION; then + echo "install-less-cli" + else + echo "cli-less-install" + fi +} + +verify_version_compatibility() { + + ## If ! is_initialized, then the system hasn't been installed + ## First, compare the CLI image version to what version was initialized in /config/*.ver.donotmodify + ## - If they match, good + ## - If they don't match and one is nightly, fail + ## - If they don't match, then if CLI is older fail with message to get proper CLI + ## - If they don't match, then if CLLI is newer fail with message to run upgrade first + + CHE_IMAGE_VERSION=$(get_image_version) + + if is_initialized; then + COMPARE_CLI_ENV=$(compare_cli_version_to_installed_version) + INSTALLED_VERSION=$(get_installed_version) + case "${COMPARE_CLI_ENV}" in + "match") + ;; + "nightly") + error "" + error "Your CLI version '${CHE_IMAGE_FULLNAME}' does not match your installed version '$INSTALLED_VERSION'." + error "" + error "The 'nightly' CLI is only compatible with 'nightly' installed versions." + error "You may not '${CHE_MINI_PRODUCT_NAME} upgrade' from 'nightly' to a numbered (tagged) version." + error "" + error "Run the CLI as '${CHE_IMAGE_NAME}:' to install a tagged version." + return 2 + ;; + "install-less-cli") + error "" + error "Your CLI version '${CHE_IMAGE_FULLNAME}' is newer than your installed version '$INSTALLED_VERSION'." + error "" + error "Run '${CHE_IMAGE_FULLNAME} upgrade' to migrate your installation to '$CHE_IMAGE_VERSION'." + error "Or, run the CLI with '${CHE_IMAGE_NAME}:$INSTALLED_VERSION' to match the CLI with your installed version." + return 2 + ;; + "cli-less-install") + error "" + error "Your CLI version '${CHE_IMAGE_FULLNAME}' is older than your installed version '$INSTALLED_VERSION'." + error "" + error "You cannot use an older CLI with a newer installation." + error "" + error "Run the CLI with '${CHE_IMAGE_NAME}:$INSTALLED_VERSION' to match the CLI with your existing installed version." + return 2 + ;; + esac + fi + + # Per request of the engineers, check to see if the locally cached nightly version is older + # than the one stored on DockerHub. + if [[ "${CHE_IMAGE_VERSION}" = "nightly" ]]; then + + REMOTE_NIGHTLY_JSON=$(curl -s https://hub.docker.com/v2/repositories/${CHE_IMAGE_NAME}/tags/nightly/) + + # Retrieve info on current nightly + LOCAL_CREATION_DATE=$(docker inspect --format="{{.Created }}" ${CHE_IMAGE_FULLNAME}) + REMOTE_CREATION_DATE=$(echo $REMOTE_NIGHTLY_JSON | jq ".last_updated") + REMOTE_CREATION_DATE="${REMOTE_CREATION_DATE//\"}" + + # Unfortunatley, the "last_updated" date on DockerHub is the date it was uploaded, not created. + # So after you download the image locally, then the local image "created" value reflects when it + # was originally built, creating a istuation where the local cached version is always older than + # what is on DockerHub, even if you just pulled it. + # Solution is to compare the dates, and only print warning message if the locally created ate + # is less than the updated date on dockerhub. + if $(less_than ${LOCAL_CREATION_DATE:8:2} ${REMOTE_CREATION_DATE:8:2}); then + warning "Your local ${CHE_IMAGE_FULLNAME} image is older than the version on DockerHub." + warning "Run 'docker pull ${CHE_IMAGE_FULLNAME}' to update your CLI." + fi + fi +} + +verify_version_upgrade_compatibility() { + ## Two levels of checks + ## First, compare the CLI image version to what the admin has configured in /config/.env file + ## - If they match, nothing to upgrade + ## - If they don't match and one is nightly, fail upgrade is not supported for nightly + ## - If they don't match, then if CLI is older fail with message that we do not support downgrade + ## - If they don't match, then if CLI is newer then good + CHE_IMAGE_VERSION=$(get_image_version) + + if ! is_initialized || ! is_configured; then + info "upgrade" "$CHE_MINI_PRODUCT_NAME is not installed or configured. Nothing to upgrade." + return 2 + fi + + if is_initialized; then + COMPARE_CLI_ENV=$(compare_cli_version_to_installed_version) + CONFIGURED_VERSION=$(get_installed_version) + + case "${COMPARE_CLI_ENV}" in + "match") + error "" + error "Your CLI version '${CHE_IMAGE_FULLNAME}' is identical to your installed version '$INSTALLED_VERSION'." + error "" + error "Run '${CHE_IMAGE_NAME}: upgrade' with a newer version to upgrade." + error "View available versions with '$CHE_FORMAL_PRODUCT_NAME version'." + return 2 + ;; + "nightly") + error "" + error "Your CLI version '${CHE_IMAGE_FULLNAME}' or installed version '$INSTALLED_VERSION' is nightly." + error "" + error "You may not '${CHE_IMAGE_NAME} upgrade' from 'nightly' to a numbered (tagged) version." + error "You can 'docker pull ${CHE_IMAGE_FULLNAME}' to get a newer nightly version." + return 2 + ;; + "install-less-cli") + ;; + "cli-less-install") + error "" + error "Your CLI version '${CHE_IMAGE_FULLNAME}' is older than your installed version '$INSTALLED_VERSION'." + error "" + error "You cannot use '${CHE_IMAGE_NAME} upgrade' to downgrade versions." + error "" + error "Run '${CHE_IMAGE_NAME}: upgrade' with a newer version to upgrade." + error "View available versions with '${CHE_IMAGE_NAME} version'." + return 2 + ;; + esac + fi +} + +# Usage: +# confirm_operation [--force|--no-force] +confirm_operation() { + debug $FUNCNAME + + FORCE_OPERATION=${2:-"--no-force"} + + if [ ! "${FORCE_OPERATION}" == "--quiet" ]; then + # Warn user with passed message + info "${1}" + text "\n" + read -p " Are you sure? [N/y] " -n 1 -r + text "\n\n" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + return 1; + else + return 0; + fi + fi +} + +port_open() { + debug $FUNCNAME + + docker run -d -p $1:$1 --name fake alpine:3.4 httpd -f -p $1 -h /etc/ > /dev/null 2>&1 + NETSTAT_EXIT=$? + docker rm -f fake > /dev/null 2>&1 + + if [ $NETSTAT_EXIT = 125 ]; then + return 1 + else + return 0 + fi +} + +server_is_booted_extra_check() { + true +} + +wait_until_server_is_booted() { + SERVER_BOOT_TIMEOUT=${1} + + ELAPSED=0 + until server_is_booted ${2} || [ ${ELAPSED} -eq "${SERVER_BOOT_TIMEOUT}" ]; do + log "sleep 2" + sleep 2 + server_is_booted_extra_check + ELAPSED=$((ELAPSED+1)) + done +} \ No newline at end of file diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_action.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_action.sh new file mode 100644 index 00000000000..8f5b3a2d0f7 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_action.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_action() { + debug $FUNCNAME + + if container_exist_by_name $CHE_SERVER_CONTAINER_NAME; then + CURRENT_CHE_SERVER_CONTAINER_ID=$(get_server_container_id $CHE_SERVER_CONTAINER_NAME) + if container_is_running ${CURRENT_CHE_SERVER_CONTAINER_ID} && \ + server_is_booted ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + + # Not loaded as part of the init process to save on download time + update_image_if_not_found eclipse/che-action:nightly + docker_run eclipse/che-action:nightly "$@" + + return + fi + fi + + info "action" "The system is not running." +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_backup.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_backup.sh new file mode 100644 index 00000000000..a5a6f020c7a --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_backup.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_backup() { + debug $FUNCNAME + + # possibility to skip ${CHE_FORMAL_PRODUCT_NAME} projects backup + SKIP_BACKUP_CHE_DATA=${1:-"--no-skip-data"} + if [[ "${SKIP_BACKUP_CHE_DATA}" == "--skip-data" ]]; then + TAR_EXTRA_EXCLUDE="--exclude=instance/data${CHE_CONTAINER_ROOT}" + else + TAR_EXTRA_EXCLUDE="" + fi + + if [[ ! -d "${CHE_CONTAINER_CONFIG}" ]]; then + error "Cannot find existing CHE_CONFIG or CHE_INSTANCE." + return; + fi + + if get_server_container_id "${CHE_SERVER_CONTAINER_NAME}" >> "${LOGS}" 2>&1; then + error "$CHE_MINI_PRODUCT_NAME is running. Stop before performing a backup." + return 2; + fi + + if [[ ! -d "${CHE_CONTAINER_BACKUP}" ]]; then + mkdir -p "${CHE_CONTAINER_BACKUP}" + fi + + # check if backups already exist and if so we move it with time stamp in name + if [[ -f "${CHE_CONTAINER_BACKUP}/${CHE_BACKUP_FILE_NAME}" ]]; then + mv "${CHE_CONTAINER_BACKUP}/${CHE_BACKUP_FILE_NAME}" \ + "${CHE_CONTAINER_BACKUP}/moved-$(get_current_date)-${CHE_BACKUP_FILE_NAME}" + fi + + info "backup" "Saving codenvy data..." + docker_run -v "${CHE_HOST_CONFIG}":/root${CHE_CONTAINER_ROOT} \ + -v "${CHE_HOST_BACKUP}":/root/backup \ + $(cmd_backup_extra_args) \ + alpine:3.4 sh -c "tar czf /root/backup/${CHE_BACKUP_FILE_NAME} -C /root${CHE_CONTAINER_ROOT} . --exclude='backup' --exclude='instance/dev' --exclude='instance/logs' ${TAR_EXTRA_EXCLUDE}" + info "" + info "backup" "Codenvy data saved in ${CHE_HOST_BACKUP}/${CHE_BACKUP_FILE_NAME}" +} + +cmd_backup_extra_args() { + echo "" +} + +# return date in format which can be used as a unique file or dir name +# example 2016-10-31-1477931458 +get_current_date() { + date +'%Y-%m-%d-%s' +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_config.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_config.sh new file mode 100644 index 00000000000..2ab17a13b3f --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_config.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_config_post_action() { + true +} + +cmd_config() { + + # If the system is not initialized, initalize it. + # If the system is already initialized, but a user wants to update images, then re-download. + FORCE_UPDATE=${1:-"--no-force"} + if ! is_initialized; then + cmd_init $FORCE_UPDATE + elif [[ "${FORCE_UPDATE}" == "--pull" ]] || \ + [[ "${FORCE_UPDATE}" == "--force" ]]; then + cmd_download $FORCE_UPDATE + fi + + if [ -z ${IMAGE_PUPPET+x} ]; then + get_image_manifest $CHE_VERSION + fi + + # Development mode + if [ "${CHE_DEVELOPMENT_MODE}" = "on" ]; then + # if dev mode is on, pick configuration sources from repo. + # please note that in production mode update of configuration sources must be only on update. + docker_run -v "${CHE_HOST_CONFIG}":/copy \ + -v "${CHE_HOST_DEVELOPMENT_REPO}"/dockerfiles/init:/files \ + $IMAGE_INIT + + # in development mode to avoid permissions issues we copy tomcat assembly to ${CHE_INSTANCE} + # if ${CHE_FORMAL_PRODUCT_NAME} development tomcat exist we remove it + if [[ -d "${CHE_CONTAINER_INSTANCE}/dev" ]]; then + log "docker_run -v \"${CHE_HOST_INSTANCE}/dev\":/root/dev alpine:3.4 sh -c \"rm -rf /root/dev/*\"" + docker_run -v "${CHE_HOST_INSTANCE}/dev":/root/dev alpine:3.4 sh -c "rm -rf /root/dev/*" + log "rm -rf \"${CHE_HOST_INSTANCE}/dev\" >> \"${LOGS}\"" + rm -rf "${CHE_CONTAINER_INSTANCE}/dev" + fi + # copy ${CHE_FORMAL_PRODUCT_NAME} development tomcat to ${CHE_INSTANCE} folder + cp -r "$(echo $CHE_CONTAINER_DEVELOPMENT_REPO/$CHE_ASSEMBLY_IN_REPO)" \ + "${CHE_CONTAINER_INSTANCE}/dev" + fi + + info "config" "Generating $CHE_MINI_PRODUCT_NAME configuration..." + # Run the docker configurator + generate_configuration_with_puppet + + # Replace certain environment file lines with their container counterparts + info "config" "Customizing docker-compose for running in a container" + + # Write the installed version to the *.ver file into the instance folder + echo "$CHE_VERSION" > "${CHE_CONTAINER_INSTANCE}/${CHE_VERSION_FILE}" + + cmd_config_post_action + +} + + +# Runs puppet image to generate che configuration +generate_configuration_with_puppet() { + debug $FUNCNAME + + if is_docker_for_windows; then + CHE_ENV_FILE=$(convert_posix_to_windows "${CHE_HOST_INSTANCE}/config/$CHE_MINI_PRODUCT_NAME.env") + else + CHE_ENV_FILE="${CHE_HOST_INSTANCE}/config/$CHE_MINI_PRODUCT_NAME.env" + fi + + if [ "${CHE_DEVELOPMENT_MODE}" = "on" ]; then + # Note - bug in docker requires relative path for env, not absolute + GENERATE_CONFIG_COMMAND="docker_run -it \ + --env-file=\"${REFERENCE_CONTAINER_ENVIRONMENT_FILE}\" \ + --env-file=/version/$CHE_VERSION/images \ + -v \"${CHE_HOST_INSTANCE}\":/opt/${CHE_MINI_PRODUCT_NAME}:rw \ + -v \"${CHE_HOST_DEVELOPMENT_REPO}/dockerfiles/init/manifests\":/etc/puppet/manifests:ro \ + -v \"${CHE_HOST_DEVELOPMENT_REPO}/dockerfiles/init/modules\":/etc/puppet/modules:ro \ + -e \"CHE_ENV_FILE=${CHE_ENV_FILE}\" \ + -e \"CHE_ENVIRONMENT=development\" \ + -e \"CHE_CONFIG=${CHE_HOST_INSTANCE}\" \ + -e \"CHE_INSTANCE=${CHE_HOST_INSTANCE}\" \ + -e \"CHE_DEVELOPMENT_REPO=${CHE_HOST_DEVELOPMENT_REPO}\" \ + -e \"CHE_ASSEMBLY=${CHE_ASSEMBLY}\" \ + --entrypoint=/usr/bin/puppet \ + $IMAGE_INIT \ + apply --modulepath \ + /etc/puppet/modules/ \ + /etc/puppet/manifests/${CHE_MINI_PRODUCT_NAME}.pp --show_diff" + else + GENERATE_CONFIG_COMMAND="docker_run -it \ + --env-file=\"${REFERENCE_CONTAINER_ENVIRONMENT_FILE}\" \ + --env-file=/version/$CHE_VERSION/images \ + -v \"${CHE_HOST_INSTANCE}\":/opt/${CHE_MINI_PRODUCT_NAME}:rw \ + -e \"CHE_ENV_FILE=${CHE_ENV_FILE}\" \ + -e \"CHE_ENVIRONMENT=production\" \ + -e \"CHE_CONFIG=${CHE_HOST_INSTANCE}\" \ + -e \"CHE_INSTANCE=${CHE_HOST_INSTANCE}\" \ + --entrypoint=/usr/bin/puppet \ + $IMAGE_INIT \ + apply --modulepath \ + /etc/puppet/modules/ \ + /etc/puppet/manifests/${CHE_MINI_PRODUCT_NAME}.pp --show_diff >> \"${LOGS}\"" + fi + + log ${GENERATE_CONFIG_COMMAND} + eval ${GENERATE_CONFIG_COMMAND} +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_debug.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_debug.sh new file mode 100644 index 00000000000..c66b4f1702f --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_debug.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_debug() { + debug $FUNCNAME + info "---------------------------------------" + info "------------ CLI INFO -------------" + info "---------------------------------------" + info "" + info "----------- ${CHE_PRODUCT_NAME} INFO ------------" + info "${CHE_PRODUCT_NAME}_VERSION = ${CHE_VERSION}" + info "${CHE_PRODUCT_NAME}_INSTANCE = ${CHE_HOST_INSTANCE}" + info "${CHE_PRODUCT_NAME}_CONFIG = ${CHE_HOST_CONFIG}" + info "${CHE_PRODUCT_NAME}_HOST = ${CHE_HOST}" + info "${CHE_PRODUCT_NAME}_REGISTRY = ${CHE_MANIFEST_DIR}" + info "${CHE_PRODUCT_NAME}_DEVELOPMENT_MODE = ${CHE_DEVELOPMENT_MODE}" + if [ "${CHE_DEVELOPMENT_MODE}" = "on" ]; then + info "${CHE_PRODUCT_NAME}_DEVELOPMENT_REPO = ${CHE_HOST_DEVELOPMENT_REPO}" + fi + info "${CHE_PRODUCT_NAME}_BACKUP = ${CHE_HOST_BACKUP}" + info "" + info "----------- PLATFORM INFO -----------" + info "DOCKER_INSTALL_TYPE = $(get_docker_install_type)" + info "IS_NATIVE = $(is_native && echo "YES" || echo "NO")" + info "IS_WINDOWS = $(has_docker_for_windows_client && echo "YES" || echo "NO")" + info "IS_DOCKER_FOR_WINDOWS = $(is_docker_for_windows && echo "YES" || echo "NO")" + info "HAS_DOCKER_FOR_WINDOWS_IP = $(has_docker_for_windows_client && echo "YES" || echo "NO")" + info "IS_DOCKER_FOR_MAC = $(is_docker_for_mac && echo "YES" || echo "NO")" + info "IS_BOOT2DOCKER = $(is_boot2docker && echo "YES" || echo "NO")" + info "" +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_destroy.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_destroy.sh new file mode 100644 index 00000000000..08ed73af2cf --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_destroy.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + + +cmd_destroy_post_action() { + true +} + +cmd_destroy() { + debug $FUNCNAME + + QUIET="" + DESTROY_CLI="false" + + while [ $# -gt 0 ]; do + case $1 in + --quiet) + QUIET="--quiet" + shift ;; + --cli) + DESTROY_CLI="true" + shift ;; + *) error "Unknown parameter: $1" ; return 2 ;; + esac + done + + WARNING="destroy !!! Stopping services and !!! deleting data !!! this is unrecoverable !!!" + if ! confirm_operation "${WARNING}" "${QUIET}"; then + return; + fi + + cmd_stop + + info "destroy" "Deleting instance and config..." + + log "docker_run -v \"${CHE_HOST_CONFIG}\":${CHE_CONTAINER_ROOT} \ + alpine:3.4 sh -c \"rm -rf /root${CHE_CONTAINER_ROOT}/docs \ + && rm -rf /root${CHE_CONTAINER_ROOT}/instance \ + && rm -rf /root${CHE_CONTAINER_ROOT}/${CHE_MINI_PRODUCT_NAME}.env\"" + + docker_run -v "${CHE_HOST_CONFIG}":/root${CHE_CONTAINER_ROOT} \ + alpine:3.4 sh -c "rm -rf /root${CHE_CONTAINER_ROOT}/docs \ + && rm -rf /root${CHE_CONTAINER_ROOT}/instance \ + && rm -rf /root${CHE_CONTAINER_ROOT}/${CHE_MINI_PRODUCT_NAME}.env" > /dev/null 2>&1 || true + + # Super weird bug. For some reason on windows, this command has to be run 3x for everything + # to be destroyed properly if you are in dev mode. + if has_docker_for_windows_client; then + if [[ "${CHE_DEVELOPMENT_MODE}" = "on" ]]; then + docker_run -v "${CHE_HOST_CONFIG}":/root${CHE_CONTAINER_ROOT} \ + alpine:3.4 sh -c "rm -rf /root${CHE_CONTAINER_ROOT}/docs \ + && rm -rf /root${CHE_CONTAINER_ROOT}/instance \ + && rm -rf /root${CHE_CONTAINER_ROOT}/${CHE_MINI_PRODUCT_NAME}.env" > /dev/null 2>&1 || true + docker_run -v "${CHE_HOST_CONFIG}":/root${CHE_CONTAINER_ROOT} \ + alpine:3.4 sh -c "rm -rf /root${CHE_CONTAINER_ROOT}/docs \ + && rm -rf /root${CHE_CONTAINER_ROOT}/instance \ + && rm -rf /root${CHE_CONTAINER_ROOT}/${CHE_MINI_PRODUCT_NAME}.env" > /dev/null 2>&1 || true + fi + fi + + rm -rf "${CHE_CONTAINER_INSTANCE}" + + cmd_destroy_post_action + + # Sometimes users want the CLI after they have destroyed their instance + # If they pass destroy --cli then we will also destroy the CLI + if [[ "${DESTROY_CLI}" = "true" ]]; then + if [[ "${CLI_MOUNT}" = "not set" ]]; then + info "destroy" "Did not delete cli.log - ':/cli' not mounted" + else + info "destroy" "Deleting cli.log..." + docker_run -v "${CLI_MOUNT}":/root/cli alpine:3.4 sh -c "rm -rf /root/cli/cli.log" + fi + fi +} + diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_download.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_download.sh new file mode 100644 index 00000000000..b355ca4496b --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_download.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_download() { + FORCE_UPDATE=${1:-"--no-force"} + + get_image_manifest $CHE_VERSION + + IFS=$'\n' + for SINGLE_IMAGE in $IMAGE_LIST; do + VALUE_IMAGE=$(echo $SINGLE_IMAGE | cut -d'=' -f2) + if [[ $FORCE_UPDATE == "--force" ]] || + [[ $FORCE_UPDATE == "--pull" ]]; then + update_image $FORCE_UPDATE $VALUE_IMAGE + else + update_image_if_not_found $VALUE_IMAGE + fi + done +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_help.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_help.sh new file mode 100644 index 00000000000..d6e0fa81738 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_help.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_help() { + usage +} + diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_info.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_info.sh new file mode 100644 index 00000000000..cb69f3c2e3e --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_info.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_info() { + debug $FUNCNAME + if [ $# -eq 0 ]; then + TESTS="--debug" + else + TESTS=$1 + fi + + case $TESTS in + --all|-all) + cmd_debug + cmd_network + ;; + --network|-network) + cmd_network + ;; + --debug|-debug) + cmd_debug + ;; + *) + info "info" "Unknown info flag passed: $1." + return; + ;; + esac +} + diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_init.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_init.sh new file mode 100644 index 00000000000..30044b70488 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_init.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_init() { + + # set an initial value for the flag + FORCE_UPDATE="--no-force" + AUTO_ACCEPT_LICENSE="false" + REINIT="false" + + while [ $# -gt 0 ]; do + case $1 in + --no-force|--force|--pull|--offline) + FORCE_UPDATE=$1 + shift ;; + --accept-license) + AUTO_ACCEPT_LICENSE="true" + shift ;; + --reinit) + REINIT="true" + shift ;; + *) error "Unknown parameter: $1" ; return 2 ;; + esac + done + + if [ "${FORCE_UPDATE}" == "--no-force" ]; then + # If ${CHE_FORMAL_PRODUCT_NAME}.environment file exists, then fail + if is_initialized; then + if [[ "${REINIT}" = "false" ]]; then + info "init" "Already initialized." + return 2 + fi + fi + fi + + if [[ "${CHE_IMAGE_VERSION}" = "nightly" ]]; then + warning "($CHE_MINI_PRODUCT_NAME init): 'nightly' installations cannot be upgraded to non-nightly versions" + fi + + cmd_download $FORCE_UPDATE + + if [ -z ${IMAGE_INIT+x} ]; then + get_image_manifest $CHE_VERSION + fi + + if require_license; then + if [[ "${AUTO_ACCEPT_LICENSE}" = "false" ]]; then + info "" + info "init" "Do you accept the ${CHE_FORMAL_PRODUCT_NAME} license? (${CHE_LICENSE_URL})" + text "\n" + read -p " I accept the license: [Y/n] " -n 1 -r + text "\n" + if [[ $REPLY =~ ^[Nn]$ ]]; then + return 2; + fi + fi + fi + + info "init" "Installing configuration and bootstrap variables:" + log "mkdir -p \"${CHE_CONTAINER_CONFIG}\"" + mkdir -p "${CHE_CONTAINER_CONFIG}" + log "mkdir -p \"${CHE_CONTAINER_INSTANCE}\"" + mkdir -p "${CHE_CONTAINER_INSTANCE}" + + if [ ! -w "${CHE_CONTAINER_CONFIG}" ]; then + error "CHE_CONTAINER_CONFIG is not writable. Aborting." + return 1; + fi + + if [ ! -w "${CHE_CONTAINER_INSTANCE}" ]; then + error "CHE_CONTAINER_INSTANCE is not writable. Aborting." + return 1; + fi + + # in development mode we use init files from repo otherwise we use it from docker image + if [ "${CHE_DEVELOPMENT_MODE}" = "on" ]; then + docker_run -v "${CHE_HOST_CONFIG}":/copy \ + -v "${CHE_HOST_DEVELOPMENT_REPO}"/dockerfiles/init:/files \ + -v "${CHE_HOST_DEVELOPMENT_REPO}"/dockerfiles/init/manifests/${CHE_MINI_PRODUCT_NAME}.env:/etc/puppet/manifests/${CHE_MINI_PRODUCT_NAME}.env \ + $IMAGE_INIT + else + docker_run -v "${CHE_HOST_CONFIG}":/copy $IMAGE_INIT + fi + + # If this is is a reinit, we should not overwrite these core template files. + # If this is an initial init, then we have to override some values + if [[ "${REINIT}" = "false" ]]; then + # Otherwise, we are using the templated version and making some modifications. + cmd_init_reinit_pre_action + rm -rf "${REFERENCE_CONTAINER_ENVIRONMENT_FILE}".bak > /dev/null 2>&1 + + info "init" " ${CHE_PRODUCT_NAME}_HOST=${CHE_HOST}" + info "init" " ${CHE_PRODUCT_NAME}_VERSION=${CHE_VERSION}" + info "init" " ${CHE_PRODUCT_NAME}_CONFIG=${CHE_HOST_CONFIG}" + info "init" " ${CHE_PRODUCT_NAME}_INSTANCE=${CHE_HOST_INSTANCE}" + if [ "${CHE_DEVELOPMENT_MODE}" == "on" ]; then + info "init" " ${CHE_PRODUCT_NAME}_ENVIRONMENT=development" + info "init" " ${CHE_PRODUCT_NAME}_DEVELOPMENT_REPO=${CHE_HOST_DEVELOPMENT_REPO}" + info "init" " ${CHE_PRODUCT_NAME}_ASSEMBLY=${CHE_ASSEMBLY}" + else + info "init" " ${CHE_PRODUCT_NAME}_ENVIRONMENT=production" + fi + fi + + # Encode the version that we initialized into the version file + echo "$CHE_VERSION" > "${CHE_CONTAINER_INSTANCE}/${CHE_VERSION_FILE}" +} + + +require_license() { + if [[ "${CHE_LICENSE}" = "true" ]]; then + return 0 + else + return 1 + fi +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_network.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_network.sh new file mode 100644 index 00000000000..238039c3021 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_network.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_network() { + debug $FUNCNAME + + if [ -z ${IMAGE_PUPPET+x} ]; then + get_image_manifest $CHE_VERSION + fi + + info "" + info "---------------------------------------" + info "-------- CONNECTIVITY TEST --------" + info "---------------------------------------" + # Start a fake workspace agent + log "docker run -d -p 12345:80 --name fakeagent alpine:3.4 httpd -f -p 80 -h /etc/ >> \"${LOGS}\"" + docker run -d -p 12345:80 --name fakeagent alpine:3.4 httpd -f -p 80 -h /etc/ >> "${LOGS}" + + AGENT_INTERNAL_IP=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' fakeagent) + AGENT_INTERNAL_PORT=80 + AGENT_EXTERNAL_IP=$CHE_HOST + AGENT_EXTERNAL_PORT=12345 + + + ### TEST 1: Simulate browser ==> workspace agent HTTP connectivity + HTTP_CODE=$(curl -I localhost:${AGENT_EXTERNAL_PORT}/alpine-release \ + -s -o "${LOGS}" --connect-timeout 5 \ + --write-out "%{http_code}") || echo "28" >> "${LOGS}" + + if [ "${HTTP_CODE}" = "200" ]; then + info "Browser => Workspace Agent (localhost): Connection succeeded" + else + info "Browser => Workspace Agent (localhost): Connection failed" + fi + + ### TEST 1a: Simulate browser ==> workspace agent HTTP connectivity + HTTP_CODE=$(curl -I ${AGENT_EXTERNAL_IP}:${AGENT_EXTERNAL_PORT}/alpine-release \ + -s -o "${LOGS}" --connect-timeout 5 \ + --write-out "%{http_code}") || echo "28" >> "${LOGS}" + + if [ "${HTTP_CODE}" = "200" ]; then + info "Browser => Workspace Agent ($AGENT_EXTERNAL_IP): Connection succeeded" + else + info "Browser => Workspace Agent ($AGENT_EXTERNAL_IP): Connection failed" + fi + + ### TEST 2: Simulate Che server ==> workspace agent (external IP) connectivity + export HTTP_CODE=$(docker_run --name fakeserver \ + --entrypoint=curl \ + ${IMAGE_CODENVY} \ + -I ${AGENT_EXTERNAL_IP}:${AGENT_EXTERNAL_PORT}/alpine-release \ + -s -o "${LOGS}" \ + --write-out "%{http_code}") + + if [ "${HTTP_CODE}" = "200" ]; then + info "Server => Workspace Agent (External IP): Connection succeeded" + else + info "Server => Workspace Agent (External IP): Connection failed" + fi + + ### TEST 3: Simulate Che server ==> workspace agent (internal IP) connectivity + export HTTP_CODE=$(docker_run --name fakeserver \ + --entrypoint=curl \ + ${IMAGE_CODENVY} \ + -I ${AGENT_INTERNAL_IP}:${AGENT_INTERNAL_PORT}/alpine-release \ + -s -o "${LOGS}" \ + --write-out "%{http_code}") + + if [ "${HTTP_CODE}" = "200" ]; then + info "Server => Workspace Agent (Internal IP): Connection succeeded" + else + info "Server => Workspace Agent (Internal IP): Connection failed" + fi + + log "docker rm -f fakeagent >> \"${LOGS}\"" + docker rm -f fakeagent >> "${LOGS}" +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_offline.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_offline.sh new file mode 100644 index 00000000000..8d97b332cc3 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_offline.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_offline() { + info "offline" "Grabbing image manifest for version '$CHE_VERSION'" + if ! has_version_registry $CHE_VERSION; then + version_error $CHE_VERSION + return 1; + fi + + # Make sure the images have been pulled and are in your local Docker registry + cmd_download + + mkdir -p $CHE_CONTAINER_OFFLINE_FOLDER + + IMAGE_LIST=$(cat "$CHE_MANIFEST_DIR"/$CHE_VERSION/images) + IFS=$'\n' + info "offline" "Saving ${CHE_MINI_PRODUCT_NAME} Docker images as tar files..." + + for SINGLE_IMAGE in $IMAGE_LIST; do + VALUE_IMAGE=$(echo $SINGLE_IMAGE | cut -d'=' -f2) + TAR_NAME=$(echo $VALUE_IMAGE | sed "s|\/|_|") + info "offline" "Saving $CHE_HOST_BACKUP/$TAR_NAME.tar..." + if ! $(docker save $VALUE_IMAGE > $CHE_CONTAINER_OFFLINE_FOLDER/$TAR_NAME.tar); then + error "Docker was interrupted while saving $CHE_CONTAINER_OFFLINE_FOLDER/$TAR_NAME.tar" + return 1; + fi + done + + info "offline" "Done!" +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_restore.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_restore.sh new file mode 100644 index 00000000000..bcfa067d5ec --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_restore.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_restore_pre_action() { + true +} + +cmd_restore_extra_args() { + echo "" +} + +cmd_restore() { + debug $FUNCNAME + + if [[ -d "${CHE_CONTAINER_CONFIG}" ]]; then + WARNING="Restoration overwrites existing configuration and data. Are you sure?" + if ! confirm_operation "${WARNING}" "$@"; then + return; + fi + fi + + if get_server_container_id "${CHE_SERVER_CONTAINER_NAME}" >> "${LOGS}" 2>&1; then + error "${CHE_FORMAL_PRODUCT_NAME} is running. Stop before performing a restore. Aborting" + return; + fi + + if [[ ! -f "${CHE_CONTAINER_BACKUP}/${CHE_BACKUP_FILE_NAME}" ]]; then + error "Backup files not found. To do restore please do backup first." + return; + fi + + # remove config and instance folders + log "docker_run -v \"${CHE_HOST_CONFIG}\":${CHE_CONTAINER_ROOT} \ + alpine:3.4 sh -c \"rm -rf /root${CHE_CONTAINER_ROOT}/docs \ + && rm -rf /root${CHE_CONTAINER_ROOT}/instance \ + && rm -rf /root${CHE_CONTAINER_ROOT}/${CHE_MINI_PRODUCT_NAME}.env\"" + docker_run -v "${CHE_HOST_CONFIG}":/root${CHE_CONTAINER_ROOT} \ + alpine:3.4 sh -c "rm -rf /root${CHE_CONTAINER_ROOT}/docs \ + && rm -rf /root${CHE_CONTAINER_ROOT}/instance \ + && rm -rf /root${CHE_CONTAINER_ROOT}/${CHE_MINI_PRODUCT_NAME}.env" + + info "restore" "Recovering ${CHE_FORMAL_PRODUCT_NAME} data..." + + cmd_restore_pre_action + + docker_run -v "${CHE_HOST_CONFIG}":/root${CHE_CONTAINER_ROOT} \ + -v "${CHE_HOST_BACKUP}/${CHE_BACKUP_FILE_NAME}":"/root/backup/${CHE_BACKUP_FILE_NAME}" \ + $(cmd_restore_extra_args) \ + alpine:3.4 sh -c "tar xf /root/backup/${CHE_BACKUP_FILE_NAME} -C /root${CHE_CONTAINER_ROOT}" +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_rmi.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_rmi.sh new file mode 100644 index 00000000000..ba82fce807c --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_rmi.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_rmi() { + info "rmi" "Checking registry for version '$CHE_VERSION' images" + if ! has_version_registry $CHE_VERSION; then + version_error $CHE_VERSION + return 1; + fi + + WARNING="rmi !!! Removing images disables ${CHE_FORMAL_PRODUCT_NAME} and forces a pull !!!" + if ! confirm_operation "${WARNING}" "$@"; then + return; + fi + + IMAGE_LIST=$(cat "$CHE_MANIFEST_DIR"/$CHE_VERSION/images) + IFS=$'\n' + info "rmi" "Removing ${CHE_MINI_PRODUCT_NAME} Docker images..." + + for SINGLE_IMAGE in $IMAGE_LIST; do + VALUE_IMAGE=$(echo $SINGLE_IMAGE | cut -d'=' -f2) + info "rmi" "Removing $VALUE_IMAGE..." + log "docker rmi -f ${VALUE_IMAGE} >> \"${LOGS}\" 2>&1 || true" + docker rmi -f $VALUE_IMAGE >> "${LOGS}" 2>&1 || true + done +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_ssh.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_ssh.sh new file mode 100644 index 00000000000..2dadcae17c0 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_ssh.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_ssh() { + debug $FUNCNAME + cmd_action "workspace-ssh" "$@" +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_start.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_start.sh new file mode 100644 index 00000000000..cca9de5f9c2 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_start.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_start() { + debug $FUNCNAME + + DISPLAY_URL=$(get_display_url) + + # If ${CHE_FORMAL_PRODUCT_NAME} is already started or booted, then terminate early. + if container_exist_by_name $CHE_SERVER_CONTAINER_NAME; then + CURRENT_CHE_SERVER_CONTAINER_ID=$(get_server_container_id $CHE_SERVER_CONTAINER_NAME) + if container_is_running ${CURRENT_CHE_SERVER_CONTAINER_ID} && \ + server_is_booted ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + info "start" "${CHE_FORMAL_PRODUCT_NAME} is already running" + info "start" "Server logs at \"docker logs -f ${CHE_SERVER_CONTAINER_NAME}\"" + info "start" "Ver: $(get_installed_version)" + info "start" "Use: ${DISPLAY_URL}" + info "start" "API: ${DISPLAY_URL}/swagger" + return + fi + fi + + # To protect users from accidentally updating their ${CHE_FORMAL_PRODUCT_NAME} servers when they didn't mean + # to, which can happen if CHE_VERSION=latest + FORCE_UPDATE=${1:-"--no-force"} + # Always regenerate puppet configuration from environment variable source, whether changed or not. + # If the current directory is not configured with an .env file, it will initialize + cmd_config $FORCE_UPDATE + + # Begin tests of open ports that we require + info "start" "Preflight checks" + cmd_start_check_ports + text "\n" + + # Start ${CHE_FORMAL_PRODUCT_NAME} + # Note bug in docker requires relative path, not absolute path to compose file + info "start" "Starting containers..." + COMPOSE_UP_COMMAND="docker_compose --file=\"${REFERENCE_CONTAINER_COMPOSE_FILE}\" -p=\"${CHE_MINI_PRODUCT_NAME}\" up -d" + + if [ "${CHE_DEVELOPMENT_MODE}" != "on" ]; then + COMPOSE_UP_COMMAND+=" >> \"${LOGS}\" 2>&1" + fi + + log ${COMPOSE_UP_COMMAND} + eval ${COMPOSE_UP_COMMAND} + check_if_booted +} + + +cmd_start_check_ports() { + text " port ${CHE_PORT} (http): $(port_open ${CHE_PORT} && echo "${GREEN}[AVAILABLE]${NC}" || echo "${RED}[ALREADY IN USE]${NC}") \n" + if ! $(port_open ${CHE_PORT}); then + echo "" + error "Ports required to run $CHE_MINI_PRODUCT_NAME are used by another program." + return 1; + fi +} + +cmd_stop() { + debug $FUNCNAME + + if [ $# -gt 0 ]; then + error "${CHE_MINI_PRODUCT_NAME} stop: You passed unknown options. Aborting." + return + fi + + info "stop" "Stopping containers..." + if is_initialized; then + log "docker_compose --file=\"${REFERENCE_CONTAINER_COMPOSE_FILE}\" -p=$CHE_MINI_PRODUCT_NAME stop -t ${CHE_COMPOSE_STOP_TIMEOUT} >> \"${LOGS}\" 2>&1 || true" + docker_compose --file="${REFERENCE_CONTAINER_COMPOSE_FILE}" \ + -p=$CHE_MINI_PRODUCT_NAME stop -t ${CHE_COMPOSE_STOP_TIMEOUT} >> "${LOGS}" 2>&1 || true + info "stop" "Removing containers..." + log "docker_compose --file=\"${REFERENCE_CONTAINER_COMPOSE_FILE}\" -p=$CHE_MINI_PRODUCT_NAME rm >> \"${LOGS}\" 2>&1 || true" + docker_compose --file="${REFERENCE_CONTAINER_COMPOSE_FILE}" \ + -p=$CHE_MINI_PRODUCT_NAME rm --force >> "${LOGS}" 2>&1 || true + fi +} + +cmd_restart() { + debug $FUNCNAME + + FORCE_UPDATE=${1:-"--no-force"} + info "restart" "Restarting..." + cmd_stop + cmd_start ${FORCE_UPDATE} +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_sync.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_sync.sh new file mode 100644 index 00000000000..5162fc062ef --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_sync.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_sync() { + debug $FUNCNAME + + # Determine the mount path to do the mount + info "mount" "Starting sync process to ${SYNC_MOUNT}" + + # TODO: How to take connection parameters for Codenvy? + + # Only volume mount the unison profile if it is set + if [[ "${UNISON_PROFILE_MOUNT}" = "not set" ]]; then + docker_run --cap-add SYS_ADMIN \ + --device /dev/fuse \ + --name che-mount \ + -v ${HOME}/.ssh:${HOME}/.ssh \ + -v /etc/group:/etc/group:ro \ + -v /etc/passwd:/etc/passwd:ro \ + -u $(id -u ${USER}) \ + -v "${UNISON_PROFILE_MOUNT}":/profile \ + -v "${SYNC_MOUNT}":/mnthost \ + eclipse/che-mount:nightly $* + + else + + docker_run --cap-add SYS_ADMIN \ + --device /dev/fuse \ + --name che-mount \ + -v ${HOME}/.ssh:${HOME}/.ssh \ + -v /etc/group:/etc/group:ro \ + -v /etc/passwd:/etc/passwd:ro \ + -u $(id -u ${USER}) \ + -v "${SYNC_MOUNT}":/mnthost \ + eclipse/che-mount:nightly $* + + fi + + # Docker doesn't seem to normally clean up this container + docker rm -f che-mount + +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_upgrade.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_upgrade.sh new file mode 100644 index 00000000000..472b96117d0 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_upgrade.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_upgrade() { + debug $FUNCNAME + + CHE_IMAGE_VERSION=$(get_image_version) + + # If we got here, this means: + # image version > configured & installed version + # configured version = installed version + # + # We can now upgrade using the information contained in the CLI image + + ## Download version images + info "upgrade" "Downloading $CHE_MINI_PRODUCT_NAME images for version $CHE_IMAGE_VERSION..." + get_image_manifest $CHE_IMAGE_VERSION + SAVEIFS=$IFS + IFS=$'\n' + for SINGLE_IMAGE in ${IMAGE_LIST}; do + VALUE_IMAGE=$(echo ${SINGLE_IMAGE} | cut -d'=' -f2) + update_image_if_not_found ${VALUE_IMAGE} + done + IFS=$SAVEIFS + info "upgrade" "Downloading done." + + if get_server_container_id "${CHE_SERVER_CONTAINER_NAME}" >> "${LOGS}" 2>&1; then + info "upgrade" "Stopping currently running instance..." + CURRENT_CHE_SERVER_CONTAINER_ID=$(get_server_container_id ${CHE_SERVER_CONTAINER_NAME}) + if server_is_booted ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + cmd_stop + fi + fi + info "upgrade" "Preparing backup..." + cmd_backup + + info "upgrade" "Reinitializing the system with your configuration..." + cmd_init --accept-license --reinit + + cmd_start +} diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_version.sh b/dockerfiles/base-cli/scripts/base/commands/cmd_version.sh new file mode 100644 index 00000000000..75886771ebc --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/commands/cmd_version.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cmd_version() { + debug $FUNCNAME + + # Do not perform any logging in this method as it is runnable before the system is bootstrap + echo "" + text "Your CLI version is '%s'.\n" $(get_image_version) + if is_initialized; then + text "Your installed version is '%s'.\n" $(get_installed_version) + else + text "Your installed version is ''.\n" + fi + text "Available on DockerHub:\n" + VERSION_LIST_JSON=$(curl -s https://hub.docker.com/v2/repositories/${CHE_IMAGE_NAME}/tags/) + NUMBER_OF_VERSIONS=$(echo $VERSION_LIST_JSON | jq '.count') + COUNTER=0 + while [ $COUNTER -lt $NUMBER_OF_VERSIONS ]; do + TAG=$(echo $VERSION_LIST_JSON | jq ".results[$COUNTER].name") +# DATE=$(echo $VERSION_LIST_JSON | jq ".results[$COUNTER].last_updated") +# DATE=${DATE:0:10} +# text "${DATE//\"} ${TAG//\"}\n" + text " ${TAG//\"}\n" + let COUNTER=COUNTER+1 + done +} diff --git a/dockerfiles/base-cli/scripts/base/curl.sh b/dockerfiles/base-cli/scripts/base/curl.sh new file mode 100644 index 00000000000..01070b4a37b --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/curl.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +# Contains curl scripts + +has_curl() { + hash curl 2>/dev/null && return 0 || return 1 +} + +curl() { + if ! has_curl; then + log "docker run --rm --net=host appropriate/curl \"$@\"" + docker run --rm --net=host appropriate/curl "$@" + else + log "$(which curl) \"$@\"" + $(which curl) "$@" + fi +} \ No newline at end of file diff --git a/dockerfiles/base-cli/scripts/base/docker.sh b/dockerfiles/base-cli/scripts/base/docker.sh new file mode 100644 index 00000000000..7441be4a655 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/docker.sh @@ -0,0 +1,334 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +# Contains docker scripts + +has_docker() { + hash docker 2>/dev/null && return 0 || return 1 +} + +has_compose() { + hash docker-compose 2>/dev/null && return 0 || return 1 +} + +get_container_folder() { + THIS_CONTAINER_ID=$(get_this_container_id) + FOLDER=$(get_container_host_bind_folder "$1" $THIS_CONTAINER_ID) + echo "${FOLDER:=not set}" +} + + +get_this_container_id() { + hostname +} + +get_container_host_bind_folder() { + # BINDS in the format of var/run/docker.sock:/var/run/docker.sock :${CHE_CONTAINER_ROOT} + BINDS=$(docker inspect --format="{{.HostConfig.Binds}}" "${2}" | cut -d '[' -f 2 | cut -d ']' -f 1) + + # Remove /var/run/docker.sock:/var/run/docker.sock + VALUE=${BINDS/\/var\/run\/docker\.sock\:\/var\/run\/docker\.sock/} + + # Remove leading and trailing spaces + VALUE2=$(echo "${VALUE}" | xargs) + + MOUNT="" + IFS=$' ' + for SINGLE_BIND in $VALUE2; do + case $SINGLE_BIND in + *$1) + MOUNT="${MOUNT} ${SINGLE_BIND}" + echo "${MOUNT}" | cut -f1 -d":" | xargs + ;; + *) + # Super ugly - since we parse by space, if the next parameter is not a colon, then + # we know that next parameter is second part of a directory with a space in it. + if [[ ${SINGLE_BIND} != *":"* ]]; then + MOUNT="${MOUNT} ${SINGLE_BIND}" + else + MOUNT="" + fi + ;; + esac + done +} + + +get_docker_install_type() { + debug $FUNCNAME + if is_boot2docker; then + echo "boot2docker" + elif is_docker_for_windows; then + echo "docker4windows" + elif is_docker_for_mac; then + echo "docker4mac" + else + echo "native" + fi +} + +has_docker_for_windows_client(){ + debug $FUNCNAME + if [[ "${GLOBAL_HOST_IP}" = "10.0.75.2" ]]; then + return 0 + else + return 1 + fi +} + +is_boot2docker() { + debug $FUNCNAME + if uname -r | grep -q 'boot2docker'; then + return 0 + else + return 1 + fi +} + +is_docker_for_windows() { + debug $FUNCNAME + if uname -r | grep -q 'moby' && has_docker_for_windows_client; then + return 0 + else + return 1 + fi +} + +is_docker_for_mac() { + debug $FUNCNAME + if uname -r | grep -q 'moby' && ! has_docker_for_windows_client; then + return 0 + else + return 1 + fi +} + +is_native() { + debug $FUNCNAME + if [ $(get_docker_install_type) = "native" ]; then + return 0 + else + return 1 + fi +} + +docker_run() { + debug $FUNCNAME + # Setup options for connecting to docker host + if [ -z "${DOCKER_HOST+x}" ]; then + DOCKER_HOST="/var/run/docker.sock" + fi + + if [ -S "$DOCKER_HOST" ]; then + docker run --rm -v $DOCKER_HOST:$DOCKER_HOST \ + -v $HOME:$HOME \ + -w "$(pwd)" "$@" + else + docker run --rm -e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH \ + -v $HOME:$HOME \ + -w "$(pwd)" "$@" + fi +} + +container_exist_by_name(){ + docker inspect ${1} > /dev/null 2>&1 + if [ "$?" == "0" ]; then + return 0 + else + return 1 + fi +} + +get_server_container_id() { + log "docker inspect -f '{{.Id}}' ${1}" + docker inspect -f '{{.Id}}' ${1} +} + +container_is_running() { + if [ "$(docker ps -qa -f "status=running" -f "id=${1}" | wc -l)" -eq 0 ]; then + return 1 + else + return 0 + fi +} + +wait_until_container_is_running() { + CONTAINER_START_TIMEOUT=${1} + + ELAPSED=0 + until container_is_running ${2} || [ ${ELAPSED} -eq "${CONTAINER_START_TIMEOUT}" ]; do + log "sleep 1" + sleep 1 + ELAPSED=$((ELAPSED+1)) + done +} + + +check_docker() { + if ! has_docker; then + error "Docker not found. Get it at https://docs.docker.com/engine/installation/." + return 1; + fi + + # If DOCKER_HOST is not set, then it should bind mounted + if [ -z "${DOCKER_HOST+x}" ]; then + if ! docker ps > /dev/null 2>&1; then + info "Welcome to ${CHE_FORMAL_PRODUCT_NAME}!" + info "" + info "$CHE_FORMAL_PRODUCT_NAME commands require additional parameters:" + info " Mounting 'docker.sock', which let's us access Docker" + info "" + info "Syntax:" + info " docker run -it --rm ${BOLD} -v /var/run/docker.sock:/var/run/docker.sock${NC}" + info " $CHE_MINI_PRODUCT_NAME/cli $*" + return 2; + fi + fi + + DOCKER_VERSION=($(docker version | grep "Version:" | sed 's/Version://')) + + MAJOR_VERSION_ID=$(echo ${DOCKER_VERSION[0]:0:1}) + MINOR_VERSION_ID=$(echo ${DOCKER_VERSION[0]:2:2}) + + # Docker needs to be greater than or equal to 1.11 + if [[ ${MAJOR_VERSION_ID} -lt 1 ]] || + [[ ${MINOR_VERSION_ID} -lt 11 ]]; then + error "Error - Docker engine 1.11+ required." + return 2; + fi + + # Detect version so that we can provide better error warnings + DEFAULT_CHE_VERSION=$(cat "/version/latest.ver") + CHE_IMAGE_FULLNAME=$(docker inspect --format='{{.Config.Image}}' $(get_this_container_id)) + CHE_IMAGE_NAME=$(echo "${CHE_IMAGE_FULLNAME}" | cut -d : -f1 -s) + CHE_IMAGE_VERSION=$(echo "${CHE_IMAGE_FULLNAME}" | cut -d : -f2 -s) + if [[ "${CHE_IMAGE_VERSION}" = "" ]] || + [[ "${CHE_IMAGE_VERSION}" = "latest" ]]; then + warning "You are using CLI image version 'latest' which is set to '$DEFAULT_CHE_VERSION'." + CHE_IMAGE_VERSION=$DEFAULT_CHE_VERSION + else + CHE_IMAGE_VERSION=$CHE_IMAGE_VERSION + fi + + CHE_VERSION=$CHE_IMAGE_VERSION +} + + +check_mounts() { + + # Verify that we can write to the host file system from the container + check_host_volume_mount + + DATA_MOUNT=$(get_container_folder ":${CHE_CONTAINER_ROOT}") + INSTANCE_MOUNT=$(get_container_folder ":${CHE_CONTAINER_ROOT}/instance") + BACKUP_MOUNT=$(get_container_folder ":${CHE_CONTAINER_ROOT}/backup") + REPO_MOUNT=$(get_container_folder ":/repo") + CLI_MOUNT=$(get_container_folder ":/cli") + SYNC_MOUNT=$(get_container_folder ":/sync") + UNISON_PROFILE_MOUNT=$(get_container_folder ":/unison") + + if [[ "${DATA_MOUNT}" = "not set" ]]; then + info "Welcome to $CHE_FORMAL_PRODUCT_NAME!" + info "" + info "We need some information before we can start ${CHE_FORMAL_PRODUCT_NAME}." + info "" + info "$CHE_FORMAL_PRODUCT_NAME commands require additional parameters:" + info " 1: Mounting 'docker.sock', which let's us access Docker" + info " 2: A local path where ${CHE_FORMAL_PRODUCT_NAME} will save user data" + info "" + info "Simplest syntax:" + info " docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock" + info " -v :${CHE_CONTAINER_ROOT}" + info " ${CHE_IMAGE_FULLNAME} $*" + info "" + info "" + info "Or run with overrides for instance and/or backup:" + info " docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock" + info " -v :${CHE_CONTAINER_ROOT}" + info " -v :${CHE_CONTAINER_ROOT}/instance" + info " -v :${CHE_CONTAINER_ROOT}/backup" + info " ${CHE_IMAGE_FULLNAME} $*" + return 2; + fi + + DEFAULT_CHE_CONFIG="${DATA_MOUNT}" + DEFAULT_CHE_INSTANCE="${DATA_MOUNT}"/instance + DEFAULT_CHE_BACKUP="${DATA_MOUNT}"/backup + + if [[ "${INSTANCE_MOUNT}" != "not set" ]]; then + DEFAULT_CHE_INSTANCE="${INSTANCE_MOUNT}" + fi + + if [[ "${BACKUP_MOUNT}" != "not set" ]]; then + DEFAULT_CHE_BACKUP="${BACKUP_MOUNT}" + fi + + # Set offline to CONFIG_MOUNT + CHE_HOST_CONFIG=${CHE_CONFIG:-${DEFAULT_CHE_CONFIG}} + CHE_CONTAINER_CONFIG="${CHE_CONTAINER_ROOT}" + + CHE_HOST_INSTANCE=${CHE_INSTANCE:-${DEFAULT_CHE_INSTANCE}} + CHE_CONTAINER_INSTANCE="${CHE_CONTAINER_ROOT}/instance" + + CHE_HOST_BACKUP=${CHE_BACKUP:-${DEFAULT_CHE_BACKUP}} + CHE_CONTAINER_BACKUP="${CHE_CONTAINER_ROOT}/backup" + + ### DEV MODE VARIABLES + CHE_DEVELOPMENT_MODE="off" + if [[ "${REPO_MOUNT}" != "not set" ]]; then + CHE_DEVELOPMENT_MODE="on" + CHE_HOST_DEVELOPMENT_REPO="${REPO_MOUNT}" + CHE_CONTAINER_DEVELOPMENT_REPO="/repo" + + CHE_ASSEMBLY="${CHE_HOST_INSTANCE}/dev" + + if [[ ! -d "${CHE_CONTAINER_DEVELOPMENT_REPO}" ]] || [[ ! -d "${CHE_CONTAINER_DEVELOPMENT_REPO}/assembly" ]]; then + info "Welcome to $CHE_FORMAL_PRODUCT_NAME!" + info "" + info "You volume mounted ':/repo', but we did not detect a valid ${CHE_FORMAL_PRODUCT_NAME} source repo." + info "" + info "Volume mounting ':/repo' activate dev mode, using assembly and CLI files from $CHE_FORMAL_PRODUCT_NAME repo." + info "" + info "Please check the path you mounted to verify that is a valid $CHE_FORMAL_PRODUCT_NAME git repository." + info "" + info "Simplest syntax::" + info " docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock" + info " -v :${CHE_CONTAINER_ROOT}" + info " -v :/repo" + info " ${CHE_IMAGE_FULLNAME} $*" + info "" + info "" + info "Or run with overrides for instance, and backup (all required):" + info " docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock" + info " -v :${CHE_CONTAINER_ROOT}" + info " -v :${CHE_CONTAINER_ROOT}/instance" + info " -v :${CHE_CONTAINER_ROOT}/backup" + info " -v :/repo" + info " ${CHE_IMAGE_FULLNAME} $*" + return 2 + fi + if [[ ! -d $(echo ${CHE_CONTAINER_DEVELOPMENT_REPO}/${CHE_ASSEMBLY_IN_REPO}) ]]; then + info "Welcome to $CHE_FORMAL_PRODUCT_NAME!" + info "" + info "You volume mounted a valid $CHE_FORMAL_PRODUCT_NAME repo to ':/repo', but we could not find a ${CHE_FORMAL_PRODUCT_NAME} assembly." + info "Have you built ${CHE_ASSEMBLY_IN_REPO_MODULE_NAME} with 'mvn clean install'?" + return 2 + fi + fi +} + +docker_compose() { + debug $FUNCNAME + + if has_compose; then + docker-compose "$@" + else + docker_run -v "${CHE_HOST_INSTANCE}":"${CHE_CONTAINER_INSTANCE}" \ + docker/compose:1.8.1 "$@" + fi +} + diff --git a/dockerfiles/base-cli/scripts/base/paths.sh b/dockerfiles/base-cli/scripts/base/paths.sh new file mode 100644 index 00000000000..136d4b2a117 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/paths.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +# Contains path utilities + +check_host_volume_mount() { + echo 'test' > ${CHE_CONTAINER_ROOT}/test + + if [[ ! -f ${CHE_CONTAINER_ROOT}/test ]]; then + error "Docker installed, but unable to write files to your host." + error "Have you enabled Docker to allow mounting host directories?" + error "Did you give our CLI rights to create files on your host?" + return 2; + fi + + rm -rf ${CHE_CONTAINER_ROOT}/test +} + +get_mount_path() { + debug $FUNCNAME + FULL_PATH=$(get_full_path "${1}") + POSIX_PATH=$(convert_windows_to_posix "${FULL_PATH}") + CLEAN_PATH=$(get_clean_path "${POSIX_PATH}") + echo $CLEAN_PATH +} + +get_full_path() { + debug $FUNCNAME + # create full directory path + echo "$(cd "$(dirname "${1}")"; pwd)/$(basename "$1")" +} + +convert_windows_to_posix() { + debug $FUNCNAME + echo "/"$(echo "$1" | sed 's/\\/\//g' | sed 's/://') +} + +convert_posix_to_windows() { + debug $FUNCNAME + # Remove leading slash + VALUE="${1:1}" + + # Get first character (drive letter) + VALUE2="${VALUE:0:1}" + + # Replace / with \ + VALUE3=$(echo ${VALUE} | tr '/' '\\' | sed 's/\\/\\\\/g') + + # Replace c\ with c:\ for drive letter + echo "$VALUE3" | sed "s/./$VALUE2:/1" +} + +get_clean_path() { + debug $FUNCNAME + INPUT_PATH=$1 + # \some\path => /some/path + OUTPUT_PATH=$(echo ${INPUT_PATH} | tr '\\' '/') + # /somepath/ => /somepath + OUTPUT_PATH=${OUTPUT_PATH%/} + # /some//path => /some/path + OUTPUT_PATH=$(echo ${OUTPUT_PATH} | tr -s '/') + # "/some/path" => /some/path + OUTPUT_PATH=${OUTPUT_PATH//\"} + echo ${OUTPUT_PATH} +} \ No newline at end of file diff --git a/dockerfiles/base-cli/scripts/base/startup.sh b/dockerfiles/base-cli/scripts/base/startup.sh new file mode 100644 index 00000000000..28269a19e57 --- /dev/null +++ b/dockerfiles/base-cli/scripts/base/startup.sh @@ -0,0 +1,270 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + + + +init_constants() { + BLUE='\033[1;34m' + GREEN='\033[0;32m' + RED='\033[0;31m' + YELLOW='\033[38;5;220m' + BOLD='\033[1m' + UNDERLINE='\033[4m' + NC='\033[0m' + LOG_INITIALIZED=false + + DEFAULT_CHE_PRODUCT_NAME="CHE" + CHE_PRODUCT_NAME=${CHE_PRODUCT_NAME:-${DEFAULT_CHE_PRODUCT_NAME}} + + # Name used in CLI statements + DEFAULT_CHE_MINI_PRODUCT_NAME="che" + CHE_MINI_PRODUCT_NAME=${CHE_MINI_PRODUCT_NAME:-${DEFAULT_CHE_MINI_PRODUCT_NAME}} + + DEFAULT_CHE_FORMAL_PRODUCT_NAME="Eclipse Che" + CHE_FORMAL_PRODUCT_NAME=${CHE_FORMAL_PRODUCT_NAME:-${DEFAULT_CHE_FORMAL_PRODUCT_NAME}} + + # Path to root folder inside the container + DEFAULT_CHE_CONTAINER_ROOT="/${CHE_MINI_PRODUCT_NAME}" + CHE_CONTAINER_ROOT=${CHE_CONTAINER_ROOT:-${DEFAULT_CHE_CONTAINER_ROOT}} + + # Turns on stack trace + DEFAULT_CHE_CLI_DEBUG="false" + CHE_CLI_DEBUG=${CLI_DEBUG:-${DEFAULT_CHE_CLI_DEBUG}} + + # Activates console output + DEFAULT_CHE_CLI_INFO="true" + CHE_CLI_INFO=${CLI_INFO:-${DEFAULT_CHE_CLI_INFO}} + + # Activates console warnings + DEFAULT_CHE_CLI_WARN="true" + CHE_CLI_WARN=${CLI_WARN:-${DEFAULT_CHE_CLI_WARN}} + + # Activates console output + DEFAULT_CHE_CLI_LOG="true" + CHE_CLI_LOG=${CLI_LOG:-${DEFAULT_CHE_CLI_LOG}} + + DEFAULT_CHE_ASSEMBLY_IN_REPO_MODULE_NAME="assembly/assembly-main" + CHE_ASSEMBLY_IN_REPO_MODULE_NAME=${CHE_ASSEMBLY_IN_REPO_MODULE_NAME:-${DEFAULT_CHE_ASSEMBLY_IN_REPO_MODULE_NAME}} + + DEFAULT_CHE_ASSEMBLY_IN_REPO="${DEFAULT_CHE_ASSEMBLY_IN_REPO_MODULE_NAME}/target/eclipse-che*/eclipse-che-*" + CHE_ASSEMBLY_IN_REPO=${CHE_ASSEMBLY_IN_REPO:-${DEFAULT_CHE_ASSEMBLY_IN_REPO}} + + DEFAULT_CHE_SCRIPTS_CONTAINER_SOURCE_DIR="/repo/dockerfiles/cli/scripts" + CHE_SCRIPTS_CONTAINER_SOURCE_DIR=${CHE_SCRIPTS_CONTAINER_SOURCE_DIR:-${DEFAULT_CHE_SCRIPTS_CONTAINER_SOURCE_DIR}} + + DEFAULT_CHE_LICENSE_URL="https://www.eclipse.org/legal/epl-v10.html" + CHE_LICENSE_URL=${CHE_LICENSE_URL:-${DEFAULT_CHE_LICENSE_URL}} + +} + + +# Sends arguments as a text to CLI log file +# Usage: +# log [other arguments] +log() { + if [[ "$LOG_INITIALIZED" = "true" ]]; then + if is_log; then + echo "$@" >> "${LOGS}" + fi + fi +} + +usage () { + debug $FUNCNAME + printf "%s" "${USAGE}" + return 1; +} + +warning() { + if is_warning; then + printf "${YELLOW}WARN:${NC} %s\n" "${1}" + fi + log $(printf "WARN: %s\n" "${1}") +} + +info() { + if [ -z ${2+x} ]; then + PRINT_COMMAND="" + PRINT_STATEMENT=$1 + else + PRINT_COMMAND="($CHE_MINI_PRODUCT_NAME $1): " + PRINT_STATEMENT=$2 + fi + if is_info; then + printf "${GREEN}INFO:${NC} %b%b\n" \ + "${PRINT_COMMAND}" \ + "${PRINT_STATEMENT}" + fi + log $(printf "INFO: %b %b\n" \ + "${PRINT_COMMAND}" \ + "${PRINT_STATEMENT}") +} + +debug() { + if is_debug; then + printf "\n${BLUE}DEBUG:${NC} %s" "${1}" + fi + log $(printf "\nDEBUG: %s" "${1}") +} + +error() { + printf "${RED}ERROR:${NC} %s\n" "${1}" + log $(printf "ERROR: %s\n" "${1}") +} + +# Prints message without changes +# Usage: has the same syntax as printf command +text() { + printf "$@" + log $(printf "$@") +} + +## TODO use that for all native calls to improve logging for support purposes +# Executes command with 'eval' command. +# Also logs what is being executed and stdout/stderr +# Usage: +# cli_eval +# Examples: +# cli_eval "$(which curl) http://localhost:80/api/" +cli_eval() { + log "$@" + tmpfile=$(mktemp) + if eval "$@" &>"${tmpfile}"; then + # Execution succeeded + cat "${tmpfile}" >> "${LOGS}" + cat "${tmpfile}" + rm "${tmpfile}" + else + # Execution failed + cat "${tmpfile}" >> "${LOGS}" + cat "${tmpfile}" + rm "${tmpfile}" + fail + fi +} + +# Executes command with 'eval' command and suppress stdout/stderr. +# Also logs what is being executed and stdout+stderr +# Usage: +# cli_silent_eval +# Examples: +# cli_silent_eval "$(which curl) http://localhost:80/api/" +cli_silent_eval() { + log "$@" + eval "$@" >> "${LOGS}" 2>&1 +} + +is_log() { + if [ "${CHE_CLI_LOG}" = "true" ]; then + return 0 + else + return 1 + fi +} + +is_warning() { + if [ "${CHE_CLI_WARN}" = "true" ]; then + return 0 + else + return 1 + fi +} + +is_info() { + if [ "${CHE_CLI_INFO}" = "true" ]; then + return 0 + else + return 1 + fi +} + +is_debug() { + if [ "${CHE_CLI_DEBUG}" = "true" ]; then + return 0 + else + return 1 + fi +} + + +init_logging() { + # Initialize CLI folder + CLI_DIR="/cli" + test -d "${CLI_DIR}" || mkdir -p "${CLI_DIR}" + + # Ensure logs folder exists + LOGS="${CLI_DIR}/cli.log" + LOG_INITIALIZED=true + + # Log date of CLI execution + log "$(date)" +} + + + +init() { + init_constants + + SCRIPTS_BASE_CONTAINER_SOURCE_DIR="/scripts/base" + # add helper scripts + for HELPER_FILE in "${SCRIPTS_BASE_CONTAINER_SOURCE_DIR}"/*.sh + do + source "${HELPER_FILE}" + done + + # Make sure Docker is working and we have /var/run/docker.sock mounted or valid DOCKER_HOST + check_docker "$@" + + init_usage + if [[ $# == 0 ]]; then + usage; + fi + + # Only verify mounts after Docker is confirmed to be working. + check_mounts "$@" + + # Only initialize after mounts have been established so we can write cli.log out to a mount folder + init_logging "$@" + + SCRIPTS_CONTAINER_SOURCE_DIR="" + if [[ "${CHE_DEVELOPMENT_MODE}" = "on" ]]; then + # Use the CLI that is inside the repository. + SCRIPTS_CONTAINER_SOURCE_DIR=${CHE_SCRIPTS_CONTAINER_SOURCE_DIR} + else + # Use the CLI that is inside the container. + SCRIPTS_CONTAINER_SOURCE_DIR="/scripts" + fi + + # Primary source directory + source "${SCRIPTS_BASE_CONTAINER_SOURCE_DIR}"/cli/cli-functions.sh + + # add base commands + for BASECOMMAND_FILE in "${SCRIPTS_BASE_CONTAINER_SOURCE_DIR}"/commands/*.sh + do + source "${BASECOMMAND_FILE}" + done + + source "${SCRIPTS_CONTAINER_SOURCE_DIR}"/cli.sh +} + + +start() { + # Bootstrap enough stuff to load /cli/cli.sh + init "$@" + + # Begin product-specific CLI calls + info "cli" "Loading cli..." + cli_pre_init + cli_init "$@" + cli_parse "$@" + cli_execute "$@" + +} + +# See: https://sipb.mit.edu/doc/safe-shell/ +set -e +set -u diff --git a/dockerfiles/build-all.sh b/dockerfiles/build-all.sh new file mode 100755 index 00000000000..5dc2bea4f0a --- /dev/null +++ b/dockerfiles/build-all.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +# See: https://sipb.mit.edu/doc/safe-shell/ +set -e +set -u + +. build.include +init + +# loop on all libraries first +for directory in lib-*/ ; do + if [[ -e ${directory}/build.sh ]] ; then + echo "Call buid.sh from ${directory}" + ${directory}build.sh "$@" + else + echo "skipping ${directory}" + fi +done + +# loop on all directories and call build.sh script if present +for directory in */ ; do + if [[ -e ${directory}/build.sh ]] ; then + echo "Call buid.sh from ${directory}" + ${directory}build.sh "$@" + else + echo "skipping ${directory}" + fi +done + + +if [ $? -eq 0 ]; then + echo "${GREEN}All images have been generated successfully${NC}" +else + echo "${RED}Failure when building a docker image" + exit 1 +fi diff --git a/dockerfiles/build.include b/dockerfiles/build.include new file mode 100755 index 00000000000..6f40c20f9e5 --- /dev/null +++ b/dockerfiles/build.include @@ -0,0 +1,31 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +init() { + BLUE='\033[1;34m' + GREEN='\033[0;32m' + RED='\033[0;31m' + NC='\033[0m' + if [[ $# -eq 0 ]] ; then + TAG="nightly" + echo "No tag provided, using nightly as default" + else + TAG=${1} + fi +} + +build() { + DIR=$(cd "$(dirname "$0")"; pwd) + echo "Building Docker Image ${IMAGE_NAME} from $DIR directory with tag $TAG" + cd $DIR && docker build -t ${IMAGE_NAME}:${TAG} . + if [ $? -eq 0 ]; then + echo "${GREEN}Script run successfully: ${BLUE}${IMAGE_NAME}:${TAG}${NC}" + else + echo "${RED}Failure when building docker image ${IMAGE_NAME}:${TAG}${NC}" + exit 1 + fi +} diff --git a/dockerfiles/cli/Dockerfile b/dockerfiles/cli/Dockerfile new file mode 100644 index 00000000000..6c84027ec7b --- /dev/null +++ b/dockerfiles/cli/Dockerfile @@ -0,0 +1,18 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# build: +# docker build -t eclipse/che-cli . +# +# use: +# docker run -v $(pwd):/che eclipse/che-cli [command] +FROM eclipse/che-base:nightly + +COPY scripts /scripts/ +COPY version /version/ + +RUN mkdir /che && chmod u+x /scripts/entrypoint.sh +ENTRYPOINT ["/scripts/entrypoint.sh"] diff --git a/dockerfiles/cli/build.sh b/dockerfiles/cli/build.sh new file mode 100755 index 00000000000..dbdb84d32a6 --- /dev/null +++ b/dockerfiles/cli/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-cli" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/cli/scripts/cli.sh b/dockerfiles/cli/scripts/cli.sh new file mode 100644 index 00000000000..25a9aa43f09 --- /dev/null +++ b/dockerfiles/cli/scripts/cli.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# + +cli_pre_init() { + GLOBAL_HOST_IP=${GLOBAL_HOST_IP:=$(docker_run --net host eclipse/che-ip:nightly)} + DEFAULT_CHE_HOST=$GLOBAL_HOST_IP + CHE_HOST=${CHE_HOST:-${DEFAULT_CHE_HOST}} + DEFAULT_CHE_PORT=8080 + CHE_PORT=${CHE_PORT:-${DEFAULT_CHE_PORT}} +} \ No newline at end of file diff --git a/dockerfiles/cli/scripts/cmd_empty.sh b/dockerfiles/cli/scripts/cmd_empty.sh new file mode 100644 index 00000000000..c2553cf7d0b --- /dev/null +++ b/dockerfiles/cli/scripts/cmd_empty.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# diff --git a/dockerfiles/cli/scripts/entrypoint.sh b/dockerfiles/cli/scripts/entrypoint.sh new file mode 100755 index 00000000000..f44f7e4e08e --- /dev/null +++ b/dockerfiles/cli/scripts/entrypoint.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# + +init_usage() { + USAGE=" +Usage: docker run -it --rm + -v /var/run/docker.sock:/var/run/docker.sock + -v :${CHE_CONTAINER_ROOT} + ${CHE_IMAGE_FULLNAME} [COMMAND] + + help This message + version Installed version and upgrade paths + init Initializes a directory with a ${CHE_FORMAL_PRODUCT_NAME} install + [--no-force Default - uses cached local Docker images + --pull Checks for newer images from DockerHub + --force Removes all images and re-pulls all images from DockerHub + --offline Uses images saved to disk from the offline command + --accept-license Auto accepts the ${CHE_FORMAL_PRODUCT_NAME} license during installation + --reinit] Reinstalls using existing $CHE_MINI_PRODUCT_NAME.env configuration + start [--pull | --force | --offline] Starts ${CHE_FORMAL_PRODUCT_NAME} services + stop Stops ${CHE_FORMAL_PRODUCT_NAME} services + restart [--pull | --force] Restart ${CHE_FORMAL_PRODUCT_NAME} services + destroy Stops services, and deletes ${CHE_FORMAL_PRODUCT_NAME} instance data + [--quiet Does not ask for confirmation before destroying instance data + --cli] If :/cli is mounted, will destroy the cli.log + rmi [--quiet] Removes the Docker images for , forcing a repull + config Generates a ${CHE_FORMAL_PRODUCT_NAME} config from vars; run on any start / restart + upgrade Upgrades ${CHE_FORMAL_PRODUCT_NAME} from one version to another with migrations and backups + download [--pull|--force|--offline] Pulls Docker images for the current ${CHE_FORMAL_PRODUCT_NAME} version + backup [--quiet | --skip-data] Backups ${CHE_FORMAL_PRODUCT_NAME} configuration and data to ${CHE_CONTAINER_ROOT}/backup volume mount + restore [--quiet] Restores ${CHE_FORMAL_PRODUCT_NAME} configuration and data from ${CHE_CONTAINER_ROOT}/backup mount + offline Saves ${CHE_FORMAL_PRODUCT_NAME} Docker images into TAR files for offline install + info Displays info about ${CHE_FORMAL_PRODUCT_NAME} and the CLI + [ --all Run all debugging tests + --debug Displays system information + --network] Test connectivity between ${CHE_FORMAL_PRODUCT_NAME} sub-systems + ssh [machine-name] SSH to a workspace if SSH agent enabled + mount Synchronize workspace with current working directory + action [--help] Start action on ${CHE_FORMAL_PRODUCT_NAME} instance + test [--help] Start test on ${CHE_FORMAL_PRODUCT_NAME} instance + +Variables: + CHE_HOST IP address or hostname where ${CHE_FORMAL_PRODUCT_NAME} will serve its users + CLI_DEBUG Default=false. Prints stack trace during execution + CLI_INFO Default=true. Prints out INFO messages to standard out + CLI_WARN Default=true. Prints WARN messages to standard out + CLI_LOG Default=true. Prints messages to cli.log file +" +} + +source /scripts/base/startup.sh +start "$@" diff --git a/dockerfiles/cli/version/4.7.2/images b/dockerfiles/cli/version/4.7.2/images new file mode 100644 index 00000000000..538a741fdbc --- /dev/null +++ b/dockerfiles/cli/version/4.7.2/images @@ -0,0 +1,4 @@ +IMAGE_PUPPET=puppet/puppet-agent-alpine:4.6.2 +IMAGE_REGISTRY=registry:2.5.0 +IMAGE_INIT=eclipse/che-init:nightly +IMAGE_CHE=eclipse/che-server:4.7.2 diff --git a/dockerfiles/cli/version/5.0.0-M5/images b/dockerfiles/cli/version/5.0.0-M5/images new file mode 100644 index 00000000000..67b4e3dce62 --- /dev/null +++ b/dockerfiles/cli/version/5.0.0-M5/images @@ -0,0 +1,4 @@ +IMAGE_PUPPET=puppet/puppet-agent-alpine:4.6.2 +IMAGE_REGISTRY=registry:2.5.0 +IMAGE_INIT=eclipse/che-init:nightly +IMAGE_CHE=eclipse/che-server:5.0.0-M5 diff --git a/dockerfiles/cli/version/5.0.0-M6/images b/dockerfiles/cli/version/5.0.0-M6/images new file mode 100644 index 00000000000..6189ba7962e --- /dev/null +++ b/dockerfiles/cli/version/5.0.0-M6/images @@ -0,0 +1,4 @@ +IMAGE_PUPPET=puppet/puppet-agent-alpine:4.6.2 +IMAGE_REGISTRY=registry:2.5.0 +IMAGE_INIT=eclipse/che-init:nightly +IMAGE_CHE=eclipse/che-server:5.0.0-M6 diff --git a/dockerfiles/cli/version/5.0.0-M7/images b/dockerfiles/cli/version/5.0.0-M7/images new file mode 100644 index 00000000000..74244c38d26 --- /dev/null +++ b/dockerfiles/cli/version/5.0.0-M7/images @@ -0,0 +1,4 @@ +IMAGE_PUPPET=puppet/puppet-agent-alpine:4.6.2 +IMAGE_REGISTRY=registry:2.5.0 +IMAGE_INIT=eclipse/che-init:nightly +IMAGE_CHE=eclipse/che-server:5.0.0-M7 diff --git a/dockerfiles/cli/version/latest.ver b/dockerfiles/cli/version/latest.ver new file mode 100644 index 00000000000..f981d9fdbf2 --- /dev/null +++ b/dockerfiles/cli/version/latest.ver @@ -0,0 +1 @@ +5.0.0-M7 \ No newline at end of file diff --git a/dockerfiles/cli/version/latest/images b/dockerfiles/cli/version/latest/images new file mode 100644 index 00000000000..c6989d88836 --- /dev/null +++ b/dockerfiles/cli/version/latest/images @@ -0,0 +1,4 @@ +IMAGE_PUPPET=puppet/puppet-agent-alpine:4.6.2 +IMAGE_REGISTRY=registry:2.5.0 +IMAGE_INIT=eclipse/che-init:5.0.0-latest +IMAGE_CHE=eclipse/che-server:5.0.0-latest diff --git a/dockerfiles/cli/version/nightly/images b/dockerfiles/cli/version/nightly/images new file mode 100644 index 00000000000..059a4649dc3 --- /dev/null +++ b/dockerfiles/cli/version/nightly/images @@ -0,0 +1,4 @@ +IMAGE_PUPPET=puppet/puppet-agent-alpine:4.6.2 +IMAGE_REGISTRY=registry:2.5.0 +IMAGE_INIT=eclipse/che-init:nightly +IMAGE_CHE=eclipse/che-server:nightly diff --git a/dockerfiles/dev/Dockerfile b/dockerfiles/dev/Dockerfile new file mode 100644 index 00000000000..d6c732317fa --- /dev/null +++ b/dockerfiles/dev/Dockerfile @@ -0,0 +1,70 @@ +# Copyright (c) 2012-2016 Codenvy, S.A., 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: +# Codenvy, S.A. - initial API and implementation +# Mario Loriedo +# +# build: +# docker build -t eclipse/che-dev . +# +# use: +# docker run -it --rm --name build-che +# -v "$HOME/.m2:/home/user/.m2" +# -v "$PWD":/home/user/che-build +# -w /home/user/che-build +# codenvy/che-dev +# mvn -DskipTests=true +# -Dfindbugs.skip=true +# -Dgwt.compiler.localWorkers=2 -T 1C +# -Dskip-validate-sources +# clean install +# +# For Windows, replace $HOME with maven repo directory. +# For Windows, replace $PWD with Che source code directory. +# + +FROM codenvy/debian_jdk8 +ENV NODE_VERSION=0.12.9 \ + NODE_PATH=/usr/local/lib/node_modules + +RUN sudo apt-get update && \ + sudo apt-get -y install build-essential libssl-dev libkrb5-dev gcc make ruby-full rubygems && \ + sudo gem install sass compass && \ + sudo apt-get clean && \ + sudo apt-get -y autoremove && \ + sudo apt-get -y clean && \ + sudo rm -rf /var/lib/apt/lists/* && \ + set -ex \ + && for key in \ + 9554F04D7259F04124DE6B476D5A82AC7E37093B \ + 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \ + 0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 \ + FD3A5288F042B6850C66B31F09FE44734EB7990E \ + 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \ + DD8F2338BAE7501E3DD5AC78C273792F7D83545D \ + ; do \ + gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \ + done && \ + cd /home/user && curl --insecure -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" \ + && curl --insecure -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --verify SHASUMS256.txt.asc \ + && grep "node-v$NODE_VERSION-linux-x64.tar.gz\$" SHASUMS256.txt.asc | sha256sum -c - \ + && sudo tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 \ + && sudo rm "node-v$NODE_VERSION-linux-x64.tar.gz" SHASUMS256.txt.asc + +EXPOSE 3000 5000 9000 +RUN sudo npm install -g npm@latest +RUN sudo npm install --unsafe-perm -g gulp bower typings +RUN mkdir ~/gopath && \ + cd /home/user && wget -q https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz && \ + sudo tar -xvf go1.6.2.linux-amd64.tar.gz -C /opt/ && \ + rm go1.6.2.linux-amd64.tar.gz +ENV GOROOT=/opt/go +ENV GOPATH=/home/user/gopath +RUN echo "export PATH=$GOROOT/bin:$PATH" >> ~/.bashrc && \ + sudo chown -R user:user /opt +WORKDIR /home/user diff --git a/dockerfiles/dev/build.sh b/dockerfiles/dev/build.sh new file mode 100755 index 00000000000..4c59fb03805 --- /dev/null +++ b/dockerfiles/dev/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-dev" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/dir/Dockerfile b/dockerfiles/dir/Dockerfile new file mode 100644 index 00000000000..7a1802e008e --- /dev/null +++ b/dockerfiles/dir/Dockerfile @@ -0,0 +1,15 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# build: +# docker build -t eclipse/che-dir . +# +# use: +# docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-dir [command] + +FROM eclipse/che-lib-typescript:nightly + +ENTRYPOINT ["node", "/che-lib/index.js", "che-dir"] diff --git a/dockerfiles/dir/README.md b/dockerfiles/dir/README.md new file mode 100644 index 00000000000..81097d885f3 --- /dev/null +++ b/dockerfiles/dir/README.md @@ -0,0 +1,33 @@ +### Creating an Eclipse Che instance from a local directory + +## Build Docker container +``` +$ build.sh (on Unix) +> build.bat (on Windows) +``` + +## Run container + +Check no docker Eclipse Che container is alive and kill it if any +``` +$ docker ps -a +``` + +Clone a folder +``` +$ git clone https://github.com/che-samples/web-java-spring-petclinic +``` + +Go into this checkout directory +``` +$ cd web-java-spring-petclinic +``` + +Run script +``` +docker run -v /var/run/docker.sock:/var/run/docker.sock \ + -v "$PWD":"$PWD" --rm eclipse/che-file \ + $PWD +``` + +note: if Eclipse Che is already started, it does not handle yet this state diff --git a/dockerfiles/dir/build.sh b/dockerfiles/dir/build.sh new file mode 100755 index 00000000000..35a343d4907 --- /dev/null +++ b/dockerfiles/dir/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-dir" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/init/Dockerfile b/dockerfiles/init/Dockerfile new file mode 100644 index 00000000000..57f8f634a1d --- /dev/null +++ b/dockerfiles/init/Dockerfile @@ -0,0 +1,38 @@ +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +# Initializes an empty directory with the templates needed to configure and run Che. +# +# build: +# docker build -t eclipse/che-init: . +# +# use (to copy files onto folder): +# docker run -v $(pwd):/che eclipse/che-init: +# +# use (to run puppet config): +# docker run --entrypoint=/usr/bin/puppet eclipse/che-init: apply + + +FROM puppet/puppet-agent-alpine:4.6.2 + +# install openssh needed to generate ssh keys +RUN apk --update add openssh \ + && rm -rf /var/cache/apk/* \ + && mkdir -p /files \ + && mkdir -p /etc/puppet/modules \ + && mkdir -p /etc/puppet/manifests \ + && mkdir -p /files/docs + +COPY manifests /etc/puppet/manifests +COPY modules /etc/puppet/modules +COPY docs /files/docs +COPY entrypoint.sh / +RUN chmod +x entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] diff --git a/dockerfiles/init/build.sh b/dockerfiles/init/build.sh new file mode 100755 index 00000000000..89a58d3c21e --- /dev/null +++ b/dockerfiles/init/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-init" +source $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/init/docs/DOCS.md b/dockerfiles/init/docs/DOCS.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dockerfiles/init/docs/README.md b/dockerfiles/init/docs/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dockerfiles/init/entrypoint.sh b/dockerfiles/init/entrypoint.sh new file mode 100644 index 00000000000..973086267f1 --- /dev/null +++ b/dockerfiles/init/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial Implementation +# + +cp -rf /files/docs /copy + +# do not copy che.env if exist +if [ ! -f /copy/che.env ]; then + cp /etc/puppet/manifests/che.env /copy +fi diff --git a/dockerfiles/init/manifests/che.env b/dockerfiles/init/manifests/che.env new file mode 100644 index 00000000000..dfcc4d7b845 --- /dev/null +++ b/dockerfiles/init/manifests/che.env @@ -0,0 +1,173 @@ +############################################################ +##### ##### +##### CHE SYSTEM ##### +##### ##### +# +# Fundamental parameters that affect the initial system operation. +# + +# IP address, hostname, or DNS +# The IP address or DNS name of where the Che endpoint will service your users. +# If you are running this on a local system, we auto-detect this value as the IP +# address of your Docker daemon. On many systems, especially those from cloud hosters +# like DigitalOcean, you must explicitly set this to the external IP address or +# DNS entry provided by the provider. +#CHE_HOST=localhost + +# Proxies +# Che's internal system services such as its internal JVMs need to +# have system level properties applied so that they can reach the Internet. Che's +# system uses the Internet to communicate with DockerHub for downloading images that +# are used to run Che's systems. Note that you must configure proxy access in three +# locations. First, you enabled your system Docker daemon to use proxies. Second, you +# configure proxies for Che's internal system services. Third, if you want your users +# to access the Internet, then you should also add proxy values for their workspaces. +# +# Please be mindful of the proxy URL formatting. Proxies are unforgiving if you do not type +# the URL just right, inclduing the protocol and whether they allow a trailing /. +#CHE_HTTP_PROXY_FOR_CHE=http://myproxy.com:8001/ +#CHE_HTTPS_PROXY_FOR_CHE=http://myproxy.com:8001/ +#CHE_NO_PROXY_FOR_CHE= + +# Proxies for Workspaces +# The proxy values that will be set as environment variables within each user's workspace. +# Set these to allow users Internet access if they are behind a proxy. +#CHE_HTTP_PROXY_FOR_CHE_WORKSPACES=http://myproxy.com:8001/ +#CHE_HTTPS_PROXY_FOR_CHE_WORKSPACES=http://myproxy.com:8001/ +#CHE_NO_PROXY_FOR_CHE_WORKSPACES= + +# JPDA +# If using Che in development mode, activate this property to enable JPDA +# mode within Che's internal Tomcat +#CHE_DEBUG_SUSPEND=false +#CHE_DEBUG_PORT=8000 + + +# XMX +# Che's core server runs as a Tomcat application on top of a JVM. This sets the +# JVM XMX settings that are loaded by the JVM when the Che container boots. +# It should be rare that you would need to change this. +#CHE_SERVER_XMX=2048 + +############################################################ +##### ##### +##### WORKSPACE CONFIGURATION ##### +##### ##### +# +# User workspaces have their own runtimes. Those runtimes can be composed 1..n containers. +# We call each container a 'machine' as it is a dedicated runtime. One of the machines for a +# workspace must be designated as the 'development' machine, which installs Che agents to +# provide additional services to the user. These parameters configure how Che manages user +# machines and the agents that are deployed within them. +# +# Since workspaces have their own runtimes, they have separate proxies that do not inherit from +# the system proxies that you have configured for your Docker daemon. +# +# /etc/hosts for Workspaces +# This will add entries into the user's /etc/hosts file that is running within their workspace. +# You may need to configure this file to give the user access to systems within your network +# or access to the Internet. +#CHE_MACHINE_EXTRA_HOSTS=NULL + +# Idle Timeout +# The length of time that a user is idel with their workspace when the system will suspend the +# workspace by snapshotting it and then stopping it. Idleness is determined by the length of +# time that the user has not interacted with the workspace, meaning that one of our agents +# has not received instructions. Leaving a browser window open counts as idleness time. +#CHE_MACHINE_WS_AGENT_INACTIVE_STOP_TIMEOUT_MS=600000 + +# Memory +# The recommended RAM size that users will see for their workspace when they create new +# workspaces in the user dashboard. +#CHE_MACHINE_DEFAULT_MEM_SIZE_MB=1024 + +# Memory Swap +# Adjust machine swap memory by multiplication current machnine memory on provided value. +# default is 0 which means disabled swap, if set multiplier value equal to 0.5 +# machine swap will be configured with size that equal to half of current machine memory. +# It should be rare that you would configure this. See Docker memory swap online +# for background. +#CHE_MACHINE_DOCKER_MEMORY_SWAP_MULTIPLIER=0 + +# Host Volume Mounts +# Semicolon separated list of volume mounts. If this is provided, Che will volume mount +# those host folders into each workspace generated by your users. This is a way to allow +# you to provide access to network attached storage that is shared across many workspaces. +#CHE_MACHINE_SERVER_EXTRA_VOLUME=/path/on/host:/path/in/workspace:ro,Z;/path/to/host2:/path/in/workspace2:ro,Z; + +# Privilged Mode +# Set to `true` if you would like user workspaces to be started with Docker's privileged mode. +# Please be careful when setting this property. This allows user workspaces to gain access to +# the underly host with root privileges. However, privileged mode is needed if users want to +# launch their own Docker containers from within their Docker-powered workspace. +#CHE_MACHINE_DOCKER_PRIVILEGE_MODE=false + +# Agent Start Timeout +# The length of time that a workspace will be allowed to boot before the system terminates the +# boot process. If the Che container cannot establish two way communications with the +# agents within the workspace when it boots, then the workspace will not be started. +#CHE_MACHINE_WS_AGENT_MAX_START_TIME_MS=300000 + + +############################################################ +##### ##### +##### OAUTH CONFIGURATION ##### +##### ##### +# +# You can configure a 3rd party provider's oAuth, which will be used for your users when they +# create accounts and login. There are certain services within Che, such as GitHub +# integration, where GitHub keys are required. oAuth must be configured for those services to work. +# +# Google +#CHE_GOOGLE_CLIENT_ID=your_google_client_id +#CHE_GOOGLE_SECRET=your_google_secret + +# GitHub +#CHE_GITHUB_CLIENT_ID=your_github_client_ide +#CHE_GITHUB_SECRET=your_google_secret + +# BitBucket +#CHE_BITBUCKET_CLIENT_ID=your_bitbucket_client_ide +#CHE_BITBUCKET_SECRET=your_bitbucket_secret + +# Microsoft +#CHE_MICROSOFT_CLIENT_ID==your_microsoft_client_ide +#CHE_MICROSOFT_SECRET=your_microsoft_secret + +# WSO2 +#CHE_WSO2_CLIENT_ID=your_wso2_client_ide +#CHE_WSO2_SECRET=your_wso2_secret + +# Project Locker +#CHE_PROJECTLOCKER_CLIENT_ID=your_projectlocker_client_ide +#CHE_PROJECTLOCKER_SECRET=your_projectlocker_secret + + + +############################################################ +##### ##### +##### JMX ##### +##### ##### +# +# JMX provides a management interface point to within the Che container. JMX is not +# use by other containers such as haproxy or nginx. While Che is running, grab the +# IP address of the Che container and you can connect to its embedded JMX server. +# +#CHE_JMX_USERNAME=admin +#CHE_JMX_PASSWORD=Che + + +############################################################ +##### ##### +##### DOCKER ##### +##### ##### +# IP Address +# The IP address of the Docker daemon that is running on your host. We do a self-discovery +# to set this. You can combine this with values of DOCKER_HOST to change communications +# from socket to TCP. This value will be set to DOCKER_MACHINE_HOST env variable for +# the Che Docker container when it boots - it's how we determine what containers will boot. +#CHE_DOCKER_IP=172.17.0.1 + +# Docker Host +# How Che will connect to the Docker Host. +#DOCKER_HOST=tcp://localhost:2375 \ No newline at end of file diff --git a/dockerfiles/init/manifests/che.pp b/dockerfiles/init/manifests/che.pp new file mode 100644 index 00000000000..60750e2e777 --- /dev/null +++ b/dockerfiles/init/manifests/che.pp @@ -0,0 +1,35 @@ +node default { +################################################################################################## + $che_ip = getValue("CHE_HOST", "localhost") + $che_port = getValue("CHE_PORT", "8080") + $che_version = getValue("CHE_VERSION","nightly") + $che_instance = getValue("CHE_INSTANCE","/tmp/che") + $che_config = getValue("CHE_CONFIG","/path/to/che/che/puppet/sources") + $che_assembly = getValue("CHE_ASSEMBLY","/home/user/che") + $che_env = getValue("CHE_ENVIRONMENT","production") + $che_debug_port = getValue("CHE_DEBUG_PORT","8000") + $che_debug_suspend = getValue("CHE_DEBUG_SUSPEND","false") + $docker_ip = getValue("CHE_DOCKER_IP","172.17.0.1") + $docker_host = getValue("DOCKER_HOST","tcp://localhost:2375") + + +############################### +# oAuth configurations + $google_client_id = getValue("CHE_GOOGLE_CLIENT_ID","your_google_client_id") + $google_secret = getValue("CHE_GOOGLE_SECRET","your_google_secret") + $github_client_id = getValue("CHE_GITHUB_CLIENT_ID","423531cf41d6c13e1b3b") + $github_secret = getValue("CHE_GITHUB_SECRET","e708bfc28c541a8f25feac4466c93611d9018a3d") + $bitbucket_client_id = getValue("CHE_BITBUCKET_CLIENT_ID","your_bitbucket_client_id") + $bitbucket_secret = getValue("CHE_BITBUCKET_SECRET","your_bitbucket_secret") + $wso2_client_id = getValue("CHE_WSO2_CLIENT_ID","your_wso2_client_id") + $wso2_secret = getValue("CHE_WSO2_SECRET","your_wso2_secret") + $projectlocker_client_id = getValue("CHE_PROJECTLOCKER_CLIENT_ID","your_projectlocker_client_id") + $projectlocker_secret = getValue("CHE_PROJECTLOCKER_SECRET","your_projectlocker_secret") + $microsoft_client_id = getValue("CHE_MICROSOFT_CLIENT_ID","your_microsoft_client_id") + $microsoft_secret = getValue("CHE_MICROSOFT_SECRET","your_microsoft_secret") + +############################### +# Include base module + include base +} + diff --git a/dockerfiles/init/modules/base/manifests/init.pp b/dockerfiles/init/modules/base/manifests/init.pp new file mode 100644 index 00000000000..46f4211f75c --- /dev/null +++ b/dockerfiles/init/modules/base/manifests/init.pp @@ -0,0 +1,16 @@ +class base { + $dirs = [ + "/opt/che", + "/opt/che/data", + "/opt/che/config", + "/opt/che/logs", + "/opt/che/templates", + "/opt/che/stacks" ] + file { $dirs: + ensure => "directory", + mode => "755", + } + + include che + include compose +} diff --git a/dockerfiles/init/modules/che/manifests/init.pp b/dockerfiles/init/modules/che/manifests/init.pp new file mode 100644 index 00000000000..b8f27df46af --- /dev/null +++ b/dockerfiles/init/modules/che/manifests/init.pp @@ -0,0 +1,9 @@ +class che { + +# creating che.env + file { "/opt/che/config/che.env": + ensure => "present", + content => template("che/che.env.erb"), + mode => "644", + } +} diff --git a/dockerfiles/init/modules/che/templates/che.env.erb b/dockerfiles/init/modules/che/templates/che.env.erb new file mode 100644 index 00000000000..c434a00e1eb --- /dev/null +++ b/dockerfiles/init/modules/che/templates/che.env.erb @@ -0,0 +1,24 @@ +CHE_IP=<%= scope.lookupvar('che::che_ip') %> +CHE_PORT=<%= scope.lookupvar('che::che_port') %> +CHE_LOGS_DIR=/logs +#DOCKER_HOST=<%= scope.lookupvar('che::docker_host') %> +#DOCKER_MACHINE_HOST=<%= scope.lookupvar('che::docker_ip') %> + +<% if scope.lookupvar('che::che_env') != "production" -%> +JPDA=jpda +CHE_ASSEMBLY=<%= scope.lookupvar('che::che_assembly') %> +CHE_LOG_LEVEL=debug +JPDA_ADDRESS=<%= scope.lookupvar('che::che_debug_port') %> +<% if scope.lookupvar('che::che_debug_suspend') == "true" %>JPDA_SUSPEND=y<% end -%> +<% end %> + +CHE_DATABASE=/data +CHE_WORKSPACE_STORAGE=/data/workspaces +CHE_WORKSPACE_LOGS=/data/logs/machine +CHE_TEMPLATE_STORAGE=/data/templates +CHE_STACKS_STORAGE=/data/stacks/stacks.json +CHE_STACKS_IMAGES=/data/stacks/images + +CHE_WORKSPACE_TERMINAL__LINUX__AMD64=<%= scope.lookupvar('che::che_instance') %>/data/lib/linux_amd64/terminal +CHE_WORKSPACE_TERMINAL__LINUX__ARM7=<%= scope.lookupvar('che::che_instance') %>/data/lib/linux_arm7/terminal +CHE_WORKSPACE_AGENT_DEV=<%= scope.lookupvar('che::che_instance') %>/data/lib/ws-agent.tar.gz diff --git a/dockerfiles/init/modules/compose/manifests/init.pp b/dockerfiles/init/modules/compose/manifests/init.pp new file mode 100644 index 00000000000..8fa71835bfb --- /dev/null +++ b/dockerfiles/init/modules/compose/manifests/init.pp @@ -0,0 +1,14 @@ +class compose { + file { "/opt/che/docker-compose-container.yml": + ensure => "present", + content => template("compose/docker-compose-container.yml.erb"), + mode => '644', + } + + file { "/opt/che/docker-compose.yml": + ensure => "present", + content => template("compose/docker-compose.yml.erb"), + mode => '644', + } + +} diff --git a/dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb b/dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb new file mode 100644 index 00000000000..2dd0f57c4b4 --- /dev/null +++ b/dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb @@ -0,0 +1,24 @@ +# ################################### +# This file is generated by puppet +# PLEASE DON'T MODIFY BY HAND +# ################################### + +che: + image: <%= ENV["IMAGE_CHE"] %> + env_file: + - '/che/instance/config/che.env' + volumes: + - '/var/run/docker.sock:/var/run/docker.sock' + - '<%= scope.lookupvar('che::che_instance') -%>/data:/data' + - '<%= scope.lookupvar('che::che_instance') -%>/logs:/logs' + - '<%= scope.lookupvar('che::che_instance') -%>/config:/conf' +<% if scope.lookupvar('che::che_env') != 'production' -%> + - '<%= scope.lookupvar('che::che_assembly') -%>:/assembly' +<% end -%> + ports: + - '<%= scope.lookupvar('che::che_port') -%>:8080' +<% if scope.lookupvar('che::che_env') != 'production' -%> + - '8000:8000' +<% end -%> + restart: always + container_name: che diff --git a/dockerfiles/init/modules/compose/templates/docker-compose.yml.erb b/dockerfiles/init/modules/compose/templates/docker-compose.yml.erb new file mode 100644 index 00000000000..9b266bf33a2 --- /dev/null +++ b/dockerfiles/init/modules/compose/templates/docker-compose.yml.erb @@ -0,0 +1,24 @@ +# ################################### +# This file is generated by puppet +# PLEASE DON'T MODIFY BY HAND +# ################################### + +che: + image: <%= ENV["IMAGE_CHE"] %> + env_file: + - '<%= ENV["CHE_ENV_FILE"] %>' + volumes: + - '/var/run/docker.sock:/var/run/docker.sock' + - '<%= scope.lookupvar('che::che_instance') -%>/data:/data' + - '<%= scope.lookupvar('che::che_instance') -%>/logs:/logs' + - '<%= scope.lookupvar('che::che_instance') -%>/config:/conf' +<% if scope.lookupvar('che::che_env') != 'production' -%> + - '<%= scope.lookupvar('che::che_assembly') -%>:/assembly' +<% end -%> + ports: + - '<%= scope.lookupvar('che::che_port') -%>:8080' +<% if scope.lookupvar('che::che_env') != 'production' -%> + - '8000:8000' +<% end -%> + restart: always + container_name: che diff --git a/dockerfiles/init/modules/puppet_plugins/lib/puppet/parser/functions/getValue.rb b/dockerfiles/init/modules/puppet_plugins/lib/puppet/parser/functions/getValue.rb new file mode 100644 index 00000000000..5edaa815a6f --- /dev/null +++ b/dockerfiles/init/modules/puppet_plugins/lib/puppet/parser/functions/getValue.rb @@ -0,0 +1,12 @@ +module Puppet::Parser::Functions + newfunction(:getValue, :type => :rvalue) do |args| + envname = args[0] + default_value = args[1] + if ENV[envname].nil? + actual_value = default_value + else + actual_value = ENV[envname] + end + return actual_value + end +end \ No newline at end of file diff --git a/dockerfiles/ip/Dockerfile b/dockerfiles/ip/Dockerfile new file mode 100644 index 00000000000..e19d27a72a9 --- /dev/null +++ b/dockerfiles/ip/Dockerfile @@ -0,0 +1,16 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# build: +# docker build -t eclipse/che-ip . +# +# use: +# docker run --rm --net=host eclipse/che-ip + +FROM alpine:3.4 + +COPY entrypoint.sh /bin/entrypoint.sh +ENTRYPOINT ["/bin/entrypoint.sh"] diff --git a/dockerfiles/ip/build.sh b/dockerfiles/ip/build.sh new file mode 100755 index 00000000000..1104cea4939 --- /dev/null +++ b/dockerfiles/ip/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-ip" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/ip/entrypoint.sh b/dockerfiles/ip/entrypoint.sh new file mode 100755 index 00000000000..1400e2e3980 --- /dev/null +++ b/dockerfiles/ip/entrypoint.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Copyright (c) 2012-2016 Codenvy, S.A., 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 + +# define network interface variable +NETWORK_IF= + +# handle docker for windows/mac +if uname -r | grep -q 'moby'; then + if [ -d "/sys/class/net/hvint0" ]; then + NETWORK_IF=hvint0 + elif [ -d "/sys/class/net/eth0" ]; then + NETWORK_IF=eth0 + fi +fi + +if test -z ${NETWORK_IF}; then + for i in $( ls /sys/class/net ); do + if [ ${i:0:3} = eth ] ;then + NETWORK_IF=${i} + fi + done +fi + +# if not found, consider native and use docker0 +if test -z ${NETWORK_IF} + then + if [ -d "/sys/class/net/docker0" ]; then + NETWORK_IF="docker0" + fi +fi + +# if not found, throw error +if test -z ${NETWORK_IF}; then + echo unable to find a matching docker interface + exit 1 +fi + +ip a show "${NETWORK_IF}" | \ + grep 'inet ' | \ + cut -d/ -f1 | \ + awk '{print $2}' diff --git a/dockerfiles/launcher/Dockerfile b/dockerfiles/launcher/Dockerfile new file mode 100644 index 00000000000..614c7cd222d --- /dev/null +++ b/dockerfiles/launcher/Dockerfile @@ -0,0 +1,39 @@ +# Copyright (c) 2012-2016 Codenvy, S.A., 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: +# Mario Loriedo - Initial implementation +# Tyler Jewell - Improve debug output +# +# To build, in this directory: +# `docker build -t codenvy/che-launcher .` +# +# To use it: +# `docker run -t -v /var/run/docker.sock:/var/run/docker.sock codenvy/che-launcher start` +# `docker run -t -v /var/run/docker.sock:/var/run/docker.sock codenvy/che-launcher stop` +# `docker run -t -v /var/run/docker.sock:/var/run/docker.sock codenvy/che-launcher restart` +# `docker run -t -v /var/run/docker.sock:/var/run/docker.sock codenvy/che-launcher update` +# + +FROM alpine:3.4 + +RUN apk add --no-cache \ + ca-certificates \ + curl \ + openssl + +ENV DOCKER_BUCKET get.docker.com +ENV DOCKER_VERSION 1.6.0 + +RUN set -x \ + && curl -sL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" \ + > /usr/bin/docker; chmod +x /usr/bin/docker + +COPY /launcher_cmds.sh /bin/launcher_cmds.sh +COPY /launcher_funcs.sh /bin/launcher_funcs.sh +COPY /launcher.sh /bin/launcher.sh + +ENTRYPOINT ["bin/launcher.sh"] diff --git a/dockerfiles/launcher/build.sh b/dockerfiles/launcher/build.sh new file mode 100755 index 00000000000..a364f01da51 --- /dev/null +++ b/dockerfiles/launcher/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-launcher" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/launcher/launcher.sh b/dockerfiles/launcher/launcher.sh new file mode 100755 index 00000000000..f47fed01d26 --- /dev/null +++ b/dockerfiles/launcher/launcher.sh @@ -0,0 +1,160 @@ +#!/bin/sh +# Copyright (c) 2012-2016 Codenvy, S.A., 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: +# Mario Loriedo - Initial implementation +# + +launcher_dir="$(dirname "$0")" +source "$launcher_dir/launcher_funcs.sh" +source "$launcher_dir/launcher_cmds.sh" + +init_logging() { + BLUE='\033[1;34m' + GREEN='\033[0;32m' + RED='\033[0;31m' + NC='\033[0m' +} + +init_global_variables() { + + # Set variables that use docker as utilities to avoid over container execution + ETH0_ADDRESS=$(docker run --rm --net host alpine /bin/sh -c "ifconfig eth0 2> /dev/null" | \ + grep "inet addr:" | \ + cut -d: -f2 | \ + cut -d" " -f1) + + ETH1_ADDRESS=$(docker run --rm --net host alpine /bin/sh -c "ifconfig eth1 2> /dev/null" | \ + grep "inet addr:" | \ + cut -d: -f2 | \ + cut -d" " -f1) + + DOCKER0_ADDRESS=$(docker run --rm --net host alpine /bin/sh -c "ifconfig docker0 2> /dev/null" | \ + grep "inet addr:" | \ + cut -d: -f2 | \ + cut -d" " -f1) + + # Used to self-determine container version + LAUNCHER_CONTAINER_ID=$(get_che_launcher_container_id) + LAUNCHER_IMAGE_NAME=$(docker inspect --format='{{.Config.Image}}' "${LAUNCHER_CONTAINER_ID}") + LAUNCHER_IMAGE_VERSION=$(echo "${LAUNCHER_IMAGE_NAME}" | cut -d : -f2 -s) + + # Possible Docker install types are: + # native, boot2docker or moby + DOCKER_INSTALL_TYPE=$(get_docker_install_type) + + # User configurable variables + DEFAULT_CHE_PRODUCT_NAME="ECLIPSE CHE" + DEFAULT_CHE_MINI_PRODUCT_NAME="che" + DEFAULT_CHE_SERVER_CONTAINER_NAME="che-server" + DEFAULT_CHE_SERVER_IMAGE_NAME="eclipse/che-server" + DEFAULT_DOCKER_HOST_IP=$(get_docker_host_ip) + DEFAULT_CHE_HOSTNAME=$(get_che_hostname) + DEFAULT_CHE_PORT="8080" + DEFAULT_CHE_VERSION=$(get_che_launcher_version) + DEFAULT_CHE_RESTART_POLICY="no" + DEFAULT_CHE_USER="root" + DEFAULT_CHE_LOG_LEVEL="info" + DEFAULT_CHE_DEBUG_SERVER="false" + DEFAULT_CHE_DEBUG_SERVER_PORT="8000" + DEFAULT_CHE_DEBUG_SERVER_SUSPEND="false" + DEFAULT_CHE_DOCKER_MACHINE_HOST_EXTERNAL=$(get_docker_external_hostname) + + # Clean eventual user provided paths + # This is a user-provided override + CHE_CONF=${CHE_CONF:+$(get_converted_and_clean_path "${CHE_CONF}")} + CHE_CONF_LOCATION="${CHE_CONF}":"/conf:Z" + # "<-- Added comment with quote to fix broken syntax highlighting + + # This is a user-provided override + # If this is not provided by the user, we will not volume mount it and use the internal values + CHE_ASSEMBLY=${CHE_ASSEMBLY:+$(get_converted_and_clean_path "${CHE_ASSEMBLY}")} + CHE_ASSEMBLY_LOCATION="${CHE_ASSEMBLY}":"/assembly:Z" + # "<-- Added comment with quote to fix broken syntax highlighting + + DEFAULT_CHE_DATA_FOLDER="/home/user/che" + CHE_DATA=${CHE_DATA:-${DEFAULT_CHE_DATA_FOLDER}} + CHE_DATA=$(get_converted_and_clean_path "${CHE_DATA}") + CHE_DATA_LOCATION="${CHE_DATA}":"/data:Z" + # "<-- Added comment with quote to fix broken syntax highlighting + + CHE_PRODUCT_NAME=${CHE_PRODUCT_NAME:-${DEFAULT_CHE_PRODUCT_NAME}} + CHE_MINI_PRODUCT_NAME=${CHE_MINI_PRODUCT_NAME:-${DEFAULT_CHE_MINI_PRODUCT_NAME}} + CHE_SERVER_CONTAINER_NAME=${CHE_SERVER_CONTAINER_NAME:-${DEFAULT_CHE_SERVER_CONTAINER_NAME}} + CHE_SERVER_IMAGE_NAME=${CHE_SERVER_IMAGE_NAME:-${DEFAULT_CHE_SERVER_IMAGE_NAME}} + CHE_HOSTNAME=${CHE_HOSTNAME:-${DEFAULT_CHE_HOSTNAME}} + CHE_PORT=${CHE_PORT:-${DEFAULT_CHE_PORT}} + CHE_VERSION=${CHE_VERSION:-${DEFAULT_CHE_VERSION}} + CHE_RESTART_POLICY=${CHE_RESTART_POLICY:-${DEFAULT_CHE_RESTART_POLICY}} + CHE_USER=${CHE_USER:-${DEFAULT_CHE_USER}} + CHE_HOST_IP=${CHE_HOST_IP:-${DEFAULT_DOCKER_HOST_IP}} + CHE_LOG_LEVEL=${CHE_LOG_LEVEL:-${DEFAULT_CHE_LOG_LEVEL}} + CHE_DEBUG_SERVER=${CHE_DEBUG_SERVER:-${DEFAULT_CHE_DEBUG_SERVER}} + CHE_DEBUG_SERVER_PORT=${CHE_DEBUG_SERVER_PORT:-${DEFAULT_CHE_DEBUG_SERVER_PORT}} + CHE_DEBUG_SERVER_SUSPEND=${CHE_DEBUG_SERVER_SUSPEND:-${DEFAULT_CHE_DEBUG_SERVER_SUSPEND}} + CHE_DOCKER_MACHINE_HOST_EXTERNAL=${CHE_DOCKER_MACHINE_HOST_EXTERNAL:-${DEFAULT_CHE_DOCKER_MACHINE_HOST_EXTERNAL}} + + USAGE=" +Usage: + docker run --rm -t -v /var/run/docker.sock:/var/run/docker.sock ${LAUNCHER_IMAGE_NAME} [COMMAND] + start Starts ${CHE_MINI_PRODUCT_NAME} server + stop [] Stops ${CHE_MINI_PRODUCT_NAME} server + restart Restart ${CHE_MINI_PRODUCT_NAME} server + update Pull latest version of ${CHE_SERVER_IMAGE_NAME} + info Print some debugging information +" +} + +parse_command_line () { + if [ $# -eq 0 ]; then + usage + exit + fi + + case $1 in + start|stop|restart|update|info) + CHE_SERVER_ACTION=$1 + ;; + -h|--help) + usage + exit + ;; + *) + # unknown option + error_exit "You passed an unknown command line option." + ;; + esac +} + +# See: https://sipb.mit.edu/doc/safe-shell/ +set -e +set -u + +init_logging +check_docker +init_global_variables +parse_command_line "$@" + +case ${CHE_SERVER_ACTION} in + start) + start_che_server + ;; + stop) + shift + stop_che_server $@ + ;; + restart) + shift + restart_che_server $@ + ;; + update) + update_che_server + ;; + info) + print_debug_info + ;; +esac diff --git a/dockerfiles/launcher/launcher_cmds.sh b/dockerfiles/launcher/launcher_cmds.sh new file mode 100644 index 00000000000..185f5de9e25 --- /dev/null +++ b/dockerfiles/launcher/launcher_cmds.sh @@ -0,0 +1,163 @@ +#!/bin/sh +# Copyright (c) 2012-2016 Codenvy, S.A., 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: +# Mario Loriedo - Initial implementation +# + +start_che_server() { + if che_container_exist_by_name ${CHE_SERVER_CONTAINER_NAME}; then + error_exit "A container running ${CHE_PRODUCT_NAME} named \"${CHE_SERVER_CONTAINER_NAME}\" already exists. + 1. Use \"info\" to find it's URL. + 2. Use \"restart\" to stop it and start anew. + 3. Stop it with \"stop\". + 4. Remove it manually (docker rm -f ${CHE_SERVER_CONTAINER_NAME}) and try again. Or: + 5. Set CHE_SERVER_CONTAINER_NAME to a different value and try again." + fi + + CURRENT_IMAGE=$(docker images -q "${CHE_SERVER_IMAGE_NAME}":"${CHE_VERSION}") + + if [ "${CURRENT_IMAGE}" != "" ]; then + info "${CHE_PRODUCT_NAME}: Found image ${CHE_SERVER_IMAGE_NAME}:${CHE_VERSION}" + else + update_che_server + fi + + info "${CHE_PRODUCT_NAME}: Starting container..." + docker_run_with_debug "${CHE_SERVER_IMAGE_NAME}":"${CHE_VERSION}" > /dev/null + CURRENT_CHE_SERVER_CONTAINER_ID=$(get_che_server_container_id ${CHE_SERVER_CONTAINER_NAME}) + wait_until_container_is_running 10 ${CURRENT_CHE_SERVER_CONTAINER_ID} + if ! che_container_is_running ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + error_exit "${CHE_PRODUCT_NAME}: Timeout waiting for ${CHE_PRODUCT_NAME} container to start." + fi + + info "${CHE_PRODUCT_NAME}: Server logs at \"docker logs -f ${CHE_SERVER_CONTAINER_NAME}\"" + info "${CHE_PRODUCT_NAME}: Server booting..." + wait_until_server_is_booted 60 ${CURRENT_CHE_SERVER_CONTAINER_ID} + + if server_is_booted ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + info "${CHE_PRODUCT_NAME}: Booted and reachable" + info "${CHE_PRODUCT_NAME}: Ver: $(get_server_version ${CURRENT_CHE_SERVER_CONTAINER_ID})" + if ! is_docker_for_mac; then + info "${CHE_PRODUCT_NAME}: Use: http://${CHE_HOST_IP}:${CHE_PORT}" + info "${CHE_PRODUCT_NAME}: API: http://${CHE_HOST_IP}:${CHE_PORT}/swagger" + else + info "${CHE_PRODUCT_NAME}: Use: http://localhost:${CHE_PORT}" + info "${CHE_PRODUCT_NAME}: API: http://localhost:${CHE_PORT}/swagger" + fi + + if has_debug; then + info "${CHE_PRODUCT_NAME}: JPDA Debug - http://${CHE_HOST_IP}:${CHE_DEBUG_SERVER_PORT}" + fi + else + error_exit "${CHE_PRODUCT_NAME}: Timeout waiting for server. Run \"docker logs ${CHE_SERVER_CONTAINER_NAME}\" to inspect the issue." + fi +} + +stop_che_server() { + if [ $# -gt 0 ]; then + CURRENT_CHE_SERVER_CONTAINER_ID=$1 + else + CURRENT_CHE_SERVER_CONTAINER_ID=$(get_che_server_container_id ${CHE_SERVER_CONTAINER_NAME}) + fi + + if ! che_container_is_running $CURRENT_CHE_SERVER_CONTAINER_ID; then + info "${CHE_PRODUCT_NAME}: Container $CURRENT_CHE_SERVER_CONTAINER_ID is not running. Nothing to do." + else + info "${CHE_PRODUCT_NAME}: Stopping server..." + docker stop -t 300 ${CURRENT_CHE_SERVER_CONTAINER_ID} > /dev/null + if che_container_is_running ${CURRENT_CHE_SERVER_CONTAINER_ID}; then + error_exit "${CHE_PRODUCT_NAME}: Timeout waiting for the ${CHE_PRODUCT_NAME} container to stop." + fi + + info "${CHE_PRODUCT_NAME}: Removing container" + docker rm ${CURRENT_CHE_SERVER_CONTAINER_ID} > /dev/null + info "${CHE_PRODUCT_NAME}: Stopped" + fi +} + +restart_che_server() { + if [ $# -gt 0 ]; then + CURRENT_CHE_SERVER_CONTAINER_ID=$1 + else + CURRENT_CHE_SERVER_CONTAINER_ID=$(get_che_server_container_id ${CHE_SERVER_CONTAINER_NAME}) + fi + + if che_container_is_running $CURRENT_CHE_SERVER_CONTAINER_ID; then + stop_che_server $CURRENT_CHE_SERVER_CONTAINER_ID + fi + + start_che_server +} + +update_che_server() { + if [ -z "${CHE_VERSION}" ]; then + CHE_VERSION=${DEFAULT_CHE_VERSION} + fi + + info "${CHE_PRODUCT_NAME}: Pulling image ${CHE_SERVER_IMAGE_NAME}:${CHE_VERSION}" + execute_command_with_progress extended docker pull ${CHE_SERVER_IMAGE_NAME}:${CHE_VERSION} +} + +print_debug_info() { + info "---------------------------------------" + info "--------- LAUNCHER INFO ------------" + info "---------------------------------------" + info "" + info "--------- PLATFORM INFO -------------" + info "DOCKER_INSTALL_TYPE = ${DOCKER_INSTALL_TYPE}" + info "DOCKER_HOST_OS = $(get_docker_host_os)" + info "DOCKER_HOST_IP = ${DEFAULT_DOCKER_HOST_IP}" + info "DOCKER_HOST_EXTERNAL_IP = ${DEFAULT_CHE_DOCKER_MACHINE_HOST_EXTERNAL:-not set}" + info "DOCKER_DAEMON_VERSION = $(get_docker_daemon_version)" + info "" + info "" + info "--------- CHE INSTANCE LIST ----------" + CURRENT_CHE_INSTANCES=$(docker ps -aq --filter "ancestor=${CHE_SERVER_IMAGE_NAME}:${CHE_VERSION}") + IFS=$'\n' + for CHE_SERVER_CONTAINER_ID in $CURRENT_CHE_INSTANCES; do + info "" + info "--------- CHE INSTANCE: $CHE_SERVER_CONTAINER_ID" + CURRENT_CHE_SERVER_CONTAINER_NAME=$(docker inspect --format='{{.Name}}' ${CHE_SERVER_CONTAINER_ID} | cut -f2 -d"/") + info "CHE SERVER CONTAINER NANE = $CURRENT_CHE_SERVER_CONTAINER_NAME" + info "CHE CONTAINER EXISTS = $(che_container_exist $CHE_SERVER_CONTAINER_ID && echo "YES" || echo "NO")" + info "CHE CONTAINER STATUS = $(che_container_is_running $CHE_SERVER_CONTAINER_ID && echo "running" || echo "stopped")" + if che_container_is_running $CHE_SERVER_CONTAINER_ID; then + info "CHE SERVER STATUS = $(server_is_booted $CHE_SERVER_CONTAINER_ID && echo "running & api reachable" || echo "stopped")" + info "CHE VERSION = $(get_server_version $CHE_SERVER_CONTAINER_ID)" + info "CHE IMAGE = $(get_che_container_image_name $CHE_SERVER_CONTAINER_ID)" + info "CHE CONF = $(get_che_container_conf_folder $CHE_SERVER_CONTAINER_ID)" + info "CHE DATA = $(get_che_container_data_folder $CHE_SERVER_CONTAINER_ID)" + CURRENT_CHE_HOST_IP=$(get_che_container_host_ip_from_container $CHE_SERVER_CONTAINER_ID) + CURRENT_CHE_PORT=$(docker inspect --format='{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' ${CHE_SERVER_CONTAINER_ID}) + info "CHE USE URL = http://${CURRENT_CHE_HOST_IP}:${CURRENT_CHE_PORT}" + info "CHE API URL = http://${CURRENT_CHE_HOST_IP}:${CURRENT_CHE_PORT}/swagger" + if has_container_debug $CHE_SERVER_CONTAINER_ID; then + CURRENT_CHE_DEBUG_PORT=$(docker inspect --format='{{ (index (index .NetworkSettings.Ports "8000/tcp") 0).HostPort }}' ${CHE_SERVER_CONTAINER_ID}) + info "CHE JPDA DEBUG URL = http://${CURRENT_CHE_HOST_IP}:${CURRENT_CHE_DEBUG_PORT}" + fi + info 'CHE LOGS = run `docker logs -f '${CURRENT_CHE_SERVER_CONTAINER_NAME}'`' + fi + done + info "" + info "" + info "---- CURRENT COMMAND LINE OPTIONS ---" + info "CHE_VERSION = ${CHE_VERSION}" + info "CHE_DATA = ${CHE_DATA}" + info "CHE_CONF = ${CHE_CONF:-not set}" + info "CHE_ASSEMBLY = ${CHE_ASSEMBLY:-not set}" + info "CHE_PORT = ${CHE_PORT}" + info "CHE_HOST_IP = ${CHE_HOST_IP}" + info "CHE_RESTART_POLICY = ${CHE_RESTART_POLICY}" + info "CHE_USER = ${CHE_USER}" + info "CHE_LOG_LEVEL = ${CHE_LOG_LEVEL}" + info "CHE_DEBUG_SERVER = ${CHE_DEBUG_SERVER}" + info "CHE_DEBUG_SERVER_PORT = ${CHE_DEBUG_SERVER_PORT}" + info "CHE_HOSTNAME = ${CHE_HOSTNAME}" + info "CHE_SERVER_CONTAINER_NAME = ${CHE_SERVER_CONTAINER_NAME}" + info "CHE_SERVER_IMAGE_NAME = ${CHE_SERVER_IMAGE_NAME}" +} \ No newline at end of file diff --git a/dockerfiles/launcher/launcher_funcs.sh b/dockerfiles/launcher/launcher_funcs.sh new file mode 100644 index 00000000000..fbbdb640d38 --- /dev/null +++ b/dockerfiles/launcher/launcher_funcs.sh @@ -0,0 +1,496 @@ +#!/bin/sh +# Copyright (c) 2012-2016 Codenvy, S.A., 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: +# Mario Loriedo - Initial implementation +# + +usage () { + printf "%s" "${USAGE}" +} + +info() { + printf "${GREEN}INFO:${NC} %s\n" "${1}" +} + +debug() { + printf "${BLUE}DEBUG:${NC} %s\n" "${1}" +} + +error() { + printf "${RED}ERROR:${NC} %s\n" "${1}" +} + +error_exit() { + echo "---------------------------------------" + error "!!!" + error " ${1}" + error "!!!" + echo "---------------------------------------" + exit 1 +} + +convert_windows_to_posix() { + # "/some/path" => /some/path + OUTPUT_PATH=${1//\"} + echo "/"$(echo "$OUTPUT_PATH" | sed 's/\\/\//g' | sed 's/://') +} + +get_clean_path() { + INPUT_PATH=$1 + # \some\path => /some/path + OUTPUT_PATH=$(echo ${INPUT_PATH} | tr '\\' '/') + # /somepath/ => /somepath + OUTPUT_PATH=${OUTPUT_PATH%/} + # /some//path => /some/path + OUTPUT_PATH=$(echo ${OUTPUT_PATH} | tr -s '/') + # "/some/path" => /some/path + OUTPUT_PATH=${OUTPUT_PATH//\"} + echo ${OUTPUT_PATH} +} + +get_converted_and_clean_path() { + CONVERTED_PATH=$(convert_windows_to_posix "${1}") + CLEAN_PATH=$(get_clean_path "${CONVERTED_PATH}") + echo $CLEAN_PATH +} + +get_che_launcher_container_id() { + hostname +} + +get_che_launcher_version() { + if [ -n "${LAUNCHER_IMAGE_VERSION}" ]; then + echo "${LAUNCHER_IMAGE_VERSION}" + else + echo "latest" + fi +} + +is_boot2docker() { + if uname -r | grep -q 'boot2docker'; then + return 0 + else + return 1 + fi +} + +has_docker_for_windows_ip() { + if [ "${ETH0_ADDRESS}" = "10.0.75.2" ]; then + return 0 + else + return 1 + fi +} + +is_docker_for_mac() { + if uname -r | grep -q 'moby' && ! has_docker_for_windows_ip; then + return 0 + else + return 1 + fi +} + +is_docker_for_windows() { + if uname -r | grep -q 'moby' && has_docker_for_windows_ip; then + return 0 + else + return 1 + fi +} + +docker_run() { + ENV_FILE=$(get_list_of_che_system_environment_variables) + docker run -d --name "${CHE_SERVER_CONTAINER_NAME}" \ + -v /var/run/docker.sock:/var/run/docker.sock:Z \ + -v "$CHE_DATA_LOCATION" \ + -p "${CHE_PORT}":"${CHE_PORT}" \ + --restart="${CHE_RESTART_POLICY}" \ + --user="${CHE_USER}" \ + -e "CHE_LOG_LEVEL=${CHE_LOG_LEVEL}" \ + -e "CHE_IP=$CHE_HOST_IP" \ + --env-file=$ENV_FILE \ + "$@" + + rm -rf $ENV_FILE > /dev/null +} + +docker_run_if_in_vm() { + # If the container will run inside of a VM, additional parameters must be set. + # Setting CHE_IN_VM=true will have the che-server container set the values. + if is_docker_for_mac || is_docker_for_windows || is_boot2docker; then + docker_run -e "CHE_IN_VM=true" "$@" + else + docker_run "$@" + fi +} + +docker_run_with_assembly() { + if has_assembly; then + docker_run_if_in_vm -v "$CHE_ASSEMBLY_LOCATION" -e "CHE_ASSEMBLY=${CHE_ASSEMBLY}" "$@" + else + docker_run_if_in_vm "$@" + fi +} + +docker_run_with_conf() { + if has_che_conf_path; then + docker_run_with_assembly -v "$CHE_CONF_LOCATION" -e "CHE_LOCAL_CONF_DIR=${CHE_CONF}" "$@" + else + docker_run_with_assembly "$@" + fi +} + +docker_run_with_external_hostname() { + if has_external_hostname; then + docker_run_with_conf -e "CHE_DOCKER_MACHINE_HOST_EXTERNAL=${CHE_DOCKER_MACHINE_HOST_EXTERNAL}" "$@" + else + docker_run_with_conf "$@" + fi +} + +docker_run_with_debug() { + if has_debug && has_debug_suspend; then + docker_run_with_external_hostname -p "${CHE_DEBUG_SERVER_PORT}":8000 \ + -e "CHE_DEBUG_SERVER=true" \ + -e "JPDA_SUSPEND=y" "$@" + elif has_debug; then + docker_run_with_external_hostname -p "${CHE_DEBUG_SERVER_PORT}":8000 \ + -e "CHE_DEBUG_SERVER=true" "$@" + else + docker_run_with_external_hostname "$@" + fi +} + +has_debug_suspend() { + if [ "${CHE_DEBUG_SERVER_SUSPEND}" = "false" ]; then + return 1 + else + return 0 + fi +} + +has_debug() { + if [ "${CHE_DEBUG_SERVER}" = "false" ]; then + return 1 + else + return 0 + fi +} + +has_che_conf_path() { + if [ "${CHE_CONF}" = "" ]; then + return 1 + else + return 0 + fi +} + +has_assembly() { + if [ "${CHE_ASSEMBLY}" = "" ]; then + return 1 + else + return 0 + fi +} + +has_external_hostname() { + if [ "${CHE_DOCKER_MACHINE_HOST_EXTERNAL}" = "" ]; then + return 1 + else + return 0 + fi +} + +get_list_of_che_system_environment_variables() { + # See: http://stackoverflow.com/questions/4128235/what-is-the-exact-meaning-of-ifs-n + IFS=$'\n' + + DOCKER_ENV=$(mktemp) + + # First grab all known CHE_ variables + CHE_VARIABLES=$(env | grep CHE_) + for SINGLE_VARIABLE in "${CHE_VARIABLES}"; do + echo "${SINGLE_VARIABLE}" >> $DOCKER_ENV + done + + + # Add in known proxy variables + if [ ! -z ${http_proxy+x} ]; then + echo "http_proxy=${http_proxy}" >> $DOCKER_ENV + fi + + if [ ! -z ${https_proxy+x} ]; then + echo "https_proxy=${https_proxy}" >> $DOCKER_ENV + fi + + if [ ! -z ${no_proxy+x} ]; then + echo "no_proxy=${no_proxy}" >> $DOCKER_ENV + fi + + echo $DOCKER_ENV +} + + +get_docker_install_type() { + if is_boot2docker; then + echo "boot2docker" + elif is_docker_for_windows; then + echo "docker4windows" + elif is_docker_for_mac; then + echo "docker4mac" + else + echo "native" + fi +} + +get_docker_host_ip() { + case $(get_docker_install_type) in + boot2docker) + echo $ETH1_ADDRESS + ;; + native) + echo $DOCKER0_ADDRESS + ;; + *) + echo $ETH0_ADDRESS + ;; + esac +} + +get_docker_host_os() { + docker info | grep "Operating System:" | sed "s/^Operating System: //" +} + +get_docker_daemon_version() { + docker version | grep -i "server version:" | sed "s/^server version: //I" +} + +get_che_hostname() { + INSTALL_TYPE=$(get_docker_install_type) + if [ "${INSTALL_TYPE}" = "boot2docker" ]; then + echo $DEFAULT_DOCKER_HOST_IP + else + echo "localhost" + fi +} + +check_docker() { + if [ ! -S /var/run/docker.sock ]; then + error_exit "Docker socket (/var/run/docker.sock) hasn't be mounted \ +inside the container. Verify the syntax of the \"docker run\" command." + fi + + if ! docker ps > /dev/null 2>&1; then + output=$(docker ps) + error_exit "Error when running \"docker ps\": ${output}" + fi +} + +che_container_exist_by_name() { + docker inspect ${1} > /dev/null 2>&1 + if [ "$?" == "0" ]; then + return 0 + else + return 1 + fi +} + +che_container_exist() { + if [ "$(docker ps -aq -f "id=${1}" | wc -l)" -eq 0 ]; then + return 1 + else + return 0 + fi +} + +che_container_is_running() { + if [ "$(docker ps -qa -f "status=running" -f "id=${1}" | wc -l)" -eq 0 ]; then + return 1 + else + return 0 + fi +} + +che_container_is_stopped() { + if [ "$(docker ps -qa -f "status=exited" -f "name=${1}" | wc -l)" -eq 0 ]; then + return 1 + else + return 0 + fi +} + +contains() { + string="$1" + substring="$2" + if test "${string#*$substring}" != "$string" + then + return 0 # $substring is in $string + else + return 1 # $substring is not in $string + fi +} + +has_container_debug () { + if $(contains $(get_container_debug $1) ""); then + return 1 + else + return 0 + fi +} + +get_container_debug() { + CURRENT_CHE_DEBUG=$(docker inspect --format='{{.NetworkSettings.Ports}}' ${1}) + IFS=$' ' + for SINGLE_BIND in $CURRENT_CHE_DEBUG; do + case $SINGLE_BIND in + *8000/tcp:*) + echo $SINGLE_BIND | cut -f2 -d":" + ;; + *) + ;; + esac + done +} + +get_che_container_host_ip_from_container() { + BINDS=$(docker inspect --format="{{.Config.Env}}" "${1}" | cut -d '[' -f 2 | cut -d ']' -f 1) + + IFS=$' ' + for SINGLE_BIND in $BINDS; do + case $SINGLE_BIND in + *CHE_IP*) + echo $SINGLE_BIND | cut -f2 -d= + ;; + *) + ;; + esac + done +} + +get_che_container_host_bind_folder() { + BINDS=$(docker inspect --format="{{.HostConfig.Binds}}" "${2}" | cut -d '[' -f 2 | cut -d ']' -f 1) + + IFS=$' ' + for SINGLE_BIND in $BINDS; do + case $SINGLE_BIND in + *$1*) + echo $SINGLE_BIND | cut -f1 -d":" + ;; + *) + ;; + esac + done +} + +get_che_container_conf_folder() { + FOLDER=$(get_che_container_host_bind_folder "/conf:Z" $1) + echo "${FOLDER:=not set}" +} + +get_che_container_data_folder() { + FOLDER=$(get_che_container_host_bind_folder "/home/user/che/workspaces:Z" $1) + echo "${FOLDER:=not set}" +} + +get_che_container_image_name() { + docker inspect --format="{{.Config.Image}}" "${1}" +} + +get_che_server_container_id() { + docker inspect -f '{{.Id}}' ${1} +} + +get_docker_external_hostname() { + if is_docker_for_mac || is_docker_for_windows; then + echo "localhost" + else + echo "" + fi +} + +wait_until_container_is_running() { + CONTAINER_START_TIMEOUT=${1} + + ELAPSED=0 + until che_container_is_running ${2} || [ ${ELAPSED} -eq "${CONTAINER_START_TIMEOUT}" ]; do + sleep 1 + ELAPSED=$((ELAPSED+1)) + done +} + +wait_until_container_is_stopped() { + CONTAINER_STOP_TIMEOUT=${1} + + ELAPSED=0 + until che_container_is_stopped ${2} || [ ${ELAPSED} -eq "${CONTAINER_STOP_TIMEOUT}" ]; do + sleep 1 + ELAPSED=$((ELAPSED+1)) + done +} + +server_is_booted() { + HTTP_STATUS_CODE=$(curl -I http://$(docker inspect -f '{{.NetworkSettings.IPAddress}}' "${1}"):$CHE_PORT/api/ \ + -s -o /dev/null --write-out "%{http_code}") + if [ "${HTTP_STATUS_CODE}" = "200" ]; then + return 0 + else + return 1 + fi +} + +get_server_version() { + HTTP_STATUS_CODE=$(curl -X OPTIONS http://$(docker inspect -f '{{.NetworkSettings.IPAddress}}' \ + "${1}"):$CHE_PORT/api/ -s) + + FIRST=${HTTP_STATUS_CODE//\ /} + IFS=',' + for SINGLE_BIND in $FIRST; do + case $SINGLE_BIND in + *implementationVersion*) + echo ${SINGLE_BIND//\"} | cut -f2 -d":" | cut -f1 -d"}" + ;; + *) + ;; + esac + done +} + +wait_until_server_is_booted () { + SERVER_BOOT_TIMEOUT=${1} + + ELAPSED=0 + until server_is_booted ${2} || [ ${ELAPSED} -eq "${SERVER_BOOT_TIMEOUT}" ]; do + sleep 1 + ELAPSED=$((ELAPSED+1)) + done +} + +execute_command_with_progress() { + progress=$1 + command=$2 + shift 2 + + pid="" + + case "$progress" in + extended) + $command "$@" + ;; + basic|*) + $command "$@" &>/dev/null & + pid=$! + while kill -0 "$pid" >/dev/null 2>&1; do + printf "#" + sleep 10 + done + wait $pid # return pid's exit code + printf "\n" + ;; + esac + printf "\n" +} diff --git a/dockerfiles/launcher/launcher_test.bats b/dockerfiles/launcher/launcher_test.bats new file mode 100644 index 00000000000..fb8840df07d --- /dev/null +++ b/dockerfiles/launcher/launcher_test.bats @@ -0,0 +1,184 @@ +#!/usr/bin/env bats +# Copyright (c) 2012-2016 Codenvy, S.A., 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: +# Mario Loriedo - Initial implementation +# Tyler Jewell - Improvements +# +# To run the tests: +# docker run -w /tests/ -v $PWD:/tests dduportal/bats:0.4.0 /tests/launcher_test.bats +# + +source ./launcher_funcs.sh + +@test "clean folder path that is already clean" { + result="$(get_clean_path /somefolder)" + [ "$result" = "/somefolder" ] +} + +@test "clean folder path with extra slash" { + result="$(get_clean_path /somefolder/)" + [ "$result" = "/somefolder" ] +} + +@test "clean folder path with two consecutive slashes" { + result="$(get_clean_path /some//path)" + [ "$result" = "/some/path" ] +} + +@test "clean folder path with backslashes" { + result="$(get_clean_path \\some\\path)" + [ "$result" = "/some/path" ] +} + +@test "clean folder path with quotes" { + result="$(get_clean_path \"/some\"/path\")" + [ "$result" = "/some/path" ] +} + +@test "wait for che container that never stops" { + export CHE_SERVER_CONTAINER_NAME="wait-for-che-test1" + docker run -d --name ${CHE_SERVER_CONTAINER_NAME} alpine:3.4 ping localhost + wait_until_container_is_stopped 2 + run che_container_is_stopped + docker rm -f ${CHE_SERVER_CONTAINER_NAME} + [ "$status" -eq 1 ] +} + +@test "wait for che container that stops" { + export CHE_SERVER_CONTAINER_NAME="wait-for-che-test2" + docker run -d --name ${CHE_SERVER_CONTAINER_NAME} alpine:3.4 ping -c 2 localhost + wait_until_container_is_stopped 3 + run che_container_is_stopped + docker rm -f ${CHE_SERVER_CONTAINER_NAME} + [ "$status" -eq 0 ] +} + +@test "get container conf folder that is set" { + # Given + export CHE_SERVER_CONTAINER_NAME="che-test-get-container-conf-folder" + CONF_FOLDER=$(pwd)/che-test-conf + mkdir ${CONF_FOLDER} + docker run --name ${CHE_SERVER_CONTAINER_NAME} -v ${CONF_FOLDER}:/conf alpine:3.4 true + + # When + result="$(get_che_container_conf_folder)" + docker rm -f ${CHE_SERVER_CONTAINER_NAME} + rmdir ${CONF_FOLDER} + + # Then + [ "$result" = "${CONF_FOLDER}" ] +} + +@test "get container conf folder that is not set" { + # Given + export CHE_SERVER_CONTAINER_NAME="che-test-get-container-conf-folder" + docker run --name ${CHE_SERVER_CONTAINER_NAME} alpine:3.4 true + + # When + result="$(get_che_container_conf_folder)" + docker rm -f ${CHE_SERVER_CONTAINER_NAME} + + # Then + [ "$result" = "not set" ] +} + +@test "get container data folder" { + # Given + export CHE_SERVER_CONTAINER_NAME="che-test-get-container-data-folder" + DATA_FOLDER=$(pwd)/che-test-data + mkdir ${DATA_FOLDER} + docker run --name ${CHE_SERVER_CONTAINER_NAME} -v ${DATA_FOLDER}:/home/user/che/workspaces/ alpine:3.4 true + + # When + result="$(get_che_container_data_folder)" + docker rm -f ${CHE_SERVER_CONTAINER_NAME} + rmdir ${DATA_FOLDER} + + # Then + [ "$result" = "${DATA_FOLDER}" ] +} + +@test "get image name" { + # Given + export CHE_SERVER_CONTAINER_NAME="che-test-get-container-image-name" + docker run --name ${CHE_SERVER_CONTAINER_NAME} alpine:3.4 true + + # When + result="$(get_che_container_image_name)" + docker rm -f ${CHE_SERVER_CONTAINER_NAME} + + # Then + [ "$result" = "alpine:3.4" ] +} + +@test "get che server container id" { + # Given + export CHE_SERVER_CONTAINER_NAME="che-test-get-container-id" + long_id=$(docker run -d --name ${CHE_SERVER_CONTAINER_NAME} alpine:3.4 true) + short_id=${long_id:0:12} + + # When + result="$(get_che_server_container_id)" + docker rm -f ${CHE_SERVER_CONTAINER_NAME} + + # Then + [ "$result" = "$short_id" ] +} + +@test "get docker daemon version" { + # When + result="$(get_docker_daemon_version)" + + # Then + [ "$result" ] +} + +@test "get docker host os" { + # When + result="$(get_docker_host_os)" + + # Then + [ "$result" ] +} + +@test "get che get che launcher version with nightly" { + # Given + export CHE_SERVER_CONTAINER_NAME="che-test-get-che-launcher-version" + long_id=$(docker run -d --name ${CHE_SERVER_CONTAINER_NAME} --entrypoint=true eclipse/che-launcher:nightly) + + get_che_launcher_container_id() { + echo ${long_id:0:12} + } + + # When + result="$(get_che_launcher_version)" + docker rm $CHE_SERVER_CONTAINER_NAME + + # Then + [ "$result" = "nightly" ] +} + +@test "get che get che launcher version with no specific version" { + # Given + export CHE_SERVER_CONTAINER_NAME="che-test-get-che-launcher-version" + long_id=$(docker run -d --name ${CHE_SERVER_CONTAINER_NAME} --entrypoint=true eclipse/che-launcher) + + get_che_launcher_container_id() { + echo ${long_id:0:12} + } + + # When + result="$(get_che_launcher_version)" + docker rm $CHE_SERVER_CONTAINER_NAME + + echo "expected: latest" + echo "actual: $result" + + # Then + [ "$result" = "latest" ] +} diff --git a/dockerfiles/lib-typescript/.babelrc b/dockerfiles/lib-typescript/.babelrc new file mode 100644 index 00000000000..c13c5f627fd --- /dev/null +++ b/dockerfiles/lib-typescript/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} diff --git a/dockerfiles/lib-typescript/.dockerignore b/dockerfiles/lib-typescript/.dockerignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/dockerfiles/lib-typescript/.dockerignore @@ -0,0 +1 @@ +node_modules diff --git a/dockerfiles/lib-typescript/.gitignore b/dockerfiles/lib-typescript/.gitignore new file mode 100644 index 00000000000..c6249c9b894 --- /dev/null +++ b/dockerfiles/lib-typescript/.gitignore @@ -0,0 +1,5 @@ +lib +node_modules +npm-debug.log +src/typings +coverage diff --git a/dockerfiles/lib-typescript/Dockerfile b/dockerfiles/lib-typescript/Dockerfile new file mode 100644 index 00000000000..778d7a4c7cb --- /dev/null +++ b/dockerfiles/lib-typescript/Dockerfile @@ -0,0 +1,32 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Codenvy, S.A. - Initial implementation +# + +FROM mhart/alpine-node:6 + +ENV DOCKER_BUCKET=get.docker.com \ + DOCKER_VERSION=1.6.0 + +RUN set -x \ + && apk add --no-cache \ + ca-certificates \ + curl \ + openssl \ + && curl -sL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" \ + > /usr/bin/docker; chmod +x /usr/bin/docker \ + && apk del curl ca-certificates openssl + +COPY runtime-dependencies/package.json /runtime/ +COPY . /lib-typescript/ + +RUN cd /lib-typescript/ && npm install \ + && cd /runtime && npm install && /lib-typescript/node_modules/.bin/tsc --project /lib-typescript/ \ + && mv /lib-typescript/lib /che-lib && cd /lib-typescript/src && find . -name "*.properties" -exec install -D {} /che-lib/{} \;\ + && rm -rf /lib-typescript && mv /runtime/node_modules /che-lib && rm -rf /runtime + diff --git a/dockerfiles/lib-typescript/Dockerfile.dev b/dockerfiles/lib-typescript/Dockerfile.dev new file mode 100644 index 00000000000..3ba203bc43d --- /dev/null +++ b/dockerfiles/lib-typescript/Dockerfile.dev @@ -0,0 +1,30 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Codenvy, S.A. - Initial implementation +# + +FROM mhart/alpine-node:6 + +ENV DOCKER_BUCKET=get.docker.com \ + DOCKER_VERSION=1.6.0 + +COPY package.json /compile/ +COPY runtime-dependencies/package.json /runtime/ +RUN set -x \ + && apk add --no-cache \ + ca-certificates \ + curl \ + openssl \ + && curl -sL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" \ + > /usr/bin/docker; chmod +x /usr/bin/docker \ + && apk del curl ca-certificates openssl \ + && cd /compile && npm install && cd /runtime && npm install \ + && mkdir /lib-typescript && mv /compile/node_modules /lib-typescript/ +COPY . /lib-typescript/ +RUN /lib-typescript/node_modules/.bin/tsc --project /lib-typescript/ && mv /lib-typescript/lib /che-lib \ + && rm -rf /lib-typescript && mv /runtime/node_modules /che-lib && rm -rf /runtime && rm -rf /compile diff --git a/dockerfiles/lib-typescript/README.md b/dockerfiles/lib-typescript/README.md new file mode 100644 index 00000000000..4f373efaa1f --- /dev/null +++ b/dockerfiles/lib-typescript/README.md @@ -0,0 +1,8 @@ +# Typescript library used in some docker images like che-dir, che-action and che-test + + +Steps to build the docker image: + +``` +$ build.sh +``` \ No newline at end of file diff --git a/dockerfiles/lib-typescript/build.sh b/dockerfiles/lib-typescript/build.sh new file mode 100755 index 00000000000..0a163bb5219 --- /dev/null +++ b/dockerfiles/lib-typescript/build.sh @@ -0,0 +1,65 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-lib-typescript" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +DIR=$(cd "$(dirname "$0")"; pwd) + +generate_dto() { + echo "Checking DTO" + + # if file already exists and in snapshot mode + POM_VERSION=$(cat ${DIR}/dto-pom.xml | grep "^ .*$" | awk -F'[><]' '{print $3}') + if [ -e "${DIR}/src/api/dto/che-dto.ts" ]; then + # DTO file exists, Do we have snapshot ? + if [[ ${POM_VERSION} != *"SNAPSHOT" ]] + then + if [ ${DIR}/src/api/dto/che-dto.ts -nt ${DIR}/dto-pom.xml ]; then + echo "Using tagged version and dto file is up-to-date. Not generating it." + return + else + echo "Using tagged version but DTO file is older than dto-pom.xml file. Need to generate again." + fi + else + echo "Snapshot version is used in pom.xml. Generating again pom.xml"; + fi + fi + + DTO_CONTENT=$(cd $DIR && docker run -i --rm -v "$HOME/.m2:/root/.m2" -v "$PWD"/dto-pom.xml:/usr/src/mymaven/pom.xml -w /usr/src/mymaven maven:3.3-jdk-8 /bin/bash -c "mvn -q -DskipTests=true -Dfindbugs.skip=true -Dskip-validate-sources install && cat target/dto-typescript.ts") + + # Check if maven command has worked or not + if [ $? -eq 0 ]; then + # Create directory if it doesn't exist + if [ ! -d "${DIR}/src/api/dto" ]; then + mkdir ${DIR}/src/api/dto + fi + echo 'DTO has been generated' + echo "${DTO_CONTENT}" > ${DIR}/src/api/dto/che-dto.ts + else + echo "Failure when generating DTO. Error was ${DTO_CONTENT}" + exit 1 + fi +} + + +native_build() { + ./node_modules/typescript/bin/tsc --project . +} + +init +generate_dto + +DIR=$(cd "$(dirname "$0")"; pwd) +echo "Building Docker Image ${IMAGE_NAME} from $DIR directory with tag $TAG" +cd $DIR && docker build -t ${IMAGE_NAME}:${TAG} . +if [ $? -eq 0 ]; then + echo "${GREEN}Script run successfully: ${BLUE}${IMAGE_NAME}:${TAG}${NC}" +else + echo "${RED}Failure when building docker image ${IMAGE_NAME}:${TAG}${NC}" + exit 1 +fi diff --git a/dockerfiles/lib-typescript/dto-pom.xml b/dockerfiles/lib-typescript/dto-pom.xml new file mode 100644 index 00000000000..ecdb5515ab4 --- /dev/null +++ b/dockerfiles/lib-typescript/dto-pom.xml @@ -0,0 +1,123 @@ + + + + + 4.0.0 + + maven-depmgt-pom + org.eclipse.che.depmgt + 5.0.0-M7 + + dto-typescript + pom + Che TypeScript DTO + + 5.0.0-M7 + + + + codenvy-public-repo + codenvy public + https://maven.codenvycorp.com/content/groups/public/ + + + codenvy-public-snapshots-repo + codenvy public snapshots + https://maven.codenvycorp.com/content/repositories/codenvy-public-snapshots/ + + + + + codenvy-public-repo + codenvy public + https://maven.codenvycorp.com/content/groups/public/ + + + codenvy-public-snapshots-repo + codenvy public snapshots + https://maven.codenvycorp.com/content/repositories/codenvy-public-snapshots/ + + + + + + org.eclipse.che.core + che-core-typescript-dto-maven-plugin + ${che.version} + + + + build + + + + + + org.eclipse.che.core + che-core-api-agent-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-debug-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-factory-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-git-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-machine-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-project-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-project-templates-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-ssh-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-user-shared + ${che.version} + + + org.eclipse.che.core + che-core-api-workspace-shared + ${che.version} + + + + false + + + + + diff --git a/dockerfiles/lib-typescript/package.json b/dockerfiles/lib-typescript/package.json new file mode 100644 index 00000000000..5a4bae84844 --- /dev/null +++ b/dockerfiles/lib-typescript/package.json @@ -0,0 +1,33 @@ +{ + "name": "che-typescript", + "version": "1.0.0", + "description": "TypeScript library used in dockerfiles", + "main": "lib/index.js", + "author": "Florent Benoit", + "license": "EPL-1.0", + "scripts": { + "prepublish": "./node_modules/.bin/tsc", + "pretest": "./node_modules/.bin/tsc --outDir test --target es6 src/**/*.spec.ts src/**/**/*.spec.ts", + "coverage": "./node_modules/.bin/istanbul --include-all-sources cover node_modules/.bin/_mocha -- -R spec test/*.spec.js && ./node_modules/.bin/remap-istanbul -i coverage/coverage.json -o coverage/html -t html && open coverage/html/index.html", + "test": "./node_modules/.bin/mocha --compilers js:babel-register --require babel-polyfill --recursive" + }, + "dependencies": { + "reflect-metadata": "^0.1.8", + "websocket": "1.0.23" + }, + "devDependencies": { + "babel": "^6.5.2", + "babel-polyfill": "^6.16.0", + "@types/mocha": "^2.2.32", + "@types/node": "^6.0.41", + "@types/reflect-metadata": "0.0.4", + "babel": "^6.5.2", + "babel-preset-es2015": "^6.16.0", + "babel-register": "^6.16.3", + "chai": "^3.4.33", + "istanbul": "^0.4.5", + "mocha": "^2.2.32", + "remap-istanbul": "^0.6.4", + "typescript": "^2.0.3" + } +} diff --git a/dockerfiles/lib-typescript/runtime-dependencies/package.json b/dockerfiles/lib-typescript/runtime-dependencies/package.json new file mode 100644 index 00000000000..217fd1f81b9 --- /dev/null +++ b/dockerfiles/lib-typescript/runtime-dependencies/package.json @@ -0,0 +1,12 @@ +{ + "name": "che-typescript", + "version": "1.0.0", + "description": "TypeScript library used in dockerfiles", + "main": "lib/index.js", + "author": "Florent Benoit", + "license": "EPL-1.0", + "devDependencies": { + "reflect-metadata": "^0.1.8", + "websocket": "1.0.23" + } +} diff --git a/dockerfiles/lib-typescript/src/api/dto/che-dto.ts b/dockerfiles/lib-typescript/src/api/dto/che-dto.ts new file mode 100644 index 00000000000..c31416028e5 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/dto/che-dto.ts @@ -0,0 +1,16543 @@ +// File has been generated automatically by Eclipse Che TypeScript DTO generator + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface MachineConfigDto { + getLimits(): org.eclipse.che.api.machine.shared.dto.MachineLimitsDto; + getServers(): Array; + setServers(arg0): void; + withType(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + setType(arg0): void; + getSource(): org.eclipse.che.api.machine.shared.dto.MachineSourceDto; + withSource(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + setSource(arg0): void; + withName(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + withLinks(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + withServers(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + isDev(): boolean; + withDev(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + setDev(arg0): void; + withEnvVariables(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + setLimits(arg0): void; + withLimits(arg0): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + getEnvVariables(): Map; + setEnvVariables(arg0): void; + getName(): string; + setName(arg0): void; + getType(): string; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class MachineConfigDtoImpl implements org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + + servers : Array; + dev : boolean; + envVariables : Map; + name : string; + links : Array; + source : org.eclipse.che.api.machine.shared.dto.MachineSourceDto; + type : string; + limits : org.eclipse.che.api.machine.shared.dto.MachineLimitsDto; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.servers = new Array(); + if (__jsonObject) { + if (__jsonObject.servers) { + __jsonObject.servers.forEach((item) => { + this.servers.push(new org.eclipse.che.api.machine.shared.dto.ServerConfDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.dev) { + this.dev = __jsonObject.dev; + } + } + this.envVariables = new Map(); + if (__jsonObject) { + if (__jsonObject.envVariables) { + let tmp : Array = Object.keys(__jsonObject.envVariables); + tmp.forEach((key) => { + this.envVariables.set(key, __jsonObject.envVariables[key]); + }); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.source) { + this.source = new org.eclipse.che.api.machine.shared.dto.MachineSourceDtoImpl(__jsonObject.source); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.limits) { + this.limits = new org.eclipse.che.api.machine.shared.dto.MachineLimitsDtoImpl(__jsonObject.limits); + } + } + + } + + getLimits() : org.eclipse.che.api.machine.shared.dto.MachineLimitsDto { + return this.limits; + } + getServers() : Array { + return this.servers; + } + setServers(servers : Array) : void { + this.servers = servers; + } + withType(type : string) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getSource() : org.eclipse.che.api.machine.shared.dto.MachineSourceDto { + return this.source; + } + withSource(source : org.eclipse.che.api.machine.shared.dto.MachineSourceDto) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.source = source; + return this; + } + setSource(source : org.eclipse.che.api.machine.shared.dto.MachineSourceDto) : void { + this.source = source; + } + withName(name : string) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.name = name; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.links = links; + return this; + } + withServers(servers : Array) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.servers = servers; + return this; + } + isDev() : boolean { + return this.dev; + } + withDev(dev : boolean) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.dev = dev; + return this; + } + setDev(dev : boolean) : void { + this.dev = dev; + } + withEnvVariables(envVariables : Map) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.envVariables = envVariables; + return this; + } + setLimits(limits : org.eclipse.che.api.machine.shared.dto.MachineLimitsDto) : void { + this.limits = limits; + } + withLimits(limits : org.eclipse.che.api.machine.shared.dto.MachineLimitsDto) : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + this.limits = limits; + return this; + } + getEnvVariables() : Map { + return this.envVariables; + } + setEnvVariables(envVariables : Map) : void { + this.envVariables = envVariables; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getType() : string { + return this.type; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.servers) { + let listArray = []; + this.servers.forEach((item) => { + listArray.push((item as org.eclipse.che.api.machine.shared.dto.ServerConfDtoImpl).toJson()); + json.servers = listArray; + }); + } + if (this.dev) { + json.dev = this.dev; + } + if (this.envVariables) { + let tmpMap : any = {}; + for (const [key, value] of this.envVariables.entries()) { + tmpMap[key] = value; + } + json.envVariables = tmpMap; + } + if (this.name) { + json.name = this.name; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.source) { + json.source = (this.source as org.eclipse.che.api.machine.shared.dto.MachineSourceDtoImpl).toJson(); + } + if (this.type) { + json.type = this.type; + } + if (this.limits) { + json.limits = (this.limits as org.eclipse.che.api.machine.shared.dto.MachineLimitsDtoImpl).toJson(); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface ExtendedMachineDto { + getServers(): Map; + setServers(arg0): void; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto; + withServers(arg0): org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto; + getAgents(): Array; + setAgents(arg0): void; + withAgents(arg0): org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto; + getAttributes(): Map; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class ExtendedMachineDtoImpl implements org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto { + + servers : Map; + attributes : Map; + agents : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.servers = new Map(); + if (__jsonObject) { + if (__jsonObject.servers) { + let tmp : Array = Object.keys(__jsonObject.servers); + tmp.forEach((key) => { + this.servers.set(key, new org.eclipse.che.api.workspace.shared.dto.ServerConf2DtoImpl(__jsonObject.servers[key])); + }); + } + } + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + this.agents = new Array(); + if (__jsonObject) { + if (__jsonObject.agents) { + __jsonObject.agents.forEach((item) => { + this.agents.push(item); + }); + } + } + + } + + getServers() : Map { + return this.servers; + } + setServers(servers : Map) : void { + this.servers = servers; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto { + this.attributes = attributes; + return this; + } + withServers(servers : Map) : org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto { + this.servers = servers; + return this; + } + getAgents() : Array { + return this.agents; + } + setAgents(agents : Array) : void { + this.agents = agents; + } + withAgents(agents : Array) : org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto { + this.agents = agents; + return this; + } + getAttributes() : Map { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.servers) { + let tmpMap : any = {}; + for (const [key, value] of this.servers.entries()) { + tmpMap[key] = (value as org.eclipse.che.api.workspace.shared.dto.ServerConf2DtoImpl).toJson(); + } + json.servers = tmpMap; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.agents) { + let listArray = []; + this.agents.forEach((item) => { + listArray.push(item); + json.agents = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface CommitRequest { + setMessage(arg0): void; + getFiles(): Array; + withMessage(arg0): org.eclipse.che.api.git.shared.CommitRequest; + isAll(): boolean; + setAmend(arg0): void; + withAmend(arg0): org.eclipse.che.api.git.shared.CommitRequest; + withAll(arg0): org.eclipse.che.api.git.shared.CommitRequest; + setFiles(arg0): void; + withFiles(arg0): org.eclipse.che.api.git.shared.CommitRequest; + isAmend(): boolean; + getMessage(): string; + setAll(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class CommitRequestImpl implements org.eclipse.che.api.git.shared.CommitRequest { + + all : boolean; + amend : boolean; + files : Array; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.all) { + this.all = __jsonObject.all; + } + } + if (__jsonObject) { + if (__jsonObject.amend) { + this.amend = __jsonObject.amend; + } + } + this.files = new Array(); + if (__jsonObject) { + if (__jsonObject.files) { + __jsonObject.files.forEach((item) => { + this.files.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + setMessage(message : string) : void { + this.message = message; + } + getFiles() : Array { + return this.files; + } + withMessage(message : string) : org.eclipse.che.api.git.shared.CommitRequest { + this.message = message; + return this; + } + isAll() : boolean { + return this.all; + } + setAmend(amend : boolean) : void { + this.amend = amend; + } + withAmend(amend : boolean) : org.eclipse.che.api.git.shared.CommitRequest { + this.amend = amend; + return this; + } + withAll(all : boolean) : org.eclipse.che.api.git.shared.CommitRequest { + this.all = all; + return this; + } + setFiles(files : Array) : void { + this.files = files; + } + withFiles(files : Array) : org.eclipse.che.api.git.shared.CommitRequest { + this.files = files; + return this; + } + isAmend() : boolean { + return this.amend; + } + getMessage() : string { + return this.message; + } + setAll(all : boolean) : void { + this.all = all; + } + + toJson() : any { + let json : any = {}; + + if (this.all) { + json.all = this.all; + } + if (this.amend) { + json.amend = this.amend; + } + if (this.files) { + let listArray = []; + this.files.forEach((item) => { + listArray.push(item); + json.files = listArray; + }); + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface ServerPropertiesDto { + setPath(arg0): void; + withPath(arg0): org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto; + getInternalUrl(): string; + getInternalAddress(): string; + setInternalAddress(arg0): void; + withInternalAddress(arg0): org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto; + setInternalUrl(arg0): void; + withInternalUrl(arg0): org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto; + getPath(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class ServerPropertiesDtoImpl implements org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto { + + path : string; + internalAddress : string; + internalUrl : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.internalAddress) { + this.internalAddress = __jsonObject.internalAddress; + } + } + if (__jsonObject) { + if (__jsonObject.internalUrl) { + this.internalUrl = __jsonObject.internalUrl; + } + } + + } + + setPath(path : string) : void { + this.path = path; + } + withPath(path : string) : org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto { + this.path = path; + return this; + } + getInternalUrl() : string { + return this.internalUrl; + } + getInternalAddress() : string { + return this.internalAddress; + } + setInternalAddress(internalAddress : string) : void { + this.internalAddress = internalAddress; + } + withInternalAddress(internalAddress : string) : org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto { + this.internalAddress = internalAddress; + return this; + } + setInternalUrl(internalUrl : string) : void { + this.internalUrl = internalUrl; + } + withInternalUrl(internalUrl : string) : org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto { + this.internalUrl = internalUrl; + return this; + } + getPath() : string { + return this.path; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.internalAddress) { + json.internalAddress = this.internalAddress; + } + if (this.internalUrl) { + json.internalUrl = this.internalUrl; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface CommandDto { + getCommandLine(): string; + withType(arg0): org.eclipse.che.api.machine.shared.dto.CommandDto; + setType(arg0): void; + withName(arg0): org.eclipse.che.api.machine.shared.dto.CommandDto; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.machine.shared.dto.CommandDto; + withCommandLine(arg0): org.eclipse.che.api.machine.shared.dto.CommandDto; + setCommandLine(arg0): void; + getName(): string; + setName(arg0): void; + getType(): string; + getAttributes(): Map; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class CommandDtoImpl implements org.eclipse.che.api.machine.shared.dto.CommandDto { + + name : string; + attributes : Map; + commandLine : string; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + if (__jsonObject) { + if (__jsonObject.commandLine) { + this.commandLine = __jsonObject.commandLine; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + getCommandLine() : string { + return this.commandLine; + } + withType(type : string) : org.eclipse.che.api.machine.shared.dto.CommandDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withName(name : string) : org.eclipse.che.api.machine.shared.dto.CommandDto { + this.name = name; + return this; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.machine.shared.dto.CommandDto { + this.attributes = attributes; + return this; + } + withCommandLine(commandLine : string) : org.eclipse.che.api.machine.shared.dto.CommandDto { + this.commandLine = commandLine; + return this; + } + setCommandLine(commandLine : string) : void { + this.commandLine = commandLine; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getType() : string { + return this.type; + } + getAttributes() : Map { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.commandLine) { + json.commandLine = this.commandLine; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto.event { + + export interface MachineStatusEvent { + getEventType(): string; + getError(): string; + setEventType(arg0): void; + withError(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; + withEventType(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; + getWorkspaceId(): string; + withWorkspaceId(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; + isDev(): boolean; + withDev(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; + setDev(arg0): void; + getMachineId(): string; + setMachineId(arg0): void; + withMachineId(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; + getMachineName(): string; + withMachineName(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; + setError(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto.event { + + export class MachineStatusEventImpl implements org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent { + + machineId : string; + dev : boolean; + eventType : string; + error : string; + machineName : string; + workspaceId : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.machineId) { + this.machineId = __jsonObject.machineId; + } + } + if (__jsonObject) { + if (__jsonObject.dev) { + this.dev = __jsonObject.dev; + } + } + if (__jsonObject) { + if (__jsonObject.eventType) { + this.eventType = __jsonObject.eventType; + } + } + if (__jsonObject) { + if (__jsonObject.error) { + this.error = __jsonObject.error; + } + } + if (__jsonObject) { + if (__jsonObject.machineName) { + this.machineName = __jsonObject.machineName; + } + } + if (__jsonObject) { + if (__jsonObject.workspaceId) { + this.workspaceId = __jsonObject.workspaceId; + } + } + + } + + getEventType() : string { + return this.eventType; + } + getError() : string { + return this.error; + } + setEventType(eventType : string) : void { + this.eventType = eventType; + } + withError(error : string) : org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent { + this.error = error; + return this; + } + withEventType(eventType : string) : org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent { + this.eventType = eventType; + return this; + } + getWorkspaceId() : string { + return this.workspaceId; + } + withWorkspaceId(workspaceId : string) : org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent { + this.workspaceId = workspaceId; + return this; + } + isDev() : boolean { + return this.dev; + } + withDev(dev : boolean) : org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent { + this.dev = dev; + return this; + } + setDev(dev : boolean) : void { + this.dev = dev; + } + getMachineId() : string { + return this.machineId; + } + setMachineId(machineId : string) : void { + this.machineId = machineId; + } + withMachineId(machineId : string) : org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent { + this.machineId = machineId; + return this; + } + getMachineName() : string { + return this.machineName; + } + withMachineName(machineName : string) : org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent { + this.machineName = machineName; + return this; + } + setError(error : string) : void { + this.error = error; + } + + toJson() : any { + let json : any = {}; + + if (this.machineId) { + json.machineId = this.machineId; + } + if (this.dev) { + json.dev = this.dev; + } + if (this.eventType) { + json.eventType = this.eventType; + } + if (this.error) { + json.error = this.error; + } + if (this.machineName) { + json.machineName = this.machineName; + } + if (this.workspaceId) { + json.workspaceId = this.workspaceId; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface RequestBodyDescriptor { + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class RequestBodyDescriptorImpl implements org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor { + + description : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + + } + + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor { + this.description = description; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.description) { + json.description = this.description; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface Remote { + getUrl(): string; + withName(arg0): org.eclipse.che.api.git.shared.Remote; + withUrl(arg0): org.eclipse.che.api.git.shared.Remote; + getName(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RemoteImpl implements org.eclipse.che.api.git.shared.Remote { + + name : string; + url : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.url) { + this.url = __jsonObject.url; + } + } + + } + + getUrl() : string { + return this.url; + } + withName(name : string) : org.eclipse.che.api.git.shared.Remote { + this.name = name; + return this; + } + withUrl(url : string) : org.eclipse.che.api.git.shared.Remote { + this.url = url; + return this; + } + getName() : string { + return this.name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.url) { + json.url = this.url; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface ServiceError { + setMessage(arg0): void; + withMessage(arg0): org.eclipse.che.api.core.rest.shared.dto.ServiceError; + getMessage(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class ServiceErrorImpl implements org.eclipse.che.api.core.rest.shared.dto.ServiceError { + + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + setMessage(message : string) : void { + this.message = message; + } + withMessage(message : string) : org.eclipse.che.api.core.rest.shared.dto.ServiceError { + this.message = message; + return this; + } + getMessage() : string { + return this.message; + } + + toJson() : any { + let json : any = {}; + + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface PushRequest { + setTimeout(arg0): void; + getTimeout(): number; + setPassword(arg0): void; + getUsername(): string; + getPassword(): string; + setUsername(arg0): void; + setRemote(arg0): void; + withRemote(arg0): org.eclipse.che.api.git.shared.PushRequest; + withPassword(arg0): org.eclipse.che.api.git.shared.PushRequest; + getRefSpec(): Array; + setRefSpec(arg0): void; + withRefSpec(arg0): org.eclipse.che.api.git.shared.PushRequest; + getRemote(): string; + isForce(): boolean; + setForce(arg0): void; + withForce(arg0): org.eclipse.che.api.git.shared.PushRequest; + withTimeout(arg0): org.eclipse.che.api.git.shared.PushRequest; + withUsername(arg0): org.eclipse.che.api.git.shared.PushRequest; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class PushRequestImpl implements org.eclipse.che.api.git.shared.PushRequest { + + password : string; + refSpec : Array; + force : boolean; + remote : string; + timeout : number; + username : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.password) { + this.password = __jsonObject.password; + } + } + this.refSpec = new Array(); + if (__jsonObject) { + if (__jsonObject.refSpec) { + __jsonObject.refSpec.forEach((item) => { + this.refSpec.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.force) { + this.force = __jsonObject.force; + } + } + if (__jsonObject) { + if (__jsonObject.remote) { + this.remote = __jsonObject.remote; + } + } + if (__jsonObject) { + if (__jsonObject.timeout) { + this.timeout = __jsonObject.timeout; + } + } + if (__jsonObject) { + if (__jsonObject.username) { + this.username = __jsonObject.username; + } + } + + } + + setTimeout(timeout : number) : void { + this.timeout = timeout; + } + getTimeout() : number { + return this.timeout; + } + setPassword(password : string) : void { + this.password = password; + } + getUsername() : string { + return this.username; + } + getPassword() : string { + return this.password; + } + setUsername(username : string) : void { + this.username = username; + } + setRemote(remote : string) : void { + this.remote = remote; + } + withRemote(remote : string) : org.eclipse.che.api.git.shared.PushRequest { + this.remote = remote; + return this; + } + withPassword(password : string) : org.eclipse.che.api.git.shared.PushRequest { + this.password = password; + return this; + } + getRefSpec() : Array { + return this.refSpec; + } + setRefSpec(refSpec : Array) : void { + this.refSpec = refSpec; + } + withRefSpec(refSpec : Array) : org.eclipse.che.api.git.shared.PushRequest { + this.refSpec = refSpec; + return this; + } + getRemote() : string { + return this.remote; + } + isForce() : boolean { + return this.force; + } + setForce(force : boolean) : void { + this.force = force; + } + withForce(force : boolean) : org.eclipse.che.api.git.shared.PushRequest { + this.force = force; + return this; + } + withTimeout(timeout : number) : org.eclipse.che.api.git.shared.PushRequest { + this.timeout = timeout; + return this; + } + withUsername(username : string) : org.eclipse.che.api.git.shared.PushRequest { + this.username = username; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.password) { + json.password = this.password; + } + if (this.refSpec) { + let listArray = []; + this.refSpec.forEach((item) => { + listArray.push(item); + json.refSpec = listArray; + }); + } + if (this.force) { + json.force = this.force; + } + if (this.remote) { + json.remote = this.remote; + } + if (this.timeout) { + json.timeout = this.timeout; + } + if (this.username) { + json.username = this.username; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface GitUrlVendorInfo { + getVendorBaseHost(): string; + getOAuthScopes(): Array; + setVendorName(arg0): void; + withVendorName(arg0): org.eclipse.che.api.git.shared.GitUrlVendorInfo; + setVendorBaseHost(arg0): void; + withVendorBaseHost(arg0): org.eclipse.che.api.git.shared.GitUrlVendorInfo; + setOAuthScopes(arg0): void; + withOAuthScopes(arg0): org.eclipse.che.api.git.shared.GitUrlVendorInfo; + setGivenUrlSSH(arg0): void; + withGivenUrlSSH(arg0): org.eclipse.che.api.git.shared.GitUrlVendorInfo; + isGivenUrlSSH(): boolean; + getVendorName(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class GitUrlVendorInfoImpl implements org.eclipse.che.api.git.shared.GitUrlVendorInfo { + + vendorBaseHost : string; + givenUrlSSH : boolean; + oAuthScopes : Array; + vendorName : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.vendorBaseHost) { + this.vendorBaseHost = __jsonObject.vendorBaseHost; + } + } + if (__jsonObject) { + if (__jsonObject.givenUrlSSH) { + this.givenUrlSSH = __jsonObject.givenUrlSSH; + } + } + this.oAuthScopes = new Array(); + if (__jsonObject) { + if (__jsonObject.oAuthScopes) { + __jsonObject.oAuthScopes.forEach((item) => { + this.oAuthScopes.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.vendorName) { + this.vendorName = __jsonObject.vendorName; + } + } + + } + + getVendorBaseHost() : string { + return this.vendorBaseHost; + } + getOAuthScopes() : Array { + return this.oAuthScopes; + } + setVendorName(vendorName : string) : void { + this.vendorName = vendorName; + } + withVendorName(vendorName : string) : org.eclipse.che.api.git.shared.GitUrlVendorInfo { + this.vendorName = vendorName; + return this; + } + setVendorBaseHost(vendorBaseHost : string) : void { + this.vendorBaseHost = vendorBaseHost; + } + withVendorBaseHost(vendorBaseHost : string) : org.eclipse.che.api.git.shared.GitUrlVendorInfo { + this.vendorBaseHost = vendorBaseHost; + return this; + } + setOAuthScopes(oAuthScopes : Array) : void { + this.oAuthScopes = oAuthScopes; + } + withOAuthScopes(oAuthScopes : Array) : org.eclipse.che.api.git.shared.GitUrlVendorInfo { + this.oAuthScopes = oAuthScopes; + return this; + } + setGivenUrlSSH(givenUrlSSH : boolean) : void { + this.givenUrlSSH = givenUrlSSH; + } + withGivenUrlSSH(givenUrlSSH : boolean) : org.eclipse.che.api.git.shared.GitUrlVendorInfo { + this.givenUrlSSH = givenUrlSSH; + return this; + } + isGivenUrlSSH() : boolean { + return this.givenUrlSSH; + } + getVendorName() : string { + return this.vendorName; + } + + toJson() : any { + let json : any = {}; + + if (this.vendorBaseHost) { + json.vendorBaseHost = this.vendorBaseHost; + } + if (this.givenUrlSSH) { + json.givenUrlSSH = this.givenUrlSSH; + } + if (this.oAuthScopes) { + let listArray = []; + this.oAuthScopes.forEach((item) => { + listArray.push(item); + json.oAuthScopes = listArray; + }); + } + if (this.vendorName) { + json.vendorName = this.vendorName; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface RemoteUpdateRequest { + getBranches(): Array; + setBranches(arg0): void; + isAddBranches(): boolean; + setRemoveUrl(arg0): void; + getAddPushUrl(): Array; + setAddBranches(arg0): void; + getAddUrl(): Array; + setAddUrl(arg0): void; + getRemoveUrl(): Array; + setAddPushUrl(arg0): void; + getRemovePushUrl(): Array; + setRemovePushUrl(arg0): void; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RemoteUpdateRequestImpl implements org.eclipse.che.api.git.shared.RemoteUpdateRequest { + + removeUrl : Array; + removePushUrl : Array; + addPushUrl : Array; + addBranches : boolean; + addUrl : Array; + name : string; + branches : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.removeUrl = new Array(); + if (__jsonObject) { + if (__jsonObject.removeUrl) { + __jsonObject.removeUrl.forEach((item) => { + this.removeUrl.push(item); + }); + } + } + this.removePushUrl = new Array(); + if (__jsonObject) { + if (__jsonObject.removePushUrl) { + __jsonObject.removePushUrl.forEach((item) => { + this.removePushUrl.push(item); + }); + } + } + this.addPushUrl = new Array(); + if (__jsonObject) { + if (__jsonObject.addPushUrl) { + __jsonObject.addPushUrl.forEach((item) => { + this.addPushUrl.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.addBranches) { + this.addBranches = __jsonObject.addBranches; + } + } + this.addUrl = new Array(); + if (__jsonObject) { + if (__jsonObject.addUrl) { + __jsonObject.addUrl.forEach((item) => { + this.addUrl.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + this.branches = new Array(); + if (__jsonObject) { + if (__jsonObject.branches) { + __jsonObject.branches.forEach((item) => { + this.branches.push(item); + }); + } + } + + } + + getBranches() : Array { + return this.branches; + } + setBranches(branches : Array) : void { + this.branches = branches; + } + isAddBranches() : boolean { + return this.addBranches; + } + setRemoveUrl(removeUrl : Array) : void { + this.removeUrl = removeUrl; + } + getAddPushUrl() : Array { + return this.addPushUrl; + } + setAddBranches(addBranches : boolean) : void { + this.addBranches = addBranches; + } + getAddUrl() : Array { + return this.addUrl; + } + setAddUrl(addUrl : Array) : void { + this.addUrl = addUrl; + } + getRemoveUrl() : Array { + return this.removeUrl; + } + setAddPushUrl(addPushUrl : Array) : void { + this.addPushUrl = addPushUrl; + } + getRemovePushUrl() : Array { + return this.removePushUrl; + } + setRemovePushUrl(removePushUrl : Array) : void { + this.removePushUrl = removePushUrl; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.removeUrl) { + let listArray = []; + this.removeUrl.forEach((item) => { + listArray.push(item); + json.removeUrl = listArray; + }); + } + if (this.removePushUrl) { + let listArray = []; + this.removePushUrl.forEach((item) => { + listArray.push(item); + json.removePushUrl = listArray; + }); + } + if (this.addPushUrl) { + let listArray = []; + this.addPushUrl.forEach((item) => { + listArray.push(item); + json.addPushUrl = listArray; + }); + } + if (this.addBranches) { + json.addBranches = this.addBranches; + } + if (this.addUrl) { + let listArray = []; + this.addUrl.forEach((item) => { + listArray.push(item); + json.addUrl = listArray; + }); + } + if (this.name) { + json.name = this.name; + } + if (this.branches) { + let listArray = []; + this.branches.forEach((item) => { + listArray.push(item); + json.branches = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export interface StartActionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.action.StartActionDto; + setType(arg0): void; + setBreakpoints(arg0): void; + withBreakpoints(arg0): org.eclipse.che.api.debug.shared.dto.action.StartActionDto; + getBreakpoints(): Array; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export class StartActionDtoImpl implements org.eclipse.che.api.debug.shared.dto.action.StartActionDto { + + breakpoints : Array; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.breakpoints = new Array(); + if (__jsonObject) { + if (__jsonObject.breakpoints) { + __jsonObject.breakpoints.forEach((item) => { + this.breakpoints.push(new org.eclipse.che.api.debug.shared.dto.BreakpointDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.action.StartActionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setBreakpoints(breakpoints : Array) : void { + this.breakpoints = breakpoints; + } + withBreakpoints(breakpoints : Array) : org.eclipse.che.api.debug.shared.dto.action.StartActionDto { + this.breakpoints = breakpoints; + return this; + } + getBreakpoints() : Array { + return this.breakpoints; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.breakpoints) { + let listArray = []; + this.breakpoints.forEach((item) => { + listArray.push((item as org.eclipse.che.api.debug.shared.dto.BreakpointDtoImpl).toJson()); + json.breakpoints = listArray; + }); + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface ShowFileContentResponse { + setContent(arg0): void; + withContent(arg0): org.eclipse.che.api.git.shared.ShowFileContentResponse; + getContent(): string; + getCommits(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class ShowFileContentResponseImpl implements org.eclipse.che.api.git.shared.ShowFileContentResponse { + + commits : Array; + content : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.commits = new Array(); + if (__jsonObject) { + if (__jsonObject.commits) { + __jsonObject.commits.forEach((item) => { + this.commits.push(new org.eclipse.che.api.git.shared.RevisionImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.content) { + this.content = __jsonObject.content; + } + } + + } + + setContent(content : string) : void { + this.content = content; + } + withContent(content : string) : org.eclipse.che.api.git.shared.ShowFileContentResponse { + this.content = content; + return this; + } + getContent() : string { + return this.content; + } + getCommits() : Array { + return this.commits; + } + + toJson() : any { + let json : any = {}; + + if (this.commits) { + let listArray = []; + this.commits.forEach((item) => { + listArray.push((item as org.eclipse.che.api.git.shared.RevisionImpl).toJson()); + json.commits = listArray; + }); + } + if (this.content) { + json.content = this.content; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface ProjectTypeDto { + getParents(): Array; + withAttributes(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + withId(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + withParents(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + isPrimaryable(): boolean; + withPrimaryable(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + withDisplayName(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + isMixable(): boolean; + withMixable(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + isPersisted(): boolean; + withPersisted(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + getAncestors(): Array; + withAncestors(arg0): org.eclipse.che.api.project.shared.dto.ProjectTypeDto; + getId(): string; + getAttributes(): Array; + getDisplayName(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class ProjectTypeDtoImpl implements org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + + primaryable : boolean; + displayName : string; + attributes : Array; + mixable : boolean; + id : string; + persisted : boolean; + ancestors : Array; + parents : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.primaryable) { + this.primaryable = __jsonObject.primaryable; + } + } + if (__jsonObject) { + if (__jsonObject.displayName) { + this.displayName = __jsonObject.displayName; + } + } + this.attributes = new Array(); + if (__jsonObject) { + if (__jsonObject.attributes) { + __jsonObject.attributes.forEach((item) => { + this.attributes.push(new org.eclipse.che.api.project.shared.dto.AttributeDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.mixable) { + this.mixable = __jsonObject.mixable; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.persisted) { + this.persisted = __jsonObject.persisted; + } + } + this.ancestors = new Array(); + if (__jsonObject) { + if (__jsonObject.ancestors) { + __jsonObject.ancestors.forEach((item) => { + this.ancestors.push(item); + }); + } + } + this.parents = new Array(); + if (__jsonObject) { + if (__jsonObject.parents) { + __jsonObject.parents.forEach((item) => { + this.parents.push(item); + }); + } + } + + } + + getParents() : Array { + return this.parents; + } + withAttributes(attributes : Array) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.attributes = attributes; + return this; + } + withId(id : string) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.id = id; + return this; + } + withParents(parents : Array) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.parents = parents; + return this; + } + isPrimaryable() : boolean { + return this.primaryable; + } + withPrimaryable(primaryable : boolean) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.primaryable = primaryable; + return this; + } + withDisplayName(displayName : string) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.displayName = displayName; + return this; + } + isMixable() : boolean { + return this.mixable; + } + withMixable(mixable : boolean) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.mixable = mixable; + return this; + } + isPersisted() : boolean { + return this.persisted; + } + withPersisted(persisted : boolean) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.persisted = persisted; + return this; + } + getAncestors() : Array { + return this.ancestors; + } + withAncestors(ancestors : Array) : org.eclipse.che.api.project.shared.dto.ProjectTypeDto { + this.ancestors = ancestors; + return this; + } + getId() : string { + return this.id; + } + getAttributes() : Array { + return this.attributes; + } + getDisplayName() : string { + return this.displayName; + } + + toJson() : any { + let json : any = {}; + + if (this.primaryable) { + json.primaryable = this.primaryable; + } + if (this.displayName) { + json.displayName = this.displayName; + } + if (this.attributes) { + let listArray = []; + this.attributes.forEach((item) => { + listArray.push((item as org.eclipse.che.api.project.shared.dto.AttributeDtoImpl).toJson()); + json.attributes = listArray; + }); + } + if (this.mixable) { + json.mixable = this.mixable; + } + if (this.id) { + json.id = this.id; + } + if (this.persisted) { + json.persisted = this.persisted; + } + if (this.ancestors) { + let listArray = []; + this.ancestors.forEach((item) => { + listArray.push(item); + json.ancestors = listArray; + }); + } + if (this.parents) { + let listArray = []; + this.parents.forEach((item) => { + listArray.push(item); + json.parents = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface PoliciesDto { + getSince(): number; + setSince(arg0): void; + getReferer(): string; + setMatch(arg0): void; + withMatch(arg0): org.eclipse.che.api.factory.shared.dto.PoliciesDto; + setReferer(arg0): void; + withReferer(arg0): org.eclipse.che.api.factory.shared.dto.PoliciesDto; + withSince(arg0): org.eclipse.che.api.factory.shared.dto.PoliciesDto; + getUntil(): number; + setUntil(arg0): void; + withUntil(arg0): org.eclipse.che.api.factory.shared.dto.PoliciesDto; + getMatch(): string; + withCreate(arg0): org.eclipse.che.api.factory.shared.dto.PoliciesDto; + getCreate(): string; + setCreate(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class PoliciesDtoImpl implements org.eclipse.che.api.factory.shared.dto.PoliciesDto { + + referer : string; + match : string; + create : string; + until : number; + since : number; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.referer) { + this.referer = __jsonObject.referer; + } + } + if (__jsonObject) { + if (__jsonObject.match) { + this.match = __jsonObject.match; + } + } + if (__jsonObject) { + if (__jsonObject.create) { + this.create = __jsonObject.create; + } + } + if (__jsonObject) { + if (__jsonObject.until) { + this.until = __jsonObject.until; + } + } + if (__jsonObject) { + if (__jsonObject.since) { + this.since = __jsonObject.since; + } + } + + } + + getSince() : number { + return this.since; + } + setSince(since : number) : void { + this.since = since; + } + getReferer() : string { + return this.referer; + } + setMatch(match : string) : void { + this.match = match; + } + withMatch(match : string) : org.eclipse.che.api.factory.shared.dto.PoliciesDto { + this.match = match; + return this; + } + setReferer(referer : string) : void { + this.referer = referer; + } + withReferer(referer : string) : org.eclipse.che.api.factory.shared.dto.PoliciesDto { + this.referer = referer; + return this; + } + withSince(since : number) : org.eclipse.che.api.factory.shared.dto.PoliciesDto { + this.since = since; + return this; + } + getUntil() : number { + return this.until; + } + setUntil(until : number) : void { + this.until = until; + } + withUntil(until : number) : org.eclipse.che.api.factory.shared.dto.PoliciesDto { + this.until = until; + return this; + } + getMatch() : string { + return this.match; + } + withCreate(create : string) : org.eclipse.che.api.factory.shared.dto.PoliciesDto { + this.create = create; + return this; + } + getCreate() : string { + return this.create; + } + setCreate(create : string) : void { + this.create = create; + } + + toJson() : any { + let json : any = {}; + + if (this.referer) { + json.referer = this.referer; + } + if (this.match) { + json.match = this.match; + } + if (this.create) { + json.create = this.create; + } + if (this.until) { + json.until = this.until; + } + if (this.since) { + json.since = this.since; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export interface GitCheckoutEventDto { + withType(arg0): org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto; + withName(arg0): org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto; + getName(): string; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export class GitCheckoutEventDtoImpl implements org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto { + + name : string; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto { + this.type = type; + return this; + } + withName(name : string) : org.eclipse.che.api.project.shared.dto.event.GitCheckoutEventDto { + this.name = name; + return this; + } + getName() : string { + return this.name; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.stack { + + export interface StackDto { + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + getSource(): org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto; + withSource(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + getComponents(): Array; + setId(arg0): void; + setSource(arg0): void; + setScope(arg0): void; + setComponents(arg0): void; + setTags(arg0): void; + withName(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + withLinks(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + withId(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + setCreator(arg0): void; + withCreator(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + withTags(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + withComponents(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + getWorkspaceConfig(): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + setWorkspaceConfig(arg0): void; + withWorkspaceConfig(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + withScope(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackDto; + setName(arg0): void; + getDescription(): string; + getScope(): string; + getTags(): Array; + getCreator(): string; + getName(): string; + getId(): string; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.stack { + + export class StackDtoImpl implements org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + + components : Array; + creator : string; + scope : string; + name : string; + description : string; + links : Array; + source : org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto; + id : string; + workspaceConfig : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + tags : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.components = new Array(); + if (__jsonObject) { + if (__jsonObject.components) { + __jsonObject.components.forEach((item) => { + this.components.push(new org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.creator) { + this.creator = __jsonObject.creator; + } + } + if (__jsonObject) { + if (__jsonObject.scope) { + this.scope = __jsonObject.scope; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.source) { + this.source = new org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDtoImpl(__jsonObject.source); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.workspaceConfig) { + this.workspaceConfig = new org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDtoImpl(__jsonObject.workspaceConfig); + } + } + this.tags = new Array(); + if (__jsonObject) { + if (__jsonObject.tags) { + __jsonObject.tags.forEach((item) => { + this.tags.push(item); + }); + } + } + + } + + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.description = description; + return this; + } + getSource() : org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto { + return this.source; + } + withSource(source : org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.source = source; + return this; + } + getComponents() : Array { + return this.components; + } + setId(id : string) : void { + this.id = id; + } + setSource(source : org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto) : void { + this.source = source; + } + setScope(scope : string) : void { + this.scope = scope; + } + setComponents(components : Array) : void { + this.components = components; + } + setTags(tags : Array) : void { + this.tags = tags; + } + withName(name : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.name = name; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.links = links; + return this; + } + withId(id : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.id = id; + return this; + } + setCreator(creator : string) : void { + this.creator = creator; + } + withCreator(creator : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.creator = creator; + return this; + } + withTags(tags : Array) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.tags = tags; + return this; + } + withComponents(components : Array) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.components = components; + return this; + } + getWorkspaceConfig() : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + return this.workspaceConfig; + } + setWorkspaceConfig(workspaceConfig : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto) : void { + this.workspaceConfig = workspaceConfig; + } + withWorkspaceConfig(workspaceConfig : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.workspaceConfig = workspaceConfig; + return this; + } + withScope(scope : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackDto { + this.scope = scope; + return this; + } + setName(name : string) : void { + this.name = name; + } + getDescription() : string { + return this.description; + } + getScope() : string { + return this.scope; + } + getTags() : Array { + return this.tags; + } + getCreator() : string { + return this.creator; + } + getName() : string { + return this.name; + } + getId() : string { + return this.id; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.components) { + let listArray = []; + this.components.forEach((item) => { + listArray.push((item as org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDtoImpl).toJson()); + json.components = listArray; + }); + } + if (this.creator) { + json.creator = this.creator; + } + if (this.scope) { + json.scope = this.scope; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.source) { + json.source = (this.source as org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDtoImpl).toJson(); + } + if (this.id) { + json.id = this.id; + } + if (this.workspaceConfig) { + json.workspaceConfig = (this.workspaceConfig as org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDtoImpl).toJson(); + } + if (this.tags) { + let listArray = []; + this.tags.forEach((item) => { + listArray.push(item); + json.tags = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface Status { + setFormat(arg0): void; + getFormat(): string; + getMissing(): Array; + setMissing(arg0): void; + getBranchName(): string; + getRemoved(): Array; + setRemoved(arg0): void; + getConflicting(): Array; + setClean(arg0): void; + setUntracked(arg0): void; + setBranchName(arg0): void; + getAdded(): Array; + setAdded(arg0): void; + getUntracked(): Array; + getUntrackedFolders(): Array; + setUntrackedFolders(arg0): void; + setConflicting(arg0): void; + getRepositoryState(): string; + setRepositoryState(arg0): void; + getChanged(): Array; + setChanged(arg0): void; + isClean(): boolean; + getModified(): Array; + setModified(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class StatusImpl implements org.eclipse.che.api.git.shared.Status { + + conflicting : Array; + removed : Array; + added : Array; + untrackedFolders : Array; + format : string; + missing : Array; + branchName : string; + untracked : Array; + modified : Array; + clean : boolean; + repositoryState : string; + changed : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.conflicting = new Array(); + if (__jsonObject) { + if (__jsonObject.conflicting) { + __jsonObject.conflicting.forEach((item) => { + this.conflicting.push(item); + }); + } + } + this.removed = new Array(); + if (__jsonObject) { + if (__jsonObject.removed) { + __jsonObject.removed.forEach((item) => { + this.removed.push(item); + }); + } + } + this.added = new Array(); + if (__jsonObject) { + if (__jsonObject.added) { + __jsonObject.added.forEach((item) => { + this.added.push(item); + }); + } + } + this.untrackedFolders = new Array(); + if (__jsonObject) { + if (__jsonObject.untrackedFolders) { + __jsonObject.untrackedFolders.forEach((item) => { + this.untrackedFolders.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.format) { + this.format = __jsonObject.format; + } + } + this.missing = new Array(); + if (__jsonObject) { + if (__jsonObject.missing) { + __jsonObject.missing.forEach((item) => { + this.missing.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.branchName) { + this.branchName = __jsonObject.branchName; + } + } + this.untracked = new Array(); + if (__jsonObject) { + if (__jsonObject.untracked) { + __jsonObject.untracked.forEach((item) => { + this.untracked.push(item); + }); + } + } + this.modified = new Array(); + if (__jsonObject) { + if (__jsonObject.modified) { + __jsonObject.modified.forEach((item) => { + this.modified.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.clean) { + this.clean = __jsonObject.clean; + } + } + if (__jsonObject) { + if (__jsonObject.repositoryState) { + this.repositoryState = __jsonObject.repositoryState; + } + } + this.changed = new Array(); + if (__jsonObject) { + if (__jsonObject.changed) { + __jsonObject.changed.forEach((item) => { + this.changed.push(item); + }); + } + } + + } + + setFormat(format : string) : void { + this.format = format; + } + getFormat() : string { + return this.format; + } + getMissing() : Array { + return this.missing; + } + setMissing(missing : Array) : void { + this.missing = missing; + } + getBranchName() : string { + return this.branchName; + } + getRemoved() : Array { + return this.removed; + } + setRemoved(removed : Array) : void { + this.removed = removed; + } + getConflicting() : Array { + return this.conflicting; + } + setClean(clean : boolean) : void { + this.clean = clean; + } + setUntracked(untracked : Array) : void { + this.untracked = untracked; + } + setBranchName(branchName : string) : void { + this.branchName = branchName; + } + getAdded() : Array { + return this.added; + } + setAdded(added : Array) : void { + this.added = added; + } + getUntracked() : Array { + return this.untracked; + } + getUntrackedFolders() : Array { + return this.untrackedFolders; + } + setUntrackedFolders(untrackedFolders : Array) : void { + this.untrackedFolders = untrackedFolders; + } + setConflicting(conflicting : Array) : void { + this.conflicting = conflicting; + } + getRepositoryState() : string { + return this.repositoryState; + } + setRepositoryState(repositoryState : string) : void { + this.repositoryState = repositoryState; + } + getChanged() : Array { + return this.changed; + } + setChanged(changed : Array) : void { + this.changed = changed; + } + isClean() : boolean { + return this.clean; + } + getModified() : Array { + return this.modified; + } + setModified(modified : Array) : void { + this.modified = modified; + } + + toJson() : any { + let json : any = {}; + + if (this.conflicting) { + let listArray = []; + this.conflicting.forEach((item) => { + listArray.push(item); + json.conflicting = listArray; + }); + } + if (this.removed) { + let listArray = []; + this.removed.forEach((item) => { + listArray.push(item); + json.removed = listArray; + }); + } + if (this.added) { + let listArray = []; + this.added.forEach((item) => { + listArray.push(item); + json.added = listArray; + }); + } + if (this.untrackedFolders) { + let listArray = []; + this.untrackedFolders.forEach((item) => { + listArray.push(item); + json.untrackedFolders = listArray; + }); + } + if (this.format) { + json.format = this.format; + } + if (this.missing) { + let listArray = []; + this.missing.forEach((item) => { + listArray.push(item); + json.missing = listArray; + }); + } + if (this.branchName) { + json.branchName = this.branchName; + } + if (this.untracked) { + let listArray = []; + this.untracked.forEach((item) => { + listArray.push(item); + json.untracked = listArray; + }); + } + if (this.modified) { + let listArray = []; + this.modified.forEach((item) => { + listArray.push(item); + json.modified = listArray; + }); + } + if (this.clean) { + json.clean = this.clean; + } + if (this.repositoryState) { + json.repositoryState = this.repositoryState; + } + if (this.changed) { + let listArray = []; + this.changed.forEach((item) => { + listArray.push(item); + json.changed = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface MoveOptions { + setOverWrite(arg0): void; + getOverWrite(): boolean; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class MoveOptionsImpl implements org.eclipse.che.api.project.shared.dto.MoveOptions { + + name : string; + overWrite : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.overWrite) { + this.overWrite = __jsonObject.overWrite; + } + } + + } + + setOverWrite(overWrite : boolean) : void { + this.overWrite = overWrite; + } + getOverWrite() : boolean { + return this.overWrite; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.overWrite) { + json.overWrite = this.overWrite; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export interface StepOutActionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.action.StepOutActionDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export class StepOutActionDtoImpl implements org.eclipse.che.api.debug.shared.dto.action.StepOutActionDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.action.StepOutActionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface MachineProcessDto { + withType(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + setType(arg0): void; + setPid(arg0): void; + withName(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + withLinks(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + withCommandLine(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + withPid(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + setAlive(arg0): void; + withAlive(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + withOutputChannel(arg0): org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + setOutputChannel(arg0): void; + setCommandLine(arg0): void; + setName(arg0): void; + getPid(): number; + getOutputChannel(): string; + isAlive(): boolean; + getCommandLine(): string; + getName(): string; + getType(): string; + getAttributes(): Map; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class MachineProcessDtoImpl implements org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + + alive : boolean; + outputChannel : string; + name : string; + pid : number; + attributes : Map; + links : Array; + type : string; + commandLine : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.alive) { + this.alive = __jsonObject.alive; + } + } + if (__jsonObject) { + if (__jsonObject.outputChannel) { + this.outputChannel = __jsonObject.outputChannel; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.pid) { + this.pid = __jsonObject.pid; + } + } + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.commandLine) { + this.commandLine = __jsonObject.commandLine; + } + } + + } + + withType(type : string) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setPid(pid : number) : void { + this.pid = pid; + } + withName(name : string) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.name = name; + return this; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.attributes = attributes; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.links = links; + return this; + } + withCommandLine(commandLine : string) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.commandLine = commandLine; + return this; + } + withPid(pid : number) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.pid = pid; + return this; + } + setAlive(alive : boolean) : void { + this.alive = alive; + } + withAlive(alive : boolean) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.alive = alive; + return this; + } + withOutputChannel(outputChannel : string) : org.eclipse.che.api.machine.shared.dto.MachineProcessDto { + this.outputChannel = outputChannel; + return this; + } + setOutputChannel(outputChannel : string) : void { + this.outputChannel = outputChannel; + } + setCommandLine(commandLine : string) : void { + this.commandLine = commandLine; + } + setName(name : string) : void { + this.name = name; + } + getPid() : number { + return this.pid; + } + getOutputChannel() : string { + return this.outputChannel; + } + isAlive() : boolean { + return this.alive; + } + getCommandLine() : string { + return this.commandLine; + } + getName() : string { + return this.name; + } + getType() : string { + return this.type; + } + getAttributes() : Map { + return this.attributes; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.alive) { + json.alive = this.alive; + } + if (this.outputChannel) { + json.outputChannel = this.outputChannel; + } + if (this.name) { + json.name = this.name; + } + if (this.pid) { + json.pid = this.pid; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.type) { + json.type = this.type; + } + if (this.commandLine) { + json.commandLine = this.commandLine; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface GitUser { + getEmail(): string; + setEmail(arg0): void; + withName(arg0): org.eclipse.che.api.git.shared.GitUser; + withEmail(arg0): org.eclipse.che.api.git.shared.GitUser; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class GitUserImpl implements org.eclipse.che.api.git.shared.GitUser { + + name : string; + email : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.email) { + this.email = __jsonObject.email; + } + } + + } + + getEmail() : string { + return this.email; + } + setEmail(email : string) : void { + this.email = email; + } + withName(name : string) : org.eclipse.che.api.git.shared.GitUser { + this.name = name; + return this; + } + withEmail(email : string) : org.eclipse.che.api.git.shared.GitUser { + this.email = email; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.email) { + json.email = this.email; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export interface StepOverActionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.action.StepOverActionDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export class StepOverActionDtoImpl implements org.eclipse.che.api.debug.shared.dto.action.StepOverActionDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.action.StepOverActionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface ProjectImporterData { + getConfiguration(): Map; + setConfiguration(arg0): void; + setImporters(arg0): void; + withConfiguration(arg0): org.eclipse.che.api.project.shared.dto.ProjectImporterData; + withImporters(arg0): org.eclipse.che.api.project.shared.dto.ProjectImporterData; + getImporters(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class ProjectImporterDataImpl implements org.eclipse.che.api.project.shared.dto.ProjectImporterData { + + importers : Array; + configuration : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.importers = new Array(); + if (__jsonObject) { + if (__jsonObject.importers) { + __jsonObject.importers.forEach((item) => { + this.importers.push(new org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptorImpl(item)); + }); + } + } + this.configuration = new Map(); + if (__jsonObject) { + if (__jsonObject.configuration) { + let tmp : Array = Object.keys(__jsonObject.configuration); + tmp.forEach((key) => { + this.configuration.set(key, __jsonObject.configuration[key]); + }); + } + } + + } + + getConfiguration() : Map { + return this.configuration; + } + setConfiguration(configuration : Map) : void { + this.configuration = configuration; + } + setImporters(importers : Array) : void { + this.importers = importers; + } + withConfiguration(configuration : Map) : org.eclipse.che.api.project.shared.dto.ProjectImporterData { + this.configuration = configuration; + return this; + } + withImporters(importers : Array) : org.eclipse.che.api.project.shared.dto.ProjectImporterData { + this.importers = importers; + return this; + } + getImporters() : Array { + return this.importers; + } + + toJson() : any { + let json : any = {}; + + if (this.importers) { + let listArray = []; + this.importers.forEach((item) => { + listArray.push((item as org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptorImpl).toJson()); + json.importers = listArray; + }); + } + if (this.configuration) { + let tmpMap : any = {}; + for (const [key, value] of this.configuration.entries()) { + tmpMap[key] = value; + } + json.configuration = tmpMap; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface AddRequest { + getFilePattern(): Array; + setFilePattern(arg0): void; + withFilePattern(arg0): org.eclipse.che.api.git.shared.AddRequest; + isUpdate(): boolean; + setUpdate(arg0): void; + withUpdate(arg0): org.eclipse.che.api.git.shared.AddRequest; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class AddRequestImpl implements org.eclipse.che.api.git.shared.AddRequest { + + filePattern : Array; + update : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.filePattern = new Array(); + if (__jsonObject) { + if (__jsonObject.filePattern) { + __jsonObject.filePattern.forEach((item) => { + this.filePattern.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.update) { + this.update = __jsonObject.update; + } + } + + } + + getFilePattern() : Array { + return this.filePattern; + } + setFilePattern(filePattern : Array) : void { + this.filePattern = filePattern; + } + withFilePattern(filePattern : Array) : org.eclipse.che.api.git.shared.AddRequest { + this.filePattern = filePattern; + return this; + } + isUpdate() : boolean { + return this.update; + } + setUpdate(update : boolean) : void { + this.update = update; + } + withUpdate(update : boolean) : org.eclipse.che.api.git.shared.AddRequest { + this.update = update; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.filePattern) { + let listArray = []; + this.filePattern.forEach((item) => { + listArray.push(item); + json.filePattern = listArray; + }); + } + if (this.update) { + json.update = this.update; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface ProjectProblemDto { + setMessage(arg0): void; + getCode(): number; + setCode(arg0): void; + withCode(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto; + withMessage(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto; + getMessage(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class ProjectProblemDtoImpl implements org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto { + + code : number; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.code) { + this.code = __jsonObject.code; + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + setMessage(message : string) : void { + this.message = message; + } + getCode() : number { + return this.code; + } + setCode(code : number) : void { + this.code = code; + } + withCode(code : number) : org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto { + this.code = code; + return this; + } + withMessage(message : string) : org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto { + this.message = message; + return this; + } + getMessage() : string { + return this.message; + } + + toJson() : any { + let json : any = {}; + + if (this.code) { + json.code = this.code; + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export interface ActionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.action.ActionDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export class ActionDtoImpl implements org.eclipse.che.api.debug.shared.dto.action.ActionDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.action.ActionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface FactoryDto { + setId(arg0): void; + getWorkspace(): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + withName(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + withLinks(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + withId(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + setWorkspace(arg0): void; + withWorkspace(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + getPolicies(): org.eclipse.che.api.factory.shared.dto.PoliciesDto; + setPolicies(arg0): void; + withPolicies(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + getV(): string; + setV(arg0): void; + withV(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + getCreator(): org.eclipse.che.api.factory.shared.dto.AuthorDto; + setCreator(arg0): void; + withCreator(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + getButton(): org.eclipse.che.api.factory.shared.dto.ButtonDto; + setButton(arg0): void; + withButton(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + getIde(): org.eclipse.che.api.factory.shared.dto.IdeDto; + setIde(arg0): void; + withIde(arg0): org.eclipse.che.api.factory.shared.dto.FactoryDto; + getName(): string; + setName(arg0): void; + getId(): string; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class FactoryDtoImpl implements org.eclipse.che.api.factory.shared.dto.FactoryDto { + + button : org.eclipse.che.api.factory.shared.dto.ButtonDto; + workspace : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + creator : org.eclipse.che.api.factory.shared.dto.AuthorDto; + v : string; + name : string; + policies : org.eclipse.che.api.factory.shared.dto.PoliciesDto; + links : Array; + id : string; + ide : org.eclipse.che.api.factory.shared.dto.IdeDto; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.button) { + this.button = new org.eclipse.che.api.factory.shared.dto.ButtonDtoImpl(__jsonObject.button); + } + } + if (__jsonObject) { + if (__jsonObject.workspace) { + this.workspace = new org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDtoImpl(__jsonObject.workspace); + } + } + if (__jsonObject) { + if (__jsonObject.creator) { + this.creator = new org.eclipse.che.api.factory.shared.dto.AuthorDtoImpl(__jsonObject.creator); + } + } + if (__jsonObject) { + if (__jsonObject.v) { + this.v = __jsonObject.v; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.policies) { + this.policies = new org.eclipse.che.api.factory.shared.dto.PoliciesDtoImpl(__jsonObject.policies); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.ide) { + this.ide = new org.eclipse.che.api.factory.shared.dto.IdeDtoImpl(__jsonObject.ide); + } + } + + } + + setId(id : string) : void { + this.id = id; + } + getWorkspace() : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + return this.workspace; + } + withName(name : string) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.name = name; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.links = links; + return this; + } + withId(id : string) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.id = id; + return this; + } + setWorkspace(workspace : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto) : void { + this.workspace = workspace; + } + withWorkspace(workspace : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.workspace = workspace; + return this; + } + getPolicies() : org.eclipse.che.api.factory.shared.dto.PoliciesDto { + return this.policies; + } + setPolicies(policies : org.eclipse.che.api.factory.shared.dto.PoliciesDto) : void { + this.policies = policies; + } + withPolicies(policies : org.eclipse.che.api.factory.shared.dto.PoliciesDto) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.policies = policies; + return this; + } + getV() : string { + return this.v; + } + setV(v : string) : void { + this.v = v; + } + withV(v : string) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.v = v; + return this; + } + getCreator() : org.eclipse.che.api.factory.shared.dto.AuthorDto { + return this.creator; + } + setCreator(creator : org.eclipse.che.api.factory.shared.dto.AuthorDto) : void { + this.creator = creator; + } + withCreator(creator : org.eclipse.che.api.factory.shared.dto.AuthorDto) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.creator = creator; + return this; + } + getButton() : org.eclipse.che.api.factory.shared.dto.ButtonDto { + return this.button; + } + setButton(button : org.eclipse.che.api.factory.shared.dto.ButtonDto) : void { + this.button = button; + } + withButton(button : org.eclipse.che.api.factory.shared.dto.ButtonDto) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.button = button; + return this; + } + getIde() : org.eclipse.che.api.factory.shared.dto.IdeDto { + return this.ide; + } + setIde(ide : org.eclipse.che.api.factory.shared.dto.IdeDto) : void { + this.ide = ide; + } + withIde(ide : org.eclipse.che.api.factory.shared.dto.IdeDto) : org.eclipse.che.api.factory.shared.dto.FactoryDto { + this.ide = ide; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getId() : string { + return this.id; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.button) { + json.button = (this.button as org.eclipse.che.api.factory.shared.dto.ButtonDtoImpl).toJson(); + } + if (this.workspace) { + json.workspace = (this.workspace as org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDtoImpl).toJson(); + } + if (this.creator) { + json.creator = (this.creator as org.eclipse.che.api.factory.shared.dto.AuthorDtoImpl).toJson(); + } + if (this.v) { + json.v = this.v; + } + if (this.name) { + json.name = this.name; + } + if (this.policies) { + json.policies = (this.policies as org.eclipse.che.api.factory.shared.dto.PoliciesDtoImpl).toJson(); + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.id) { + json.id = this.id; + } + if (this.ide) { + json.ide = (this.ide as org.eclipse.che.api.factory.shared.dto.IdeDtoImpl).toJson(); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface Hyperlinks { + getLinks(): Array; + setLinks(arg0): void; + withLinks(arg0): org.eclipse.che.api.core.rest.shared.dto.Hyperlinks; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class HyperlinksImpl implements org.eclipse.che.api.core.rest.shared.dto.Hyperlinks { + + links : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + + } + + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + withLinks(links : Array) : org.eclipse.che.api.core.rest.shared.dto.Hyperlinks { + this.links = links; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface MergeResult { + getConflicts(): Array; + setConflicts(arg0): void; + withConflicts(arg0): org.eclipse.che.api.git.shared.MergeResult; + getFailed(): Array; + setFailed(arg0): void; + withFailed(arg0): org.eclipse.che.api.git.shared.MergeResult; + getNewHead(): string; + setNewHead(arg0): void; + withNewHead(arg0): org.eclipse.che.api.git.shared.MergeResult; + getMergeStatus(): string; + setMergeStatus(arg0): void; + withMergeStatus(arg0): org.eclipse.che.api.git.shared.MergeResult; + getMergedCommits(): Array; + setMergedCommits(arg0): void; + withMergedCommits(arg0): org.eclipse.che.api.git.shared.MergeResult; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class MergeResultImpl implements org.eclipse.che.api.git.shared.MergeResult { + + newHead : string; + mergedCommits : Array; + conflicts : Array; + failed : Array; + mergeStatus : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.newHead) { + this.newHead = __jsonObject.newHead; + } + } + this.mergedCommits = new Array(); + if (__jsonObject) { + if (__jsonObject.mergedCommits) { + __jsonObject.mergedCommits.forEach((item) => { + this.mergedCommits.push(item); + }); + } + } + this.conflicts = new Array(); + if (__jsonObject) { + if (__jsonObject.conflicts) { + __jsonObject.conflicts.forEach((item) => { + this.conflicts.push(item); + }); + } + } + this.failed = new Array(); + if (__jsonObject) { + if (__jsonObject.failed) { + __jsonObject.failed.forEach((item) => { + this.failed.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.mergeStatus) { + this.mergeStatus = __jsonObject.mergeStatus; + } + } + + } + + getConflicts() : Array { + return this.conflicts; + } + setConflicts(conflicts : Array) : void { + this.conflicts = conflicts; + } + withConflicts(conflicts : Array) : org.eclipse.che.api.git.shared.MergeResult { + this.conflicts = conflicts; + return this; + } + getFailed() : Array { + return this.failed; + } + setFailed(failed : Array) : void { + this.failed = failed; + } + withFailed(failed : Array) : org.eclipse.che.api.git.shared.MergeResult { + this.failed = failed; + return this; + } + getNewHead() : string { + return this.newHead; + } + setNewHead(newHead : string) : void { + this.newHead = newHead; + } + withNewHead(newHead : string) : org.eclipse.che.api.git.shared.MergeResult { + this.newHead = newHead; + return this; + } + getMergeStatus() : string { + return this.mergeStatus; + } + setMergeStatus(mergeStatus : string) : void { + this.mergeStatus = mergeStatus; + } + withMergeStatus(mergeStatus : string) : org.eclipse.che.api.git.shared.MergeResult { + this.mergeStatus = mergeStatus; + return this; + } + getMergedCommits() : Array { + return this.mergedCommits; + } + setMergedCommits(mergedCommits : Array) : void { + this.mergedCommits = mergedCommits; + } + withMergedCommits(mergedCommits : Array) : org.eclipse.che.api.git.shared.MergeResult { + this.mergedCommits = mergedCommits; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.newHead) { + json.newHead = this.newHead; + } + if (this.mergedCommits) { + let listArray = []; + this.mergedCommits.forEach((item) => { + listArray.push(item); + json.mergedCommits = listArray; + }); + } + if (this.conflicts) { + let listArray = []; + this.conflicts.forEach((item) => { + listArray.push(item); + json.conflicts = listArray; + }); + } + if (this.failed) { + let listArray = []; + this.failed.forEach((item) => { + listArray.push(item); + json.failed = listArray; + }); + } + if (this.mergeStatus) { + json.mergeStatus = this.mergeStatus; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface DebuggerInfoDto { + getVersion(): string; + setVersion(arg0): void; + setFile(arg0): void; + setHost(arg0): void; + setPort(arg0): void; + getPid(): number; + setPid(arg0): void; + withName(arg0): org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + withVersion(arg0): org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + withPort(arg0): org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + withPid(arg0): org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + withFile(arg0): org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + withHost(arg0): org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + getName(): string; + setName(arg0): void; + getFile(): string; + getHost(): string; + getPort(): number; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class DebuggerInfoDtoImpl implements org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + + file : string; + port : number; + host : string; + name : string; + pid : number; + version : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.file) { + this.file = __jsonObject.file; + } + } + if (__jsonObject) { + if (__jsonObject.port) { + this.port = __jsonObject.port; + } + } + if (__jsonObject) { + if (__jsonObject.host) { + this.host = __jsonObject.host; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.pid) { + this.pid = __jsonObject.pid; + } + } + if (__jsonObject) { + if (__jsonObject.version) { + this.version = __jsonObject.version; + } + } + + } + + getVersion() : string { + return this.version; + } + setVersion(version : string) : void { + this.version = version; + } + setFile(file : string) : void { + this.file = file; + } + setHost(host : string) : void { + this.host = host; + } + setPort(port : number) : void { + this.port = port; + } + getPid() : number { + return this.pid; + } + setPid(pid : number) : void { + this.pid = pid; + } + withName(name : string) : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + this.name = name; + return this; + } + withVersion(version : string) : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + this.version = version; + return this; + } + withPort(port : number) : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + this.port = port; + return this; + } + withPid(pid : number) : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + this.pid = pid; + return this; + } + withFile(file : string) : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + this.file = file; + return this; + } + withHost(host : string) : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + this.host = host; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getFile() : string { + return this.file; + } + getHost() : string { + return this.host; + } + getPort() : number { + return this.port; + } + + toJson() : any { + let json : any = {}; + + if (this.file) { + json.file = this.file; + } + if (this.port) { + json.port = this.port; + } + if (this.host) { + json.host = this.host; + } + if (this.name) { + json.name = this.name; + } + if (this.pid) { + json.pid = this.pid; + } + if (this.version) { + json.version = this.version; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export interface StepIntoActionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.action.StepIntoActionDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export class StepIntoActionDtoImpl implements org.eclipse.che.api.debug.shared.dto.action.StepIntoActionDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.action.StepIntoActionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export interface JsonRpcError { + getData(): string; + getCode(): number; + withData(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError; + withCode(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError; + withMessage(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError; + getMessage(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export class JsonRpcErrorImpl implements org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError { + + code : number; + data : string; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.code) { + this.code = __jsonObject.code; + } + } + if (__jsonObject) { + if (__jsonObject.data) { + this.data = __jsonObject.data; + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + getData() : string { + return this.data; + } + getCode() : number { + return this.code; + } + withData(data : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError { + this.data = data; + return this; + } + withCode(code : number) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError { + this.code = code; + return this; + } + withMessage(message : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError { + this.message = message; + return this; + } + getMessage() : string { + return this.message; + } + + toJson() : any { + let json : any = {}; + + if (this.code) { + json.code = this.code; + } + if (this.data) { + json.data = this.data; + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface ProjectConfigDto { + getProblems(): Array; + getDescription(): string; + setDescription(arg0): void; + withType(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + setType(arg0): void; + withDescription(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + getSource(): org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; + withSource(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + setSource(arg0): void; + setProblems(arg0): void; + setPath(arg0): void; + withName(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + getLinks(): Array; + setLinks(arg0): void; + withLinks(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + withPath(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + getMixins(): Array; + setMixins(arg0): void; + withMixins(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + withProblems(arg0): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + getName(): string; + setName(arg0): void; + getType(): string; + getPath(): string; + getAttributes(): Map>; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class ProjectConfigDtoImpl implements org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + + path : string; + mixins : Array; + name : string; + description : string; + attributes : Map>; + links : Array; + source : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; + type : string; + problems : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + this.mixins = new Array(); + if (__jsonObject) { + if (__jsonObject.mixins) { + __jsonObject.mixins.forEach((item) => { + this.mixins.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.attributes = new Map>(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.source) { + this.source = new org.eclipse.che.api.workspace.shared.dto.SourceStorageDtoImpl(__jsonObject.source); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + this.problems = new Array(); + if (__jsonObject) { + if (__jsonObject.problems) { + __jsonObject.problems.forEach((item) => { + this.problems.push(new org.eclipse.che.api.workspace.shared.dto.ProjectProblemDtoImpl(item)); + }); + } + } + + } + + getProblems() : Array { + return this.problems; + } + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withType(type : string) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withDescription(description : string) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.description = description; + return this; + } + getSource() : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto { + return this.source; + } + withSource(source : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.source = source; + return this; + } + setSource(source : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto) : void { + this.source = source; + } + setProblems(problems : Array) : void { + this.problems = problems; + } + setPath(path : string) : void { + this.path = path; + } + withName(name : string) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.name = name; + return this; + } + setAttributes(attributes : Map>) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map>) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.attributes = attributes; + return this; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + withLinks(links : Array) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.links = links; + return this; + } + withPath(path : string) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.path = path; + return this; + } + getMixins() : Array { + return this.mixins; + } + setMixins(mixins : Array) : void { + this.mixins = mixins; + } + withMixins(mixins : Array) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.mixins = mixins; + return this; + } + withProblems(problems : Array) : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + this.problems = problems; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getType() : string { + return this.type; + } + getPath() : string { + return this.path; + } + getAttributes() : Map> { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.mixins) { + let listArray = []; + this.mixins.forEach((item) => { + listArray.push(item); + json.mixins = listArray; + }); + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.source) { + json.source = (this.source as org.eclipse.che.api.workspace.shared.dto.SourceStorageDtoImpl).toJson(); + } + if (this.type) { + json.type = this.type; + } + if (this.problems) { + let listArray = []; + this.problems.forEach((item) => { + listArray.push((item as org.eclipse.che.api.workspace.shared.dto.ProjectProblemDtoImpl).toJson()); + json.problems = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface RepoInfo { + withRemoteUri(arg0): org.eclipse.che.api.git.shared.RepoInfo; + getRemoteUri(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RepoInfoImpl implements org.eclipse.che.api.git.shared.RepoInfo { + + remoteUri : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.remoteUri) { + this.remoteUri = __jsonObject.remoteUri; + } + } + + } + + withRemoteUri(remoteUri : string) : org.eclipse.che.api.git.shared.RepoInfo { + this.remoteUri = remoteUri; + return this; + } + getRemoteUri() : string { + return this.remoteUri; + } + + toJson() : any { + let json : any = {}; + + if (this.remoteUri) { + json.remoteUri = this.remoteUri; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface SourceEstimation { + withType(arg0): org.eclipse.che.api.project.shared.dto.SourceEstimation; + withAttributes(arg0): org.eclipse.che.api.project.shared.dto.SourceEstimation; + withMatched(arg0): org.eclipse.che.api.project.shared.dto.SourceEstimation; + isMatched(): boolean; + getType(): string; + getAttributes(): Map>; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class SourceEstimationImpl implements org.eclipse.che.api.project.shared.dto.SourceEstimation { + + attributes : Map>; + matched : boolean; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.attributes = new Map>(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + if (__jsonObject) { + if (__jsonObject.matched) { + this.matched = __jsonObject.matched; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.project.shared.dto.SourceEstimation { + this.type = type; + return this; + } + withAttributes(attributes : Map>) : org.eclipse.che.api.project.shared.dto.SourceEstimation { + this.attributes = attributes; + return this; + } + withMatched(matched : boolean) : org.eclipse.che.api.project.shared.dto.SourceEstimation { + this.matched = matched; + return this; + } + isMatched() : boolean { + return this.matched; + } + getType() : string { + return this.type; + } + getAttributes() : Map> { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.matched) { + json.matched = this.matched; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.agent.shared.dto { + + export interface AgentDto { + getVersion(): string; + getServers(): Map; + setServers(arg0): void; + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + setVersion(arg0): void; + getDependencies(): Array; + setId(arg0): void; + setDependencies(arg0): void; + withName(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + withDependencies(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + withId(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + withVersion(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + setScript(arg0): void; + withScript(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + withProperties(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + withServers(arg0): org.eclipse.che.api.agent.shared.dto.AgentDto; + getName(): string; + getProperties(): Map; + setProperties(arg0): void; + setName(arg0): void; + getId(): string; + getScript(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.agent.shared.dto { + + export class AgentDtoImpl implements org.eclipse.che.api.agent.shared.dto.AgentDto { + + servers : Map; + name : string; + description : string; + id : string; + version : string; + script : string; + properties : Map; + dependencies : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.servers = new Map(); + if (__jsonObject) { + if (__jsonObject.servers) { + let tmp : Array = Object.keys(__jsonObject.servers); + tmp.forEach((key) => { + this.servers.set(key, new org.eclipse.che.api.workspace.shared.dto.ServerConf2DtoImpl(__jsonObject.servers[key])); + }); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.version) { + this.version = __jsonObject.version; + } + } + if (__jsonObject) { + if (__jsonObject.script) { + this.script = __jsonObject.script; + } + } + this.properties = new Map(); + if (__jsonObject) { + if (__jsonObject.properties) { + let tmp : Array = Object.keys(__jsonObject.properties); + tmp.forEach((key) => { + this.properties.set(key, __jsonObject.properties[key]); + }); + } + } + this.dependencies = new Array(); + if (__jsonObject) { + if (__jsonObject.dependencies) { + __jsonObject.dependencies.forEach((item) => { + this.dependencies.push(item); + }); + } + } + + } + + getVersion() : string { + return this.version; + } + getServers() : Map { + return this.servers; + } + setServers(servers : Map) : void { + this.servers = servers; + } + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.description = description; + return this; + } + setVersion(version : string) : void { + this.version = version; + } + getDependencies() : Array { + return this.dependencies; + } + setId(id : string) : void { + this.id = id; + } + setDependencies(dependencies : Array) : void { + this.dependencies = dependencies; + } + withName(name : string) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.name = name; + return this; + } + withDependencies(dependencies : Array) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.dependencies = dependencies; + return this; + } + withId(id : string) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.id = id; + return this; + } + withVersion(version : string) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.version = version; + return this; + } + setScript(script : string) : void { + this.script = script; + } + withScript(script : string) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.script = script; + return this; + } + withProperties(properties : Map) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.properties = properties; + return this; + } + withServers(servers : Map) : org.eclipse.che.api.agent.shared.dto.AgentDto { + this.servers = servers; + return this; + } + getName() : string { + return this.name; + } + getProperties() : Map { + return this.properties; + } + setProperties(properties : Map) : void { + this.properties = properties; + } + setName(name : string) : void { + this.name = name; + } + getId() : string { + return this.id; + } + getScript() : string { + return this.script; + } + + toJson() : any { + let json : any = {}; + + if (this.servers) { + let tmpMap : any = {}; + for (const [key, value] of this.servers.entries()) { + tmpMap[key] = (value as org.eclipse.che.api.workspace.shared.dto.ServerConf2DtoImpl).toJson(); + } + json.servers = tmpMap; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.id) { + json.id = this.id; + } + if (this.version) { + json.version = this.version; + } + if (this.script) { + json.script = this.script; + } + if (this.properties) { + let tmpMap : any = {}; + for (const [key, value] of this.properties.entries()) { + tmpMap[key] = value; + } + json.properties = tmpMap; + } + if (this.dependencies) { + let listArray = []; + this.dependencies.forEach((item) => { + listArray.push(item); + json.dependencies = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface ProjectImporterDescriptor { + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor; + setId(arg0): void; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor; + withId(arg0): org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor; + getCategory(): string; + setCategory(arg0): void; + withCategory(arg0): org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor; + isInternal(): boolean; + setInternal(arg0): void; + withInternal(arg0): org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor; + getId(): string; + getAttributes(): Map; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class ProjectImporterDescriptorImpl implements org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor { + + internal : boolean; + description : string; + attributes : Map; + id : string; + category : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.internal) { + this.internal = __jsonObject.internal; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.category) { + this.category = __jsonObject.category; + } + } + + } + + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor { + this.description = description; + return this; + } + setId(id : string) : void { + this.id = id; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor { + this.attributes = attributes; + return this; + } + withId(id : string) : org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor { + this.id = id; + return this; + } + getCategory() : string { + return this.category; + } + setCategory(category : string) : void { + this.category = category; + } + withCategory(category : string) : org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor { + this.category = category; + return this; + } + isInternal() : boolean { + return this.internal; + } + setInternal(internal : boolean) : void { + this.internal = internal; + } + withInternal(internal : boolean) : org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor { + this.internal = internal; + return this; + } + getId() : string { + return this.id; + } + getAttributes() : Map { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.internal) { + json.internal = this.internal; + } + if (this.description) { + json.description = this.description; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.id) { + json.id = this.id; + } + if (this.category) { + json.category = this.category; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface MachineSourceDto { + withType(arg0): org.eclipse.che.api.machine.shared.dto.MachineSourceDto; + setType(arg0): void; + setLocation(arg0): void; + setContent(arg0): void; + withContent(arg0): org.eclipse.che.api.machine.shared.dto.MachineSourceDto; + withLocation(arg0): org.eclipse.che.api.machine.shared.dto.MachineSourceDto; + getLocation(): string; + getType(): string; + getContent(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class MachineSourceDtoImpl implements org.eclipse.che.api.machine.shared.dto.MachineSourceDto { + + location : string; + type : string; + content : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.location) { + this.location = __jsonObject.location; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.content) { + this.content = __jsonObject.content; + } + } + + } + + withType(type : string) : org.eclipse.che.api.machine.shared.dto.MachineSourceDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setLocation(location : string) : void { + this.location = location; + } + setContent(content : string) : void { + this.content = content; + } + withContent(content : string) : org.eclipse.che.api.machine.shared.dto.MachineSourceDto { + this.content = content; + return this; + } + withLocation(location : string) : org.eclipse.che.api.machine.shared.dto.MachineSourceDto { + this.location = location; + return this; + } + getLocation() : string { + return this.location; + } + getType() : string { + return this.type; + } + getContent() : string { + return this.content; + } + + toJson() : any { + let json : any = {}; + + if (this.location) { + json.location = this.location; + } + if (this.type) { + json.type = this.type; + } + if (this.content) { + json.content = this.content; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface EnvironmentDto { + setRecipe(arg0): void; + withRecipe(arg0): org.eclipse.che.api.workspace.shared.dto.EnvironmentDto; + getMachines(): Map; + setMachines(arg0): void; + withMachines(arg0): org.eclipse.che.api.workspace.shared.dto.EnvironmentDto; + getRecipe(): org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class EnvironmentDtoImpl implements org.eclipse.che.api.workspace.shared.dto.EnvironmentDto { + + recipe : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto; + machines : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.recipe) { + this.recipe = new org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDtoImpl(__jsonObject.recipe); + } + } + this.machines = new Map(); + if (__jsonObject) { + if (__jsonObject.machines) { + let tmp : Array = Object.keys(__jsonObject.machines); + tmp.forEach((key) => { + this.machines.set(key, new org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDtoImpl(__jsonObject.machines[key])); + }); + } + } + + } + + setRecipe(recipe : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto) : void { + this.recipe = recipe; + } + withRecipe(recipe : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto) : org.eclipse.che.api.workspace.shared.dto.EnvironmentDto { + this.recipe = recipe; + return this; + } + getMachines() : Map { + return this.machines; + } + setMachines(machines : Map) : void { + this.machines = machines; + } + withMachines(machines : Map) : org.eclipse.che.api.workspace.shared.dto.EnvironmentDto { + this.machines = machines; + return this; + } + getRecipe() : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto { + return this.recipe; + } + + toJson() : any { + let json : any = {}; + + if (this.recipe) { + json.recipe = (this.recipe as org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDtoImpl).toJson(); + } + if (this.machines) { + let tmpMap : any = {}; + for (const [key, value] of this.machines.entries()) { + tmpMap[key] = (value as org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDtoImpl).toJson(); + } + json.machines = tmpMap; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface Log { + getCommits(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class LogImpl implements org.eclipse.che.api.git.shared.Log { + + commits : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.commits = new Array(); + if (__jsonObject) { + if (__jsonObject.commits) { + __jsonObject.commits.forEach((item) => { + this.commits.push(new org.eclipse.che.api.git.shared.RevisionImpl(item)); + }); + } + } + + } + + getCommits() : Array { + return this.commits; + } + + toJson() : any { + let json : any = {}; + + if (this.commits) { + let listArray = []; + this.commits.forEach((item) => { + listArray.push((item as org.eclipse.che.api.git.shared.RevisionImpl).toJson()); + json.commits = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export interface DisconnectEventDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.event.DisconnectEventDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export class DisconnectEventDtoImpl implements org.eclipse.che.api.debug.shared.dto.event.DisconnectEventDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.event.DisconnectEventDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export interface SuspendEventDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.event.SuspendEventDto; + setType(arg0): void; + setLocation(arg0): void; + withLocation(arg0): org.eclipse.che.api.debug.shared.dto.event.SuspendEventDto; + getLocation(): org.eclipse.che.api.debug.shared.dto.LocationDto; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export class SuspendEventDtoImpl implements org.eclipse.che.api.debug.shared.dto.event.SuspendEventDto { + + location : org.eclipse.che.api.debug.shared.dto.LocationDto; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.location) { + this.location = new org.eclipse.che.api.debug.shared.dto.LocationDtoImpl(__jsonObject.location); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.event.SuspendEventDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setLocation(location : org.eclipse.che.api.debug.shared.dto.LocationDto) : void { + this.location = location; + } + withLocation(location : org.eclipse.che.api.debug.shared.dto.LocationDto) : org.eclipse.che.api.debug.shared.dto.event.SuspendEventDto { + this.location = location; + return this; + } + getLocation() : org.eclipse.che.api.debug.shared.dto.LocationDto { + return this.location; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.location) { + json.location = (this.location as org.eclipse.che.api.debug.shared.dto.LocationDtoImpl).toJson(); + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface BreakpointDto { + isEnabled(): boolean; + setEnabled(arg0): void; + setLocation(arg0): void; + withLocation(arg0): org.eclipse.che.api.debug.shared.dto.BreakpointDto; + setCondition(arg0): void; + withCondition(arg0): org.eclipse.che.api.debug.shared.dto.BreakpointDto; + withEnabled(arg0): org.eclipse.che.api.debug.shared.dto.BreakpointDto; + getCondition(): string; + getLocation(): org.eclipse.che.api.debug.shared.dto.LocationDto; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class BreakpointDtoImpl implements org.eclipse.che.api.debug.shared.dto.BreakpointDto { + + condition : string; + location : org.eclipse.che.api.debug.shared.dto.LocationDto; + enabled : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.condition) { + this.condition = __jsonObject.condition; + } + } + if (__jsonObject) { + if (__jsonObject.location) { + this.location = new org.eclipse.che.api.debug.shared.dto.LocationDtoImpl(__jsonObject.location); + } + } + if (__jsonObject) { + if (__jsonObject.enabled) { + this.enabled = __jsonObject.enabled; + } + } + + } + + isEnabled() : boolean { + return this.enabled; + } + setEnabled(enabled : boolean) : void { + this.enabled = enabled; + } + setLocation(location : org.eclipse.che.api.debug.shared.dto.LocationDto) : void { + this.location = location; + } + withLocation(location : org.eclipse.che.api.debug.shared.dto.LocationDto) : org.eclipse.che.api.debug.shared.dto.BreakpointDto { + this.location = location; + return this; + } + setCondition(condition : string) : void { + this.condition = condition; + } + withCondition(condition : string) : org.eclipse.che.api.debug.shared.dto.BreakpointDto { + this.condition = condition; + return this; + } + withEnabled(enabled : boolean) : org.eclipse.che.api.debug.shared.dto.BreakpointDto { + this.enabled = enabled; + return this; + } + getCondition() : string { + return this.condition; + } + getLocation() : org.eclipse.che.api.debug.shared.dto.LocationDto { + return this.location; + } + + toJson() : any { + let json : any = {}; + + if (this.condition) { + json.condition = this.condition; + } + if (this.location) { + json.location = (this.location as org.eclipse.che.api.debug.shared.dto.LocationDtoImpl).toJson(); + } + if (this.enabled) { + json.enabled = this.enabled; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.user.shared.dto { + + export interface ProfileDto { + getEmail(): string; + getUserId(): string; + setUserId(arg0): void; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.user.shared.dto.ProfileDto; + getLinks(): Array; + setLinks(arg0): void; + withLinks(arg0): org.eclipse.che.api.user.shared.dto.ProfileDto; + withUserId(arg0): org.eclipse.che.api.user.shared.dto.ProfileDto; + withEmail(arg0): org.eclipse.che.api.user.shared.dto.ProfileDto; + getAttributes(): Map; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.user.shared.dto { + + export class ProfileDtoImpl implements org.eclipse.che.api.user.shared.dto.ProfileDto { + + attributes : Map; + links : Array; + userId : string; + email : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.userId) { + this.userId = __jsonObject.userId; + } + } + if (__jsonObject) { + if (__jsonObject.email) { + this.email = __jsonObject.email; + } + } + + } + + getEmail() : string { + return this.email; + } + getUserId() : string { + return this.userId; + } + setUserId(userId : string) : void { + this.userId = userId; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.user.shared.dto.ProfileDto { + this.attributes = attributes; + return this; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + withLinks(links : Array) : org.eclipse.che.api.user.shared.dto.ProfileDto { + this.links = links; + return this; + } + withUserId(userId : string) : org.eclipse.che.api.user.shared.dto.ProfileDto { + this.userId = userId; + return this; + } + withEmail(email : string) : org.eclipse.che.api.user.shared.dto.ProfileDto { + this.email = email; + return this; + } + getAttributes() : Map { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.userId) { + json.userId = this.userId; + } + if (this.email) { + json.email = this.email; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface WorkspaceRuntimeDto { + withLinks(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; + withActiveEnv(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; + getDevMachine(): org.eclipse.che.api.machine.shared.dto.MachineDto; + setDevMachine(arg0): void; + withDevMachine(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; + getMachines(): Array; + setMachines(arg0): void; + withMachines(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; + setRootFolder(arg0): void; + withRootFolder(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; + setActiveEnv(arg0): void; + getActiveEnv(): string; + getRootFolder(): string; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class WorkspaceRuntimeDtoImpl implements org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto { + + devMachine : org.eclipse.che.api.machine.shared.dto.MachineDto; + rootFolder : string; + activeEnv : string; + links : Array; + machines : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.devMachine) { + this.devMachine = new org.eclipse.che.api.machine.shared.dto.MachineDtoImpl(__jsonObject.devMachine); + } + } + if (__jsonObject) { + if (__jsonObject.rootFolder) { + this.rootFolder = __jsonObject.rootFolder; + } + } + if (__jsonObject) { + if (__jsonObject.activeEnv) { + this.activeEnv = __jsonObject.activeEnv; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + this.machines = new Array(); + if (__jsonObject) { + if (__jsonObject.machines) { + __jsonObject.machines.forEach((item) => { + this.machines.push(new org.eclipse.che.api.machine.shared.dto.MachineDtoImpl(item)); + }); + } + } + + } + + withLinks(links : Array) : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto { + this.links = links; + return this; + } + withActiveEnv(activeEnv : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto { + this.activeEnv = activeEnv; + return this; + } + getDevMachine() : org.eclipse.che.api.machine.shared.dto.MachineDto { + return this.devMachine; + } + setDevMachine(devMachine : org.eclipse.che.api.machine.shared.dto.MachineDto) : void { + this.devMachine = devMachine; + } + withDevMachine(devMachine : org.eclipse.che.api.machine.shared.dto.MachineDto) : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto { + this.devMachine = devMachine; + return this; + } + getMachines() : Array { + return this.machines; + } + setMachines(machines : Array) : void { + this.machines = machines; + } + withMachines(machines : Array) : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto { + this.machines = machines; + return this; + } + setRootFolder(rootFolder : string) : void { + this.rootFolder = rootFolder; + } + withRootFolder(rootFolder : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto { + this.rootFolder = rootFolder; + return this; + } + setActiveEnv(activeEnv : string) : void { + this.activeEnv = activeEnv; + } + getActiveEnv() : string { + return this.activeEnv; + } + getRootFolder() : string { + return this.rootFolder; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.devMachine) { + json.devMachine = (this.devMachine as org.eclipse.che.api.machine.shared.dto.MachineDtoImpl).toJson(); + } + if (this.rootFolder) { + json.rootFolder = this.rootFolder; + } + if (this.activeEnv) { + json.activeEnv = this.activeEnv; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.machines) { + let listArray = []; + this.machines.forEach((item) => { + listArray.push((item as org.eclipse.che.api.machine.shared.dto.MachineDtoImpl).toJson()); + json.machines = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface OnAppLoadedDto { + setActions(arg0): void; + withActions(arg0): org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto; + getActions(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class OnAppLoadedDtoImpl implements org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto { + + actions : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.actions = new Array(); + if (__jsonObject) { + if (__jsonObject.actions) { + __jsonObject.actions.forEach((item) => { + this.actions.push(new org.eclipse.che.api.factory.shared.dto.IdeActionDtoImpl(item)); + }); + } + } + + } + + setActions(actions : Array) : void { + this.actions = actions; + } + withActions(actions : Array) : org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto { + this.actions = actions; + return this; + } + getActions() : Array { + return this.actions; + } + + toJson() : any { + let json : any = {}; + + if (this.actions) { + let listArray = []; + this.actions.forEach((item) => { + listArray.push((item as org.eclipse.che.api.factory.shared.dto.IdeActionDtoImpl).toJson()); + json.actions = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.user.shared.dto { + + export interface UserDto { + setId(arg0): void; + setPassword(arg0): void; + getAliases(): Array; + setAliases(arg0): void; + getPassword(): string; + getEmail(): string; + setEmail(arg0): void; + withName(arg0): org.eclipse.che.api.user.shared.dto.UserDto; + getLinks(): Array; + setLinks(arg0): void; + withLinks(arg0): org.eclipse.che.api.user.shared.dto.UserDto; + withEmail(arg0): org.eclipse.che.api.user.shared.dto.UserDto; + withId(arg0): org.eclipse.che.api.user.shared.dto.UserDto; + withAliases(arg0): org.eclipse.che.api.user.shared.dto.UserDto; + withPassword(arg0): org.eclipse.che.api.user.shared.dto.UserDto; + getName(): string; + setName(arg0): void; + getId(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.user.shared.dto { + + export class UserDtoImpl implements org.eclipse.che.api.user.shared.dto.UserDto { + + password : string; + aliases : Array; + name : string; + links : Array; + id : string; + email : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.password) { + this.password = __jsonObject.password; + } + } + this.aliases = new Array(); + if (__jsonObject) { + if (__jsonObject.aliases) { + __jsonObject.aliases.forEach((item) => { + this.aliases.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.email) { + this.email = __jsonObject.email; + } + } + + } + + setId(id : string) : void { + this.id = id; + } + setPassword(password : string) : void { + this.password = password; + } + getAliases() : Array { + return this.aliases; + } + setAliases(aliases : Array) : void { + this.aliases = aliases; + } + getPassword() : string { + return this.password; + } + getEmail() : string { + return this.email; + } + setEmail(email : string) : void { + this.email = email; + } + withName(name : string) : org.eclipse.che.api.user.shared.dto.UserDto { + this.name = name; + return this; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + withLinks(links : Array) : org.eclipse.che.api.user.shared.dto.UserDto { + this.links = links; + return this; + } + withEmail(email : string) : org.eclipse.che.api.user.shared.dto.UserDto { + this.email = email; + return this; + } + withId(id : string) : org.eclipse.che.api.user.shared.dto.UserDto { + this.id = id; + return this; + } + withAliases(aliases : Array) : org.eclipse.che.api.user.shared.dto.UserDto { + this.aliases = aliases; + return this; + } + withPassword(password : string) : org.eclipse.che.api.user.shared.dto.UserDto { + this.password = password; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getId() : string { + return this.id; + } + + toJson() : any { + let json : any = {}; + + if (this.password) { + json.password = this.password; + } + if (this.aliases) { + let listArray = []; + this.aliases.forEach((item) => { + listArray.push(item); + json.aliases = listArray; + }); + } + if (this.name) { + json.name = this.name; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.id) { + json.id = this.id; + } + if (this.email) { + json.email = this.email; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface AuthorDto { + setCreated(arg0): void; + getEmail(): string; + setEmail(arg0): void; + withName(arg0): org.eclipse.che.api.factory.shared.dto.AuthorDto; + getUserId(): string; + setUserId(arg0): void; + withUserId(arg0): org.eclipse.che.api.factory.shared.dto.AuthorDto; + withEmail(arg0): org.eclipse.che.api.factory.shared.dto.AuthorDto; + getCreated(): number; + withCreated(arg0): org.eclipse.che.api.factory.shared.dto.AuthorDto; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class AuthorDtoImpl implements org.eclipse.che.api.factory.shared.dto.AuthorDto { + + created : number; + name : string; + userId : string; + email : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.created) { + this.created = __jsonObject.created; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.userId) { + this.userId = __jsonObject.userId; + } + } + if (__jsonObject) { + if (__jsonObject.email) { + this.email = __jsonObject.email; + } + } + + } + + setCreated(created : number) : void { + this.created = created; + } + getEmail() : string { + return this.email; + } + setEmail(email : string) : void { + this.email = email; + } + withName(name : string) : org.eclipse.che.api.factory.shared.dto.AuthorDto { + this.name = name; + return this; + } + getUserId() : string { + return this.userId; + } + setUserId(userId : string) : void { + this.userId = userId; + } + withUserId(userId : string) : org.eclipse.che.api.factory.shared.dto.AuthorDto { + this.userId = userId; + return this; + } + withEmail(email : string) : org.eclipse.che.api.factory.shared.dto.AuthorDto { + this.email = email; + return this; + } + getCreated() : number { + return this.created; + } + withCreated(created : number) : org.eclipse.che.api.factory.shared.dto.AuthorDto { + this.created = created; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.created) { + json.created = this.created; + } + if (this.name) { + json.name = this.name; + } + if (this.userId) { + json.userId = this.userId; + } + if (this.email) { + json.email = this.email; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface DebugSessionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.DebugSessionDto; + setType(arg0): void; + setId(arg0): void; + withId(arg0): org.eclipse.che.api.debug.shared.dto.DebugSessionDto; + getDebuggerInfo(): org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + withDebuggerInfo(arg0): org.eclipse.che.api.debug.shared.dto.DebugSessionDto; + setDebuggerInfo(arg0): void; + getId(): string; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class DebugSessionDtoImpl implements org.eclipse.che.api.debug.shared.dto.DebugSessionDto { + + id : string; + type : string; + debuggerInfo : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.debuggerInfo) { + this.debuggerInfo = new org.eclipse.che.api.debug.shared.dto.DebuggerInfoDtoImpl(__jsonObject.debuggerInfo); + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.DebugSessionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setId(id : string) : void { + this.id = id; + } + withId(id : string) : org.eclipse.che.api.debug.shared.dto.DebugSessionDto { + this.id = id; + return this; + } + getDebuggerInfo() : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto { + return this.debuggerInfo; + } + withDebuggerInfo(debuggerInfo : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto) : org.eclipse.che.api.debug.shared.dto.DebugSessionDto { + this.debuggerInfo = debuggerInfo; + return this; + } + setDebuggerInfo(debuggerInfo : org.eclipse.che.api.debug.shared.dto.DebuggerInfoDto) : void { + this.debuggerInfo = debuggerInfo; + } + getId() : string { + return this.id; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.id) { + json.id = this.id; + } + if (this.type) { + json.type = this.type; + } + if (this.debuggerInfo) { + json.debuggerInfo = (this.debuggerInfo as org.eclipse.che.api.debug.shared.dto.DebuggerInfoDtoImpl).toJson(); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface ButtonDto { + withType(arg0): org.eclipse.che.api.factory.shared.dto.ButtonDto; + setType(arg0): void; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.factory.shared.dto.ButtonDto; + getType(): string; + getAttributes(): org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class ButtonDtoImpl implements org.eclipse.che.api.factory.shared.dto.ButtonDto { + + attributes : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.attributes) { + this.attributes = new org.eclipse.che.api.factory.shared.dto.ButtonAttributesDtoImpl(__jsonObject.attributes); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.factory.shared.dto.ButtonDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setAttributes(attributes : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto) : void { + this.attributes = attributes; + } + withAttributes(attributes : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto) : org.eclipse.che.api.factory.shared.dto.ButtonDto { + this.attributes = attributes; + return this; + } + getType() : string { + return this.type; + } + getAttributes() : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.attributes) { + json.attributes = (this.attributes as org.eclipse.che.api.factory.shared.dto.ButtonAttributesDtoImpl).toJson(); + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface ServerConfDto { + setProtocol(arg0): void; + setPort(arg0): void; + setPath(arg0): void; + withRef(arg0): org.eclipse.che.api.machine.shared.dto.ServerConfDto; + withPort(arg0): org.eclipse.che.api.machine.shared.dto.ServerConfDto; + withProtocol(arg0): org.eclipse.che.api.machine.shared.dto.ServerConfDto; + withPath(arg0): org.eclipse.che.api.machine.shared.dto.ServerConfDto; + setRef(arg0): void; + getPath(): string; + getProtocol(): string; + getPort(): string; + getRef(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class ServerConfDtoImpl implements org.eclipse.che.api.machine.shared.dto.ServerConfDto { + + path : string; + protocol : string; + ref : string; + port : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.protocol) { + this.protocol = __jsonObject.protocol; + } + } + if (__jsonObject) { + if (__jsonObject.ref) { + this.ref = __jsonObject.ref; + } + } + if (__jsonObject) { + if (__jsonObject.port) { + this.port = __jsonObject.port; + } + } + + } + + setProtocol(protocol : string) : void { + this.protocol = protocol; + } + setPort(port : string) : void { + this.port = port; + } + setPath(path : string) : void { + this.path = path; + } + withRef(ref : string) : org.eclipse.che.api.machine.shared.dto.ServerConfDto { + this.ref = ref; + return this; + } + withPort(port : string) : org.eclipse.che.api.machine.shared.dto.ServerConfDto { + this.port = port; + return this; + } + withProtocol(protocol : string) : org.eclipse.che.api.machine.shared.dto.ServerConfDto { + this.protocol = protocol; + return this; + } + withPath(path : string) : org.eclipse.che.api.machine.shared.dto.ServerConfDto { + this.path = path; + return this; + } + setRef(ref : string) : void { + this.ref = ref; + } + getPath() : string { + return this.path; + } + getProtocol() : string { + return this.protocol; + } + getPort() : string { + return this.port; + } + getRef() : string { + return this.ref; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.protocol) { + json.protocol = this.protocol; + } + if (this.ref) { + json.ref = this.ref; + } + if (this.port) { + json.port = this.port; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface FetchRequest { + setTimeout(arg0): void; + getTimeout(): number; + setPassword(arg0): void; + getUsername(): string; + getPassword(): string; + setUsername(arg0): void; + setRemote(arg0): void; + withRemote(arg0): org.eclipse.che.api.git.shared.FetchRequest; + withPassword(arg0): org.eclipse.che.api.git.shared.FetchRequest; + getRefSpec(): Array; + setRefSpec(arg0): void; + withRefSpec(arg0): org.eclipse.che.api.git.shared.FetchRequest; + getRemote(): string; + withTimeout(arg0): org.eclipse.che.api.git.shared.FetchRequest; + withUsername(arg0): org.eclipse.che.api.git.shared.FetchRequest; + setRemoveDeletedRefs(arg0): void; + withRemoveDeletedRefs(arg0): org.eclipse.che.api.git.shared.FetchRequest; + isRemoveDeletedRefs(): boolean; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class FetchRequestImpl implements org.eclipse.che.api.git.shared.FetchRequest { + + password : string; + removeDeletedRefs : boolean; + refSpec : Array; + remote : string; + timeout : number; + username : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.password) { + this.password = __jsonObject.password; + } + } + if (__jsonObject) { + if (__jsonObject.removeDeletedRefs) { + this.removeDeletedRefs = __jsonObject.removeDeletedRefs; + } + } + this.refSpec = new Array(); + if (__jsonObject) { + if (__jsonObject.refSpec) { + __jsonObject.refSpec.forEach((item) => { + this.refSpec.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.remote) { + this.remote = __jsonObject.remote; + } + } + if (__jsonObject) { + if (__jsonObject.timeout) { + this.timeout = __jsonObject.timeout; + } + } + if (__jsonObject) { + if (__jsonObject.username) { + this.username = __jsonObject.username; + } + } + + } + + setTimeout(timeout : number) : void { + this.timeout = timeout; + } + getTimeout() : number { + return this.timeout; + } + setPassword(password : string) : void { + this.password = password; + } + getUsername() : string { + return this.username; + } + getPassword() : string { + return this.password; + } + setUsername(username : string) : void { + this.username = username; + } + setRemote(remote : string) : void { + this.remote = remote; + } + withRemote(remote : string) : org.eclipse.che.api.git.shared.FetchRequest { + this.remote = remote; + return this; + } + withPassword(password : string) : org.eclipse.che.api.git.shared.FetchRequest { + this.password = password; + return this; + } + getRefSpec() : Array { + return this.refSpec; + } + setRefSpec(refSpec : Array) : void { + this.refSpec = refSpec; + } + withRefSpec(refSpec : Array) : org.eclipse.che.api.git.shared.FetchRequest { + this.refSpec = refSpec; + return this; + } + getRemote() : string { + return this.remote; + } + withTimeout(timeout : number) : org.eclipse.che.api.git.shared.FetchRequest { + this.timeout = timeout; + return this; + } + withUsername(username : string) : org.eclipse.che.api.git.shared.FetchRequest { + this.username = username; + return this; + } + setRemoveDeletedRefs(removeDeletedRefs : boolean) : void { + this.removeDeletedRefs = removeDeletedRefs; + } + withRemoveDeletedRefs(removeDeletedRefs : boolean) : org.eclipse.che.api.git.shared.FetchRequest { + this.removeDeletedRefs = removeDeletedRefs; + return this; + } + isRemoveDeletedRefs() : boolean { + return this.removeDeletedRefs; + } + + toJson() : any { + let json : any = {}; + + if (this.password) { + json.password = this.password; + } + if (this.removeDeletedRefs) { + json.removeDeletedRefs = this.removeDeletedRefs; + } + if (this.refSpec) { + let listArray = []; + this.refSpec.forEach((item) => { + listArray.push(item); + json.refSpec = listArray; + }); + } + if (this.remote) { + json.remote = this.remote; + } + if (this.timeout) { + json.timeout = this.timeout; + } + if (this.username) { + json.username = this.username; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export interface RecipeUpdate { + setDescription(arg0): void; + withType(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate; + setType(arg0): void; + withDescription(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate; + setId(arg0): void; + setTags(arg0): void; + withName(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate; + withId(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate; + setScript(arg0): void; + withScript(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate; + withTags(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate; + setName(arg0): void; + getDescription(): string; + getTags(): Array; + getCreator(): string; + getName(): string; + getId(): string; + getType(): string; + getScript(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export class RecipeUpdateImpl implements org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate { + + creator : string; + name : string; + description : string; + id : string; + type : string; + script : string; + tags : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.creator) { + this.creator = __jsonObject.creator; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.script) { + this.script = __jsonObject.script; + } + } + this.tags = new Array(); + if (__jsonObject) { + if (__jsonObject.tags) { + __jsonObject.tags.forEach((item) => { + this.tags.push(item); + }); + } + } + + } + + setDescription(description : string) : void { + this.description = description; + } + withType(type : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withDescription(description : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate { + this.description = description; + return this; + } + setId(id : string) : void { + this.id = id; + } + setTags(tags : Array) : void { + this.tags = tags; + } + withName(name : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate { + this.name = name; + return this; + } + withId(id : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate { + this.id = id; + return this; + } + setScript(script : string) : void { + this.script = script; + } + withScript(script : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate { + this.script = script; + return this; + } + withTags(tags : Array) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeUpdate { + this.tags = tags; + return this; + } + setName(name : string) : void { + this.name = name; + } + getDescription() : string { + return this.description; + } + getTags() : Array { + return this.tags; + } + getCreator() : string { + return this.creator; + } + getName() : string { + return this.name; + } + getId() : string { + return this.id; + } + getType() : string { + return this.type; + } + getScript() : string { + return this.script; + } + + toJson() : any { + let json : any = {}; + + if (this.creator) { + json.creator = this.creator; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.id) { + json.id = this.id; + } + if (this.type) { + json.type = this.type; + } + if (this.script) { + json.script = this.script; + } + if (this.tags) { + let listArray = []; + this.tags.forEach((item) => { + listArray.push(item); + json.tags = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface ValueDto { + getString(): string; + getList(): Array; + withList(arg0): org.eclipse.che.api.project.shared.dto.ValueDto; + isEmpty(): boolean; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class ValueDtoImpl implements org.eclipse.che.api.project.shared.dto.ValueDto { + + string : string; + list : Array; + empty : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.string) { + this.string = __jsonObject.string; + } + } + this.list = new Array(); + if (__jsonObject) { + if (__jsonObject.list) { + __jsonObject.list.forEach((item) => { + this.list.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.empty) { + this.empty = __jsonObject.empty; + } + } + + } + + getString() : string { + return this.string; + } + getList() : Array { + return this.list; + } + withList(list : Array) : org.eclipse.che.api.project.shared.dto.ValueDto { + this.list = list; + return this; + } + isEmpty() : boolean { + return this.empty; + } + + toJson() : any { + let json : any = {}; + + if (this.string) { + json.string = this.string; + } + if (this.list) { + let listArray = []; + this.list.forEach((item) => { + listArray.push(item); + json.list = listArray; + }); + } + if (this.empty) { + json.empty = this.empty; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface CloneRequest { + setRecursive(arg0): void; + isRecursive(): boolean; + setTimeout(arg0): void; + getTimeout(): number; + setPassword(arg0): void; + getUsername(): string; + getPassword(): string; + setUsername(arg0): void; + withPassword(arg0): org.eclipse.che.api.git.shared.CloneRequest; + withRemoteUri(arg0): org.eclipse.che.api.git.shared.CloneRequest; + getWorkingDir(): string; + getRemoteUri(): string; + withTimeout(arg0): org.eclipse.che.api.git.shared.CloneRequest; + withUsername(arg0): org.eclipse.che.api.git.shared.CloneRequest; + getBranchesToFetch(): Array; + withBranchesToFetch(arg0): org.eclipse.che.api.git.shared.CloneRequest; + withWorkingDir(arg0): org.eclipse.che.api.git.shared.CloneRequest; + getRemoteName(): string; + setRemoteName(arg0): void; + withRemoteName(arg0): org.eclipse.che.api.git.shared.CloneRequest; + withRecursive(arg0): org.eclipse.che.api.git.shared.CloneRequest; + setRemoteUri(arg0): void; + setBranchesToFetch(arg0): void; + setWorkingDir(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class CloneRequestImpl implements org.eclipse.che.api.git.shared.CloneRequest { + + password : string; + remoteUri : string; + branchesToFetch : Array; + workingDir : string; + recursive : boolean; + timeout : number; + username : string; + remoteName : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.password) { + this.password = __jsonObject.password; + } + } + if (__jsonObject) { + if (__jsonObject.remoteUri) { + this.remoteUri = __jsonObject.remoteUri; + } + } + this.branchesToFetch = new Array(); + if (__jsonObject) { + if (__jsonObject.branchesToFetch) { + __jsonObject.branchesToFetch.forEach((item) => { + this.branchesToFetch.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.workingDir) { + this.workingDir = __jsonObject.workingDir; + } + } + if (__jsonObject) { + if (__jsonObject.recursive) { + this.recursive = __jsonObject.recursive; + } + } + if (__jsonObject) { + if (__jsonObject.timeout) { + this.timeout = __jsonObject.timeout; + } + } + if (__jsonObject) { + if (__jsonObject.username) { + this.username = __jsonObject.username; + } + } + if (__jsonObject) { + if (__jsonObject.remoteName) { + this.remoteName = __jsonObject.remoteName; + } + } + + } + + setRecursive(recursive : boolean) : void { + this.recursive = recursive; + } + isRecursive() : boolean { + return this.recursive; + } + setTimeout(timeout : number) : void { + this.timeout = timeout; + } + getTimeout() : number { + return this.timeout; + } + setPassword(password : string) : void { + this.password = password; + } + getUsername() : string { + return this.username; + } + getPassword() : string { + return this.password; + } + setUsername(username : string) : void { + this.username = username; + } + withPassword(password : string) : org.eclipse.che.api.git.shared.CloneRequest { + this.password = password; + return this; + } + withRemoteUri(remoteUri : string) : org.eclipse.che.api.git.shared.CloneRequest { + this.remoteUri = remoteUri; + return this; + } + getWorkingDir() : string { + return this.workingDir; + } + getRemoteUri() : string { + return this.remoteUri; + } + withTimeout(timeout : number) : org.eclipse.che.api.git.shared.CloneRequest { + this.timeout = timeout; + return this; + } + withUsername(username : string) : org.eclipse.che.api.git.shared.CloneRequest { + this.username = username; + return this; + } + getBranchesToFetch() : Array { + return this.branchesToFetch; + } + withBranchesToFetch(branchesToFetch : Array) : org.eclipse.che.api.git.shared.CloneRequest { + this.branchesToFetch = branchesToFetch; + return this; + } + withWorkingDir(workingDir : string) : org.eclipse.che.api.git.shared.CloneRequest { + this.workingDir = workingDir; + return this; + } + getRemoteName() : string { + return this.remoteName; + } + setRemoteName(remoteName : string) : void { + this.remoteName = remoteName; + } + withRemoteName(remoteName : string) : org.eclipse.che.api.git.shared.CloneRequest { + this.remoteName = remoteName; + return this; + } + withRecursive(recursive : boolean) : org.eclipse.che.api.git.shared.CloneRequest { + this.recursive = recursive; + return this; + } + setRemoteUri(remoteUri : string) : void { + this.remoteUri = remoteUri; + } + setBranchesToFetch(branchesToFetch : Array) : void { + this.branchesToFetch = branchesToFetch; + } + setWorkingDir(workingDir : string) : void { + this.workingDir = workingDir; + } + + toJson() : any { + let json : any = {}; + + if (this.password) { + json.password = this.password; + } + if (this.remoteUri) { + json.remoteUri = this.remoteUri; + } + if (this.branchesToFetch) { + let listArray = []; + this.branchesToFetch.forEach((item) => { + listArray.push(item); + json.branchesToFetch = listArray; + }); + } + if (this.workingDir) { + json.workingDir = this.workingDir; + } + if (this.recursive) { + json.recursive = this.recursive; + } + if (this.timeout) { + json.timeout = this.timeout; + } + if (this.username) { + json.username = this.username; + } + if (this.remoteName) { + json.remoteName = this.remoteName; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface StackFrameDumpDto { + setFields(arg0): void; + getVariables(): Array; + withFields(arg0): org.eclipse.che.api.debug.shared.dto.StackFrameDumpDto; + setVariables(arg0): void; + withVariables(arg0): org.eclipse.che.api.debug.shared.dto.StackFrameDumpDto; + getFields(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class StackFrameDumpDtoImpl implements org.eclipse.che.api.debug.shared.dto.StackFrameDumpDto { + + variables : Array; + fields : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.variables = new Array(); + if (__jsonObject) { + if (__jsonObject.variables) { + __jsonObject.variables.forEach((item) => { + this.variables.push(new org.eclipse.che.api.debug.shared.dto.VariableDtoImpl(item)); + }); + } + } + this.fields = new Array(); + if (__jsonObject) { + if (__jsonObject.fields) { + __jsonObject.fields.forEach((item) => { + this.fields.push(new org.eclipse.che.api.debug.shared.dto.FieldDtoImpl(item)); + }); + } + } + + } + + setFields(fields : Array) : void { + this.fields = fields; + } + getVariables() : Array { + return this.variables; + } + withFields(fields : Array) : org.eclipse.che.api.debug.shared.dto.StackFrameDumpDto { + this.fields = fields; + return this; + } + setVariables(variables : Array) : void { + this.variables = variables; + } + withVariables(variables : Array) : org.eclipse.che.api.debug.shared.dto.StackFrameDumpDto { + this.variables = variables; + return this; + } + getFields() : Array { + return this.fields; + } + + toJson() : any { + let json : any = {}; + + if (this.variables) { + let listArray = []; + this.variables.forEach((item) => { + listArray.push((item as org.eclipse.che.api.debug.shared.dto.VariableDtoImpl).toJson()); + json.variables = listArray; + }); + } + if (this.fields) { + let listArray = []; + this.fields.forEach((item) => { + listArray.push((item as org.eclipse.che.api.debug.shared.dto.FieldDtoImpl).toJson()); + json.fields = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface ButtonAttributesDto { + setColor(arg0): void; + getColor(): string; + withColor(arg0): org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto; + getCounter(): boolean; + setCounter(arg0): void; + withCounter(arg0): org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto; + getLogo(): string; + setLogo(arg0): void; + withLogo(arg0): org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto; + getStyle(): string; + setStyle(arg0): void; + withStyle(arg0): org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class ButtonAttributesDtoImpl implements org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto { + + color : string; + logo : string; + style : string; + counter : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.color) { + this.color = __jsonObject.color; + } + } + if (__jsonObject) { + if (__jsonObject.logo) { + this.logo = __jsonObject.logo; + } + } + if (__jsonObject) { + if (__jsonObject.style) { + this.style = __jsonObject.style; + } + } + if (__jsonObject) { + if (__jsonObject.counter) { + this.counter = __jsonObject.counter; + } + } + + } + + setColor(color : string) : void { + this.color = color; + } + getColor() : string { + return this.color; + } + withColor(color : string) : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto { + this.color = color; + return this; + } + getCounter() : boolean { + return this.counter; + } + setCounter(counter : boolean) : void { + this.counter = counter; + } + withCounter(counter : boolean) : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto { + this.counter = counter; + return this; + } + getLogo() : string { + return this.logo; + } + setLogo(logo : string) : void { + this.logo = logo; + } + withLogo(logo : string) : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto { + this.logo = logo; + return this; + } + getStyle() : string { + return this.style; + } + setStyle(style : string) : void { + this.style = style; + } + withStyle(style : string) : org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto { + this.style = style; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.color) { + json.color = this.color; + } + if (this.logo) { + json.logo = this.logo; + } + if (this.style) { + json.style = this.style; + } + if (this.counter) { + json.counter = this.counter; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export interface DebuggerEventDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.event.DebuggerEventDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export class DebuggerEventDtoImpl implements org.eclipse.che.api.debug.shared.dto.event.DebuggerEventDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.event.DebuggerEventDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export interface NewRecipe { + setDescription(arg0): void; + withType(arg0): org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe; + setType(arg0): void; + withDescription(arg0): org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe; + setTags(arg0): void; + withName(arg0): org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe; + setScript(arg0): void; + withScript(arg0): org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe; + withTags(arg0): org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe; + setName(arg0): void; + getDescription(): string; + getTags(): Array; + getCreator(): string; + getName(): string; + getId(): string; + getType(): string; + getScript(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export class NewRecipeImpl implements org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe { + + creator : string; + name : string; + description : string; + id : string; + type : string; + script : string; + tags : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.creator) { + this.creator = __jsonObject.creator; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.script) { + this.script = __jsonObject.script; + } + } + this.tags = new Array(); + if (__jsonObject) { + if (__jsonObject.tags) { + __jsonObject.tags.forEach((item) => { + this.tags.push(item); + }); + } + } + + } + + setDescription(description : string) : void { + this.description = description; + } + withType(type : string) : org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withDescription(description : string) : org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe { + this.description = description; + return this; + } + setTags(tags : Array) : void { + this.tags = tags; + } + withName(name : string) : org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe { + this.name = name; + return this; + } + setScript(script : string) : void { + this.script = script; + } + withScript(script : string) : org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe { + this.script = script; + return this; + } + withTags(tags : Array) : org.eclipse.che.api.machine.shared.dto.recipe.NewRecipe { + this.tags = tags; + return this; + } + setName(name : string) : void { + this.name = name; + } + getDescription() : string { + return this.description; + } + getTags() : Array { + return this.tags; + } + getCreator() : string { + return this.creator; + } + getName() : string { + return this.name; + } + getId() : string { + return this.id; + } + getType() : string { + return this.type; + } + getScript() : string { + return this.script; + } + + toJson() : any { + let json : any = {}; + + if (this.creator) { + json.creator = this.creator; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.id) { + json.id = this.id; + } + if (this.type) { + json.type = this.type; + } + if (this.script) { + json.script = this.script; + } + if (this.tags) { + let listArray = []; + this.tags.forEach((item) => { + listArray.push(item); + json.tags = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface EnvironmentRecipeDto { + getContentType(): string; + setContentType(arg0): void; + withType(arg0): org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto; + setType(arg0): void; + setLocation(arg0): void; + setContent(arg0): void; + withContent(arg0): org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto; + withContentType(arg0): org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto; + withLocation(arg0): org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto; + getLocation(): string; + getType(): string; + getContent(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class EnvironmentRecipeDtoImpl implements org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto { + + location : string; + type : string; + contentType : string; + content : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.location) { + this.location = __jsonObject.location; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.contentType) { + this.contentType = __jsonObject.contentType; + } + } + if (__jsonObject) { + if (__jsonObject.content) { + this.content = __jsonObject.content; + } + } + + } + + getContentType() : string { + return this.contentType; + } + setContentType(contentType : string) : void { + this.contentType = contentType; + } + withType(type : string) : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setLocation(location : string) : void { + this.location = location; + } + setContent(content : string) : void { + this.content = content; + } + withContent(content : string) : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto { + this.content = content; + return this; + } + withContentType(contentType : string) : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto { + this.contentType = contentType; + return this; + } + withLocation(location : string) : org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto { + this.location = location; + return this; + } + getLocation() : string { + return this.location; + } + getType() : string { + return this.type; + } + getContent() : string { + return this.content; + } + + toJson() : any { + let json : any = {}; + + if (this.location) { + json.location = this.location; + } + if (this.type) { + json.type = this.type; + } + if (this.contentType) { + json.contentType = this.contentType; + } + if (this.content) { + json.content = this.content; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface MachineRuntimeInfoDto { + getServers(): Map; + withProperties(arg0): org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto; + withServers(arg0): org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto; + withEnvVariables(arg0): org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto; + getEnvVariables(): Map; + getProperties(): Map; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class MachineRuntimeInfoDtoImpl implements org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto { + + servers : Map; + envVariables : Map; + properties : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.servers = new Map(); + if (__jsonObject) { + if (__jsonObject.servers) { + let tmp : Array = Object.keys(__jsonObject.servers); + tmp.forEach((key) => { + this.servers.set(key, new org.eclipse.che.api.machine.shared.dto.ServerDtoImpl(__jsonObject.servers[key])); + }); + } + } + this.envVariables = new Map(); + if (__jsonObject) { + if (__jsonObject.envVariables) { + let tmp : Array = Object.keys(__jsonObject.envVariables); + tmp.forEach((key) => { + this.envVariables.set(key, __jsonObject.envVariables[key]); + }); + } + } + this.properties = new Map(); + if (__jsonObject) { + if (__jsonObject.properties) { + let tmp : Array = Object.keys(__jsonObject.properties); + tmp.forEach((key) => { + this.properties.set(key, __jsonObject.properties[key]); + }); + } + } + + } + + getServers() : Map { + return this.servers; + } + withProperties(properties : Map) : org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto { + this.properties = properties; + return this; + } + withServers(servers : Map) : org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto { + this.servers = servers; + return this; + } + withEnvVariables(envVariables : Map) : org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto { + this.envVariables = envVariables; + return this; + } + getEnvVariables() : Map { + return this.envVariables; + } + getProperties() : Map { + return this.properties; + } + + toJson() : any { + let json : any = {}; + + if (this.servers) { + let tmpMap : any = {}; + for (const [key, value] of this.servers.entries()) { + tmpMap[key] = (value as org.eclipse.che.api.machine.shared.dto.ServerDtoImpl).toJson(); + } + json.servers = tmpMap; + } + if (this.envVariables) { + let tmpMap : any = {}; + for (const [key, value] of this.envVariables.entries()) { + tmpMap[key] = value; + } + json.envVariables = tmpMap; + } + if (this.properties) { + let tmpMap : any = {}; + for (const [key, value] of this.properties.entries()) { + tmpMap[key] = value; + } + json.properties = tmpMap; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface MachineLogMessageDto { + setContent(arg0): void; + withContent(arg0): org.eclipse.che.api.machine.shared.dto.MachineLogMessageDto; + withMachineName(arg0): org.eclipse.che.api.machine.shared.dto.MachineLogMessageDto; + setMachineName(arg0): void; + getMachineName(): string; + getContent(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class MachineLogMessageDtoImpl implements org.eclipse.che.api.machine.shared.dto.MachineLogMessageDto { + + content : string; + machineName : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.content) { + this.content = __jsonObject.content; + } + } + if (__jsonObject) { + if (__jsonObject.machineName) { + this.machineName = __jsonObject.machineName; + } + } + + } + + setContent(content : string) : void { + this.content = content; + } + withContent(content : string) : org.eclipse.che.api.machine.shared.dto.MachineLogMessageDto { + this.content = content; + return this; + } + withMachineName(machineName : string) : org.eclipse.che.api.machine.shared.dto.MachineLogMessageDto { + this.machineName = machineName; + return this; + } + setMachineName(machineName : string) : void { + this.machineName = machineName; + } + getMachineName() : string { + return this.machineName; + } + getContent() : string { + return this.content; + } + + toJson() : any { + let json : any = {}; + + if (this.content) { + json.content = this.content; + } + if (this.machineName) { + json.machineName = this.machineName; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface LogResponse { + getTextLog(): string; + getCommits(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class LogResponseImpl implements org.eclipse.che.api.git.shared.LogResponse { + + commits : Array; + textLog : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.commits = new Array(); + if (__jsonObject) { + if (__jsonObject.commits) { + __jsonObject.commits.forEach((item) => { + this.commits.push(new org.eclipse.che.api.git.shared.RevisionImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.textLog) { + this.textLog = __jsonObject.textLog; + } + } + + } + + getTextLog() : string { + return this.textLog; + } + getCommits() : Array { + return this.commits; + } + + toJson() : any { + let json : any = {}; + + if (this.commits) { + let listArray = []; + this.commits.forEach((item) => { + listArray.push((item as org.eclipse.che.api.git.shared.RevisionImpl).toJson()); + json.commits = listArray; + }); + } + if (this.textLog) { + json.textLog = this.textLog; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export interface ResumeActionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.action.ResumeActionDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export class ResumeActionDtoImpl implements org.eclipse.che.api.debug.shared.dto.action.ResumeActionDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.action.ResumeActionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.ssh.shared.dto { + + export interface GenerateSshPairRequest { + getService(): string; + withName(arg0): org.eclipse.che.api.ssh.shared.dto.GenerateSshPairRequest; + setService(arg0): void; + withService(arg0): org.eclipse.che.api.ssh.shared.dto.GenerateSshPairRequest; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.ssh.shared.dto { + + export class GenerateSshPairRequestImpl implements org.eclipse.che.api.ssh.shared.dto.GenerateSshPairRequest { + + service : string; + name : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.service) { + this.service = __jsonObject.service; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + + } + + getService() : string { + return this.service; + } + withName(name : string) : org.eclipse.che.api.ssh.shared.dto.GenerateSshPairRequest { + this.name = name; + return this; + } + setService(service : string) : void { + this.service = service; + } + withService(service : string) : org.eclipse.che.api.ssh.shared.dto.GenerateSshPairRequest { + this.service = service; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.service) { + json.service = this.service; + } + if (this.name) { + json.name = this.name; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface WorkspaceDto { + setId(arg0): void; + getConfig(): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + setStatus(arg0): void; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + withLinks(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + withStatus(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + withId(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + withConfig(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + withRuntime(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + setNamespace(arg0): void; + withNamespace(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + setRuntime(arg0): void; + setTemporary(arg0): void; + withTemporary(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + setConfig(arg0): void; + getRuntime(): org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; + getNamespace(): string; + getStatus(): string; + isTemporary(): boolean; + getId(): string; + getAttributes(): Map; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class WorkspaceDtoImpl implements org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + + temporary : boolean; + namespace : string; + runtime : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; + attributes : Map; + links : Array; + id : string; + config : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + status : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.temporary) { + this.temporary = __jsonObject.temporary; + } + } + if (__jsonObject) { + if (__jsonObject.namespace) { + this.namespace = __jsonObject.namespace; + } + } + if (__jsonObject) { + if (__jsonObject.runtime) { + this.runtime = new org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDtoImpl(__jsonObject.runtime); + } + } + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.config) { + this.config = new org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDtoImpl(__jsonObject.config); + } + } + if (__jsonObject) { + if (__jsonObject.status) { + this.status = __jsonObject.status; + } + } + + } + + setId(id : string) : void { + this.id = id; + } + getConfig() : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + return this.config; + } + setStatus(status : string) : void { + this.status = status; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.attributes = attributes; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.links = links; + return this; + } + withStatus(status : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.status = status; + return this; + } + withId(id : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.id = id; + return this; + } + withConfig(config : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.config = config; + return this; + } + withRuntime(runtime : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.runtime = runtime; + return this; + } + setNamespace(namespace : string) : void { + this.namespace = namespace; + } + withNamespace(namespace : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.namespace = namespace; + return this; + } + setRuntime(runtime : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto) : void { + this.runtime = runtime; + } + setTemporary(temporary : boolean) : void { + this.temporary = temporary; + } + withTemporary(temporary : boolean) : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto { + this.temporary = temporary; + return this; + } + setConfig(config : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto) : void { + this.config = config; + } + getRuntime() : org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto { + return this.runtime; + } + getNamespace() : string { + return this.namespace; + } + getStatus() : string { + return this.status; + } + isTemporary() : boolean { + return this.temporary; + } + getId() : string { + return this.id; + } + getAttributes() : Map { + return this.attributes; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.temporary) { + json.temporary = this.temporary; + } + if (this.namespace) { + json.namespace = this.namespace; + } + if (this.runtime) { + json.runtime = (this.runtime as org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDtoImpl).toJson(); + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.id) { + json.id = this.id; + } + if (this.config) { + json.config = (this.config as org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDtoImpl).toJson(); + } + if (this.status) { + json.status = this.status; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export interface RecipeDescriptor { + setDescription(arg0): void; + withType(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; + setType(arg0): void; + withDescription(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; + setId(arg0): void; + setTags(arg0): void; + withName(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; + withId(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; + setScript(arg0): void; + withScript(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; + setCreator(arg0): void; + withCreator(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; + withTags(arg0): org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; + setName(arg0): void; + getLinks(): Array; + setLinks(arg0): void; + withLinks(arg0): org.eclipse.che.api.core.rest.shared.dto.Hyperlinks; + getDescription(): string; + getTags(): Array; + getCreator(): string; + getName(): string; + getId(): string; + getType(): string; + getScript(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export class RecipeDescriptorImpl implements org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + + creator : string; + name : string; + description : string; + links : Array; + id : string; + type : string; + script : string; + tags : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.creator) { + this.creator = __jsonObject.creator; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.script) { + this.script = __jsonObject.script; + } + } + this.tags = new Array(); + if (__jsonObject) { + if (__jsonObject.tags) { + __jsonObject.tags.forEach((item) => { + this.tags.push(item); + }); + } + } + + } + + setDescription(description : string) : void { + this.description = description; + } + withType(type : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withDescription(description : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + this.description = description; + return this; + } + setId(id : string) : void { + this.id = id; + } + setTags(tags : Array) : void { + this.tags = tags; + } + withName(name : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + this.name = name; + return this; + } + withId(id : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + this.id = id; + return this; + } + setScript(script : string) : void { + this.script = script; + } + withScript(script : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + this.script = script; + return this; + } + setCreator(creator : string) : void { + this.creator = creator; + } + withCreator(creator : string) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + this.creator = creator; + return this; + } + withTags(tags : Array) : org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor { + this.tags = tags; + return this; + } + setName(name : string) : void { + this.name = name; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + withLinks(links : Array) : org.eclipse.che.api.core.rest.shared.dto.Hyperlinks { + this.links = links; + return this; + } + getDescription() : string { + return this.description; + } + getTags() : Array { + return this.tags; + } + getCreator() : string { + return this.creator; + } + getName() : string { + return this.name; + } + getId() : string { + return this.id; + } + getType() : string { + return this.type; + } + getScript() : string { + return this.script; + } + + toJson() : any { + let json : any = {}; + + if (this.creator) { + json.creator = this.creator; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.id) { + json.id = this.id; + } + if (this.type) { + json.type = this.type; + } + if (this.script) { + json.script = this.script; + } + if (this.tags) { + let listArray = []; + this.tags.forEach((item) => { + listArray.push(item); + json.tags = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface ApiInfo { + getSpecificationTitle(): string; + getSpecificationVersion(): string; + getSpecificationVendor(): string; + getImplementationVersion(): string; + getImplementationVendor(): string; + getScmRevision(): string; + setScmRevision(arg0): void; + withScmRevision(arg0): org.eclipse.che.api.core.rest.shared.dto.ApiInfo; + withSpecificationVendor(arg0): org.eclipse.che.api.core.rest.shared.dto.ApiInfo; + setSpecificationVendor(arg0): void; + withImplementationVendor(arg0): org.eclipse.che.api.core.rest.shared.dto.ApiInfo; + setImplementationVendor(arg0): void; + withSpecificationTitle(arg0): org.eclipse.che.api.core.rest.shared.dto.ApiInfo; + setSpecificationTitle(arg0): void; + withSpecificationVersion(arg0): org.eclipse.che.api.core.rest.shared.dto.ApiInfo; + setSpecificationVersion(arg0): void; + withImplementationVersion(arg0): org.eclipse.che.api.core.rest.shared.dto.ApiInfo; + setImplementationVersion(arg0): void; + getIdeVersion(): string; + withIdeVersion(arg0): org.eclipse.che.api.core.rest.shared.dto.ApiInfo; + setIdeVersion(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class ApiInfoImpl implements org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + + specificationVendor : string; + ideVersion : string; + specificationTitle : string; + implementationVersion : string; + implementationVendor : string; + scmRevision : string; + specificationVersion : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.specificationVendor) { + this.specificationVendor = __jsonObject.specificationVendor; + } + } + if (__jsonObject) { + if (__jsonObject.ideVersion) { + this.ideVersion = __jsonObject.ideVersion; + } + } + if (__jsonObject) { + if (__jsonObject.specificationTitle) { + this.specificationTitle = __jsonObject.specificationTitle; + } + } + if (__jsonObject) { + if (__jsonObject.implementationVersion) { + this.implementationVersion = __jsonObject.implementationVersion; + } + } + if (__jsonObject) { + if (__jsonObject.implementationVendor) { + this.implementationVendor = __jsonObject.implementationVendor; + } + } + if (__jsonObject) { + if (__jsonObject.scmRevision) { + this.scmRevision = __jsonObject.scmRevision; + } + } + if (__jsonObject) { + if (__jsonObject.specificationVersion) { + this.specificationVersion = __jsonObject.specificationVersion; + } + } + + } + + getSpecificationTitle() : string { + return this.specificationTitle; + } + getSpecificationVersion() : string { + return this.specificationVersion; + } + getSpecificationVendor() : string { + return this.specificationVendor; + } + getImplementationVersion() : string { + return this.implementationVersion; + } + getImplementationVendor() : string { + return this.implementationVendor; + } + getScmRevision() : string { + return this.scmRevision; + } + setScmRevision(scmRevision : string) : void { + this.scmRevision = scmRevision; + } + withScmRevision(scmRevision : string) : org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + this.scmRevision = scmRevision; + return this; + } + withSpecificationVendor(specificationVendor : string) : org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + this.specificationVendor = specificationVendor; + return this; + } + setSpecificationVendor(specificationVendor : string) : void { + this.specificationVendor = specificationVendor; + } + withImplementationVendor(implementationVendor : string) : org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + this.implementationVendor = implementationVendor; + return this; + } + setImplementationVendor(implementationVendor : string) : void { + this.implementationVendor = implementationVendor; + } + withSpecificationTitle(specificationTitle : string) : org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + this.specificationTitle = specificationTitle; + return this; + } + setSpecificationTitle(specificationTitle : string) : void { + this.specificationTitle = specificationTitle; + } + withSpecificationVersion(specificationVersion : string) : org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + this.specificationVersion = specificationVersion; + return this; + } + setSpecificationVersion(specificationVersion : string) : void { + this.specificationVersion = specificationVersion; + } + withImplementationVersion(implementationVersion : string) : org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + this.implementationVersion = implementationVersion; + return this; + } + setImplementationVersion(implementationVersion : string) : void { + this.implementationVersion = implementationVersion; + } + getIdeVersion() : string { + return this.ideVersion; + } + withIdeVersion(ideVersion : string) : org.eclipse.che.api.core.rest.shared.dto.ApiInfo { + this.ideVersion = ideVersion; + return this; + } + setIdeVersion(ideVersion : string) : void { + this.ideVersion = ideVersion; + } + + toJson() : any { + let json : any = {}; + + if (this.specificationVendor) { + json.specificationVendor = this.specificationVendor; + } + if (this.ideVersion) { + json.ideVersion = this.ideVersion; + } + if (this.specificationTitle) { + json.specificationTitle = this.specificationTitle; + } + if (this.implementationVersion) { + json.implementationVersion = this.implementationVersion; + } + if (this.implementationVendor) { + json.implementationVendor = this.implementationVendor; + } + if (this.scmRevision) { + json.scmRevision = this.scmRevision; + } + if (this.specificationVersion) { + json.specificationVersion = this.specificationVersion; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface WsAgentHealthStateDto { + getReason(): string; + getCode(): number; + setCode(arg0): void; + withCode(arg0): org.eclipse.che.api.workspace.shared.dto.WsAgentHealthStateDto; + withWorkspaceStatus(arg0): org.eclipse.che.api.workspace.shared.dto.WsAgentHealthStateDto; + getWorkspaceStatus(): string; + setReason(arg0): void; + withReason(arg0): org.eclipse.che.api.workspace.shared.dto.WsAgentHealthStateDto; + setWorkspaceStatus(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class WsAgentHealthStateDtoImpl implements org.eclipse.che.api.workspace.shared.dto.WsAgentHealthStateDto { + + reason : string; + code : number; + workspaceStatus : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.reason) { + this.reason = __jsonObject.reason; + } + } + if (__jsonObject) { + if (__jsonObject.code) { + this.code = __jsonObject.code; + } + } + if (__jsonObject) { + if (__jsonObject.workspaceStatus) { + this.workspaceStatus = __jsonObject.workspaceStatus; + } + } + + } + + getReason() : string { + return this.reason; + } + getCode() : number { + return this.code; + } + setCode(code : number) : void { + this.code = code; + } + withCode(code : number) : org.eclipse.che.api.workspace.shared.dto.WsAgentHealthStateDto { + this.code = code; + return this; + } + withWorkspaceStatus(workspaceStatus : string) : org.eclipse.che.api.workspace.shared.dto.WsAgentHealthStateDto { + this.workspaceStatus = workspaceStatus; + return this; + } + getWorkspaceStatus() : string { + return this.workspaceStatus; + } + setReason(reason : string) : void { + this.reason = reason; + } + withReason(reason : string) : org.eclipse.che.api.workspace.shared.dto.WsAgentHealthStateDto { + this.reason = reason; + return this; + } + setWorkspaceStatus(workspaceStatus : string) : void { + this.workspaceStatus = workspaceStatus; + } + + toJson() : any { + let json : any = {}; + + if (this.reason) { + json.reason = this.reason; + } + if (this.code) { + json.code = this.code; + } + if (this.workspaceStatus) { + json.workspaceStatus = this.workspaceStatus; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export interface SuspendActionDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.action.SuspendActionDto; + setType(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.action { + + export class SuspendActionDtoImpl implements org.eclipse.che.api.debug.shared.dto.action.SuspendActionDto { + + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.action.SuspendActionDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export interface VfsWatchEvent { + withType(arg0): org.eclipse.che.api.project.shared.dto.event.VfsWatchEvent; + withPath(arg0): org.eclipse.che.api.project.shared.dto.event.VfsWatchEvent; + withFile(arg0): org.eclipse.che.api.project.shared.dto.event.VfsWatchEvent; + getType(): string; + getPath(): string; + isFile(): boolean; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export class VfsWatchEventImpl implements org.eclipse.che.api.project.shared.dto.event.VfsWatchEvent { + + path : string; + file : boolean; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.file) { + this.file = __jsonObject.file; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.project.shared.dto.event.VfsWatchEvent { + this.type = type; + return this; + } + withPath(path : string) : org.eclipse.che.api.project.shared.dto.event.VfsWatchEvent { + this.path = path; + return this; + } + withFile(file : boolean) : org.eclipse.che.api.project.shared.dto.event.VfsWatchEvent { + this.file = file; + return this; + } + getType() : string { + return this.type; + } + getPath() : string { + return this.path; + } + isFile() : boolean { + return this.file; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.file) { + json.file = this.file; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.templates.shared.dto { + + export interface ProjectTemplateDescriptor { + getProblems(): Array; + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + getSource(): org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; + withSource(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + setSource(arg0): void; + setProblems(arg0): void; + setPath(arg0): void; + getTags(): Array; + setTags(arg0): void; + withName(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + getLinks(): Array; + setLinks(arg0): void; + withLinks(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + withPath(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + withDisplayName(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + getProjectType(): string; + setProjectType(arg0): void; + withProjectType(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + getMixins(): Array; + setMixins(arg0): void; + withMixins(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + withProblems(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + setDisplayName(arg0): void; + getCategory(): string; + setCategory(arg0): void; + withCategory(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + getCommands(): Array; + setCommands(arg0): void; + withCommands(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + withTags(arg0): org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; + getName(): string; + setName(arg0): void; + getPath(): string; + getAttributes(): Map>; + getDisplayName(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.templates.shared.dto { + + export class ProjectTemplateDescriptorImpl implements org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + + displayName : string; + projectType : string; + description : string; + source : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; + tags : Array; + path : string; + mixins : Array; + name : string; + attributes : Map>; + links : Array; + category : string; + commands : Array; + problems : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.displayName) { + this.displayName = __jsonObject.displayName; + } + } + if (__jsonObject) { + if (__jsonObject.projectType) { + this.projectType = __jsonObject.projectType; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + if (__jsonObject) { + if (__jsonObject.source) { + this.source = new org.eclipse.che.api.workspace.shared.dto.SourceStorageDtoImpl(__jsonObject.source); + } + } + this.tags = new Array(); + if (__jsonObject) { + if (__jsonObject.tags) { + __jsonObject.tags.forEach((item) => { + this.tags.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + this.mixins = new Array(); + if (__jsonObject) { + if (__jsonObject.mixins) { + __jsonObject.mixins.forEach((item) => { + this.mixins.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + this.attributes = new Map>(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.category) { + this.category = __jsonObject.category; + } + } + this.commands = new Array(); + if (__jsonObject) { + if (__jsonObject.commands) { + __jsonObject.commands.forEach((item) => { + this.commands.push(new org.eclipse.che.api.machine.shared.dto.CommandDtoImpl(item)); + }); + } + } + this.problems = new Array(); + if (__jsonObject) { + if (__jsonObject.problems) { + __jsonObject.problems.forEach((item) => { + this.problems.push(new org.eclipse.che.api.workspace.shared.dto.ProjectProblemDtoImpl(item)); + }); + } + } + + } + + getProblems() : Array { + return this.problems; + } + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.description = description; + return this; + } + getSource() : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto { + return this.source; + } + withSource(source : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.source = source; + return this; + } + setSource(source : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto) : void { + this.source = source; + } + setProblems(problems : Array) : void { + this.problems = problems; + } + setPath(path : string) : void { + this.path = path; + } + getTags() : Array { + return this.tags; + } + setTags(tags : Array) : void { + this.tags = tags; + } + withName(name : string) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.name = name; + return this; + } + setAttributes(attributes : Map>) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map>) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.attributes = attributes; + return this; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + withLinks(links : Array) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.links = links; + return this; + } + withPath(path : string) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.path = path; + return this; + } + withDisplayName(displayName : string) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.displayName = displayName; + return this; + } + getProjectType() : string { + return this.projectType; + } + setProjectType(projectType : string) : void { + this.projectType = projectType; + } + withProjectType(projectType : string) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.projectType = projectType; + return this; + } + getMixins() : Array { + return this.mixins; + } + setMixins(mixins : Array) : void { + this.mixins = mixins; + } + withMixins(mixins : Array) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.mixins = mixins; + return this; + } + withProblems(problems : Array) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.problems = problems; + return this; + } + setDisplayName(displayName : string) : void { + this.displayName = displayName; + } + getCategory() : string { + return this.category; + } + setCategory(category : string) : void { + this.category = category; + } + withCategory(category : string) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.category = category; + return this; + } + getCommands() : Array { + return this.commands; + } + setCommands(commands : Array) : void { + this.commands = commands; + } + withCommands(commands : Array) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.commands = commands; + return this; + } + withTags(tags : Array) : org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor { + this.tags = tags; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getPath() : string { + return this.path; + } + getAttributes() : Map> { + return this.attributes; + } + getDisplayName() : string { + return this.displayName; + } + + toJson() : any { + let json : any = {}; + + if (this.displayName) { + json.displayName = this.displayName; + } + if (this.projectType) { + json.projectType = this.projectType; + } + if (this.description) { + json.description = this.description; + } + if (this.source) { + json.source = (this.source as org.eclipse.che.api.workspace.shared.dto.SourceStorageDtoImpl).toJson(); + } + if (this.tags) { + let listArray = []; + this.tags.forEach((item) => { + listArray.push(item); + json.tags = listArray; + }); + } + if (this.path) { + json.path = this.path; + } + if (this.mixins) { + let listArray = []; + this.mixins.forEach((item) => { + listArray.push(item); + json.mixins = listArray; + }); + } + if (this.name) { + json.name = this.name; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.category) { + json.category = this.category; + } + if (this.commands) { + let listArray = []; + this.commands.forEach((item) => { + listArray.push((item as org.eclipse.che.api.machine.shared.dto.CommandDtoImpl).toJson()); + json.commands = listArray; + }); + } + if (this.problems) { + let listArray = []; + this.problems.forEach((item) => { + listArray.push((item as org.eclipse.che.api.workspace.shared.dto.ProjectProblemDtoImpl).toJson()); + json.problems = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export interface VfsFileStatusUpdateDto { + withType(arg0): org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto; + withHashCode(arg0): org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto; + withPath(arg0): org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto; + getType(): string; + getPath(): string; + getHashCode(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export class VfsFileStatusUpdateDtoImpl implements org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto { + + path : string; + hashCode : string; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.hashCode) { + this.hashCode = __jsonObject.hashCode; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto { + this.type = type; + return this; + } + withHashCode(hashCode : string) : org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto { + this.hashCode = hashCode; + return this; + } + withPath(path : string) : org.eclipse.che.api.project.shared.dto.event.VfsFileStatusUpdateDto { + this.path = path; + return this; + } + getType() : string { + return this.type; + } + getPath() : string { + return this.path; + } + getHashCode() : string { + return this.hashCode; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.hashCode) { + json.hashCode = this.hashCode; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export interface BreakpointActivatedEventDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.event.BreakpointActivatedEventDto; + setType(arg0): void; + getBreakpoint(): org.eclipse.che.api.debug.shared.dto.BreakpointDto; + setBreakpoint(arg0): void; + withBreakpoint(arg0): org.eclipse.che.api.debug.shared.dto.event.BreakpointActivatedEventDto; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto.event { + + export class BreakpointActivatedEventDtoImpl implements org.eclipse.che.api.debug.shared.dto.event.BreakpointActivatedEventDto { + + type : string; + breakpoint : org.eclipse.che.api.debug.shared.dto.BreakpointDto; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.breakpoint) { + this.breakpoint = new org.eclipse.che.api.debug.shared.dto.BreakpointDtoImpl(__jsonObject.breakpoint); + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.event.BreakpointActivatedEventDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + getBreakpoint() : org.eclipse.che.api.debug.shared.dto.BreakpointDto { + return this.breakpoint; + } + setBreakpoint(breakpoint : org.eclipse.che.api.debug.shared.dto.BreakpointDto) : void { + this.breakpoint = breakpoint; + } + withBreakpoint(breakpoint : org.eclipse.che.api.debug.shared.dto.BreakpointDto) : org.eclipse.che.api.debug.shared.dto.event.BreakpointActivatedEventDto { + this.breakpoint = breakpoint; + return this; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + if (this.breakpoint) { + json.breakpoint = (this.breakpoint as org.eclipse.che.api.debug.shared.dto.BreakpointDtoImpl).toJson(); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.agent.shared.dto { + + export interface AgentKeyDto { + getVersion(): string; + setVersion(arg0): void; + withName(arg0): org.eclipse.che.api.agent.shared.dto.AgentKeyDto; + withVersion(arg0): org.eclipse.che.api.agent.shared.dto.AgentKeyDto; + getName(): string; + setName(arg0): void; + getId(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.agent.shared.dto { + + export class AgentKeyDtoImpl implements org.eclipse.che.api.agent.shared.dto.AgentKeyDto { + + name : string; + id : string; + version : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.version) { + this.version = __jsonObject.version; + } + } + + } + + getVersion() : string { + return this.version; + } + setVersion(version : string) : void { + this.version = version; + } + withName(name : string) : org.eclipse.che.api.agent.shared.dto.AgentKeyDto { + this.name = name; + return this; + } + withVersion(version : string) : org.eclipse.che.api.agent.shared.dto.AgentKeyDto { + this.version = version; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getId() : string { + return this.id; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.id) { + json.id = this.id; + } + if (this.version) { + json.version = this.version; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export interface FileTrackingOperationDto { + withType(arg0): org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto; + getOldPath(): string; + withPath(arg0): org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto; + withOldPath(arg0): org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto; + getType(): string; + getPath(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export class FileTrackingOperationDtoImpl implements org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto { + + path : string; + oldPath : string; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.oldPath) { + this.oldPath = __jsonObject.oldPath; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto { + this.type = type; + return this; + } + getOldPath() : string { + return this.oldPath; + } + withPath(path : string) : org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto { + this.path = path; + return this; + } + withOldPath(oldPath : string) : org.eclipse.che.api.project.shared.dto.event.FileTrackingOperationDto { + this.oldPath = oldPath; + return this; + } + getType() : string { + return this.type; + } + getPath() : string { + return this.path; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.oldPath) { + json.oldPath = this.oldPath; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface RmRequest { + getItems(): Array; + setItems(arg0): void; + setCached(arg0): void; + withCached(arg0): org.eclipse.che.api.git.shared.RmRequest; + withItems(arg0): org.eclipse.che.api.git.shared.RmRequest; + isCached(): boolean; + isRecursively(): boolean; + setRecursively(arg0): void; + withRecursively(arg0): org.eclipse.che.api.git.shared.RmRequest; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RmRequestImpl implements org.eclipse.che.api.git.shared.RmRequest { + + cached : boolean; + recursively : boolean; + items : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.cached) { + this.cached = __jsonObject.cached; + } + } + if (__jsonObject) { + if (__jsonObject.recursively) { + this.recursively = __jsonObject.recursively; + } + } + this.items = new Array(); + if (__jsonObject) { + if (__jsonObject.items) { + __jsonObject.items.forEach((item) => { + this.items.push(item); + }); + } + } + + } + + getItems() : Array { + return this.items; + } + setItems(items : Array) : void { + this.items = items; + } + setCached(cached : boolean) : void { + this.cached = cached; + } + withCached(cached : boolean) : org.eclipse.che.api.git.shared.RmRequest { + this.cached = cached; + return this; + } + withItems(items : Array) : org.eclipse.che.api.git.shared.RmRequest { + this.items = items; + return this; + } + isCached() : boolean { + return this.cached; + } + isRecursively() : boolean { + return this.recursively; + } + setRecursively(recursively : boolean) : void { + this.recursively = recursively; + } + withRecursively(recursively : boolean) : org.eclipse.che.api.git.shared.RmRequest { + this.recursively = recursively; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.cached) { + json.cached = this.cached; + } + if (this.recursively) { + json.recursively = this.recursively; + } + if (this.items) { + let listArray = []; + this.items.forEach((item) => { + listArray.push(item); + json.items = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface OnProjectsLoadedDto { + setActions(arg0): void; + withActions(arg0): org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto; + getActions(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class OnProjectsLoadedDtoImpl implements org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto { + + actions : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.actions = new Array(); + if (__jsonObject) { + if (__jsonObject.actions) { + __jsonObject.actions.forEach((item) => { + this.actions.push(new org.eclipse.che.api.factory.shared.dto.IdeActionDtoImpl(item)); + }); + } + } + + } + + setActions(actions : Array) : void { + this.actions = actions; + } + withActions(actions : Array) : org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto { + this.actions = actions; + return this; + } + getActions() : Array { + return this.actions; + } + + toJson() : any { + let json : any = {}; + + if (this.actions) { + let listArray = []; + this.actions.forEach((item) => { + listArray.push((item as org.eclipse.che.api.factory.shared.dto.IdeActionDtoImpl).toJson()); + json.actions = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface Commiters { + getCommiters(): Array; + withCommiters(arg0): org.eclipse.che.api.git.shared.Commiters; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class CommitersImpl implements org.eclipse.che.api.git.shared.Commiters { + + commiters : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.commiters = new Array(); + if (__jsonObject) { + if (__jsonObject.commiters) { + __jsonObject.commiters.forEach((item) => { + this.commiters.push(new org.eclipse.che.api.git.shared.GitUserImpl(item)); + }); + } + } + + } + + getCommiters() : Array { + return this.commiters; + } + withCommiters(commiters : Array) : org.eclipse.che.api.git.shared.Commiters { + this.commiters = commiters; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.commiters) { + let listArray = []; + this.commiters.forEach((item) => { + listArray.push((item as org.eclipse.che.api.git.shared.GitUserImpl).toJson()); + json.commiters = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface BranchCreateRequest { + withName(arg0): org.eclipse.che.api.git.shared.BranchCreateRequest; + getStartPoint(): string; + setStartPoint(arg0): void; + withStartPoint(arg0): org.eclipse.che.api.git.shared.BranchCreateRequest; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class BranchCreateRequestImpl implements org.eclipse.che.api.git.shared.BranchCreateRequest { + + name : string; + startPoint : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.startPoint) { + this.startPoint = __jsonObject.startPoint; + } + } + + } + + withName(name : string) : org.eclipse.che.api.git.shared.BranchCreateRequest { + this.name = name; + return this; + } + getStartPoint() : string { + return this.startPoint; + } + setStartPoint(startPoint : string) : void { + this.startPoint = startPoint; + } + withStartPoint(startPoint : string) : org.eclipse.che.api.git.shared.BranchCreateRequest { + this.startPoint = startPoint; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.startPoint) { + json.startPoint = this.startPoint; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface Link { + setParameters(arg0): void; + setMethod(arg0): void; + getHref(): string; + setRequestBody(arg0): void; + withMethod(arg0): org.eclipse.che.api.core.rest.shared.dto.Link; + withParameters(arg0): org.eclipse.che.api.core.rest.shared.dto.Link; + setHref(arg0): void; + withHref(arg0): org.eclipse.che.api.core.rest.shared.dto.Link; + withRequestBody(arg0): org.eclipse.che.api.core.rest.shared.dto.Link; + withRel(arg0): org.eclipse.che.api.core.rest.shared.dto.Link; + setRel(arg0): void; + getProduces(): string; + withProduces(arg0): org.eclipse.che.api.core.rest.shared.dto.Link; + setProduces(arg0): void; + getConsumes(): string; + withConsumes(arg0): org.eclipse.che.api.core.rest.shared.dto.Link; + setConsumes(arg0): void; + getRequestBody(): org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor; + getRel(): string; + getMethod(): string; + getParameters(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class LinkImpl implements org.eclipse.che.api.core.rest.shared.dto.Link { + + method : string; + requestBody : org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor; + rel : string; + produces : string; + href : string; + parameters : Array; + consumes : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.method) { + this.method = __jsonObject.method; + } + } + if (__jsonObject) { + if (__jsonObject.requestBody) { + this.requestBody = new org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptorImpl(__jsonObject.requestBody); + } + } + if (__jsonObject) { + if (__jsonObject.rel) { + this.rel = __jsonObject.rel; + } + } + if (__jsonObject) { + if (__jsonObject.produces) { + this.produces = __jsonObject.produces; + } + } + if (__jsonObject) { + if (__jsonObject.href) { + this.href = __jsonObject.href; + } + } + this.parameters = new Array(); + if (__jsonObject) { + if (__jsonObject.parameters) { + __jsonObject.parameters.forEach((item) => { + this.parameters.push(new org.eclipse.che.api.core.rest.shared.dto.LinkParameterImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.consumes) { + this.consumes = __jsonObject.consumes; + } + } + + } + + setParameters(parameters : Array) : void { + this.parameters = parameters; + } + setMethod(method : string) : void { + this.method = method; + } + getHref() : string { + return this.href; + } + setRequestBody(requestBody : org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor) : void { + this.requestBody = requestBody; + } + withMethod(method : string) : org.eclipse.che.api.core.rest.shared.dto.Link { + this.method = method; + return this; + } + withParameters(parameters : Array) : org.eclipse.che.api.core.rest.shared.dto.Link { + this.parameters = parameters; + return this; + } + setHref(href : string) : void { + this.href = href; + } + withHref(href : string) : org.eclipse.che.api.core.rest.shared.dto.Link { + this.href = href; + return this; + } + withRequestBody(requestBody : org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor) : org.eclipse.che.api.core.rest.shared.dto.Link { + this.requestBody = requestBody; + return this; + } + withRel(rel : string) : org.eclipse.che.api.core.rest.shared.dto.Link { + this.rel = rel; + return this; + } + setRel(rel : string) : void { + this.rel = rel; + } + getProduces() : string { + return this.produces; + } + withProduces(produces : string) : org.eclipse.che.api.core.rest.shared.dto.Link { + this.produces = produces; + return this; + } + setProduces(produces : string) : void { + this.produces = produces; + } + getConsumes() : string { + return this.consumes; + } + withConsumes(consumes : string) : org.eclipse.che.api.core.rest.shared.dto.Link { + this.consumes = consumes; + return this; + } + setConsumes(consumes : string) : void { + this.consumes = consumes; + } + getRequestBody() : org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptor { + return this.requestBody; + } + getRel() : string { + return this.rel; + } + getMethod() : string { + return this.method; + } + getParameters() : Array { + return this.parameters; + } + + toJson() : any { + let json : any = {}; + + if (this.method) { + json.method = this.method; + } + if (this.requestBody) { + json.requestBody = (this.requestBody as org.eclipse.che.api.core.rest.shared.dto.RequestBodyDescriptorImpl).toJson(); + } + if (this.rel) { + json.rel = this.rel; + } + if (this.produces) { + json.produces = this.produces; + } + if (this.href) { + json.href = this.href; + } + if (this.parameters) { + let listArray = []; + this.parameters.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkParameterImpl).toJson()); + json.parameters = listArray; + }); + } + if (this.consumes) { + json.consumes = this.consumes; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface ExtendedError { + getErrorCode(): number; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.core.rest.shared.dto.ExtendedError; + withMessage(arg0): org.eclipse.che.api.core.rest.shared.dto.ExtendedError; + withErrorCode(arg0): org.eclipse.che.api.core.rest.shared.dto.ExtendedError; + setErrorCode(arg0): void; + getAttributes(): Map; + setMessage(arg0): void; + getMessage(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class ExtendedErrorImpl implements org.eclipse.che.api.core.rest.shared.dto.ExtendedError { + + errorCode : number; + attributes : Map; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.errorCode) { + this.errorCode = __jsonObject.errorCode; + } + } + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + getErrorCode() : number { + return this.errorCode; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.core.rest.shared.dto.ExtendedError { + this.attributes = attributes; + return this; + } + withMessage(message : string) : org.eclipse.che.api.core.rest.shared.dto.ExtendedError { + this.message = message; + return this; + } + withErrorCode(errorCode : number) : org.eclipse.che.api.core.rest.shared.dto.ExtendedError { + this.errorCode = errorCode; + return this; + } + setErrorCode(errorCode : number) : void { + this.errorCode = errorCode; + } + getAttributes() : Map { + return this.attributes; + } + setMessage(message : string) : void { + this.message = message; + } + getMessage() : string { + return this.message; + } + + toJson() : any { + let json : any = {}; + + if (this.errorCode) { + json.errorCode = this.errorCode; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export interface MachineRecipe { + withType(arg0): org.eclipse.che.api.machine.shared.dto.recipe.MachineRecipe; + setType(arg0): void; + setScript(arg0): void; + withScript(arg0): org.eclipse.che.api.machine.shared.dto.recipe.MachineRecipe; + getType(): string; + getScript(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto.recipe { + + export class MachineRecipeImpl implements org.eclipse.che.api.machine.shared.dto.recipe.MachineRecipe { + + type : string; + script : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.script) { + this.script = __jsonObject.script; + } + } + + } + + withType(type : string) : org.eclipse.che.api.machine.shared.dto.recipe.MachineRecipe { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setScript(script : string) : void { + this.script = script; + } + withScript(script : string) : org.eclipse.che.api.machine.shared.dto.recipe.MachineRecipe { + this.script = script; + return this; + } + getType() : string { + return this.type; + } + getScript() : string { + return this.script; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + if (this.script) { + json.script = this.script; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface Revision { + setId(arg0): void; + setMessage(arg0): void; + getBranches(): Array; + setBranches(arg0): void; + isFake(): boolean; + setFake(arg0): void; + withAuthor(arg0): org.eclipse.che.api.git.shared.Revision; + withBranches(arg0): org.eclipse.che.api.git.shared.Revision; + getDiffCommitFile(): Array; + setDiffCommitFile(arg0): void; + withDiffCommitFile(arg0): org.eclipse.che.api.git.shared.Revision; + getCommitParent(): Array; + setCommitParent(arg0): void; + withCommitParent(arg0): org.eclipse.che.api.git.shared.Revision; + getBranch(): string; + setBranch(arg0): void; + withBranch(arg0): org.eclipse.che.api.git.shared.Revision; + getCommitTime(): number; + setCommitTime(arg0): void; + withCommitTime(arg0): org.eclipse.che.api.git.shared.Revision; + getCommitter(): org.eclipse.che.api.git.shared.GitUser; + setCommitter(arg0): void; + withCommitter(arg0): org.eclipse.che.api.git.shared.Revision; + withId(arg0): org.eclipse.che.api.git.shared.Revision; + withMessage(arg0): org.eclipse.che.api.git.shared.Revision; + getAuthor(): org.eclipse.che.api.git.shared.GitUser; + setAuthor(arg0): void; + getMessage(): string; + getId(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RevisionImpl implements org.eclipse.che.api.git.shared.Revision { + + commitParent : Array; + committer : org.eclipse.che.api.git.shared.GitUser; + commitTime : number; + author : org.eclipse.che.api.git.shared.GitUser; + fake : boolean; + id : string; + message : string; + branches : Array; + diffCommitFile : Array; + branch : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.commitParent = new Array(); + if (__jsonObject) { + if (__jsonObject.commitParent) { + __jsonObject.commitParent.forEach((item) => { + this.commitParent.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.committer) { + this.committer = new org.eclipse.che.api.git.shared.GitUserImpl(__jsonObject.committer); + } + } + if (__jsonObject) { + if (__jsonObject.commitTime) { + this.commitTime = __jsonObject.commitTime; + } + } + if (__jsonObject) { + if (__jsonObject.author) { + this.author = new org.eclipse.che.api.git.shared.GitUserImpl(__jsonObject.author); + } + } + if (__jsonObject) { + if (__jsonObject.fake) { + this.fake = __jsonObject.fake; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + this.branches = new Array(); + if (__jsonObject) { + if (__jsonObject.branches) { + __jsonObject.branches.forEach((item) => { + this.branches.push(new org.eclipse.che.api.git.shared.BranchImpl(item)); + }); + } + } + this.diffCommitFile = new Array(); + if (__jsonObject) { + if (__jsonObject.diffCommitFile) { + __jsonObject.diffCommitFile.forEach((item) => { + this.diffCommitFile.push(new org.eclipse.che.api.git.shared.DiffCommitFileImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.branch) { + this.branch = __jsonObject.branch; + } + } + + } + + setId(id : string) : void { + this.id = id; + } + setMessage(message : string) : void { + this.message = message; + } + getBranches() : Array { + return this.branches; + } + setBranches(branches : Array) : void { + this.branches = branches; + } + isFake() : boolean { + return this.fake; + } + setFake(fake : boolean) : void { + this.fake = fake; + } + withAuthor(author : org.eclipse.che.api.git.shared.GitUser) : org.eclipse.che.api.git.shared.Revision { + this.author = author; + return this; + } + withBranches(branches : Array) : org.eclipse.che.api.git.shared.Revision { + this.branches = branches; + return this; + } + getDiffCommitFile() : Array { + return this.diffCommitFile; + } + setDiffCommitFile(diffCommitFile : Array) : void { + this.diffCommitFile = diffCommitFile; + } + withDiffCommitFile(diffCommitFile : Array) : org.eclipse.che.api.git.shared.Revision { + this.diffCommitFile = diffCommitFile; + return this; + } + getCommitParent() : Array { + return this.commitParent; + } + setCommitParent(commitParent : Array) : void { + this.commitParent = commitParent; + } + withCommitParent(commitParent : Array) : org.eclipse.che.api.git.shared.Revision { + this.commitParent = commitParent; + return this; + } + getBranch() : string { + return this.branch; + } + setBranch(branch : string) : void { + this.branch = branch; + } + withBranch(branch : string) : org.eclipse.che.api.git.shared.Revision { + this.branch = branch; + return this; + } + getCommitTime() : number { + return this.commitTime; + } + setCommitTime(commitTime : number) : void { + this.commitTime = commitTime; + } + withCommitTime(commitTime : number) : org.eclipse.che.api.git.shared.Revision { + this.commitTime = commitTime; + return this; + } + getCommitter() : org.eclipse.che.api.git.shared.GitUser { + return this.committer; + } + setCommitter(committer : org.eclipse.che.api.git.shared.GitUser) : void { + this.committer = committer; + } + withCommitter(committer : org.eclipse.che.api.git.shared.GitUser) : org.eclipse.che.api.git.shared.Revision { + this.committer = committer; + return this; + } + withId(id : string) : org.eclipse.che.api.git.shared.Revision { + this.id = id; + return this; + } + withMessage(message : string) : org.eclipse.che.api.git.shared.Revision { + this.message = message; + return this; + } + getAuthor() : org.eclipse.che.api.git.shared.GitUser { + return this.author; + } + setAuthor(author : org.eclipse.che.api.git.shared.GitUser) : void { + this.author = author; + } + getMessage() : string { + return this.message; + } + getId() : string { + return this.id; + } + + toJson() : any { + let json : any = {}; + + if (this.commitParent) { + let listArray = []; + this.commitParent.forEach((item) => { + listArray.push(item); + json.commitParent = listArray; + }); + } + if (this.committer) { + json.committer = (this.committer as org.eclipse.che.api.git.shared.GitUserImpl).toJson(); + } + if (this.commitTime) { + json.commitTime = this.commitTime; + } + if (this.author) { + json.author = (this.author as org.eclipse.che.api.git.shared.GitUserImpl).toJson(); + } + if (this.fake) { + json.fake = this.fake; + } + if (this.id) { + json.id = this.id; + } + if (this.message) { + json.message = this.message; + } + if (this.branches) { + let listArray = []; + this.branches.forEach((item) => { + listArray.push((item as org.eclipse.che.api.git.shared.BranchImpl).toJson()); + json.branches = listArray; + }); + } + if (this.diffCommitFile) { + let listArray = []; + this.diffCommitFile.forEach((item) => { + listArray.push((item as org.eclipse.che.api.git.shared.DiffCommitFileImpl).toJson()); + json.diffCommitFile = listArray; + }); + } + if (this.branch) { + json.branch = this.branch; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface GeneratorDescription { + getOptions(): Map; + setOptions(arg0): void; + withOptions(arg0): org.eclipse.che.api.project.shared.dto.GeneratorDescription; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class GeneratorDescriptionImpl implements org.eclipse.che.api.project.shared.dto.GeneratorDescription { + + options : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.options = new Map(); + if (__jsonObject) { + if (__jsonObject.options) { + let tmp : Array = Object.keys(__jsonObject.options); + tmp.forEach((key) => { + this.options.set(key, __jsonObject.options[key]); + }); + } + } + + } + + getOptions() : Map { + return this.options; + } + setOptions(options : Map) : void { + this.options = options; + } + withOptions(options : Map) : org.eclipse.che.api.project.shared.dto.GeneratorDescription { + this.options = options; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.options) { + let tmpMap : any = {}; + for (const [key, value] of this.options.entries()) { + tmpMap[key] = value; + } + json.options = tmpMap; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export interface ProjectTreeStatusUpdateDto { + withType(arg0): org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto; + withPath(arg0): org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto; + getType(): string; + getPath(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export class ProjectTreeStatusUpdateDtoImpl implements org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto { + + path : string; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto { + this.type = type; + return this; + } + withPath(path : string) : org.eclipse.che.api.project.shared.dto.event.ProjectTreeStatusUpdateDto { + this.path = path; + return this; + } + getType() : string { + return this.type; + } + getPath() : string { + return this.path; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface CheckoutRequest { + getFiles(): Array; + withName(arg0): org.eclipse.che.api.git.shared.CheckoutRequest; + setFiles(arg0): void; + withFiles(arg0): org.eclipse.che.api.git.shared.CheckoutRequest; + getStartPoint(): string; + setStartPoint(arg0): void; + withStartPoint(arg0): org.eclipse.che.api.git.shared.CheckoutRequest; + isCreateNew(): boolean; + isNoTrack(): boolean; + withNoTrack(arg0): org.eclipse.che.api.git.shared.CheckoutRequest; + setCreateNew(arg0): void; + withCreateNew(arg0): org.eclipse.che.api.git.shared.CheckoutRequest; + getTrackBranch(): string; + setTrackBranch(arg0): void; + withTrackBranch(arg0): org.eclipse.che.api.git.shared.CheckoutRequest; + setNoTrack(arg0): void; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class CheckoutRequestImpl implements org.eclipse.che.api.git.shared.CheckoutRequest { + + noTrack : boolean; + name : string; + startPoint : string; + files : Array; + trackBranch : string; + createNew : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.noTrack) { + this.noTrack = __jsonObject.noTrack; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.startPoint) { + this.startPoint = __jsonObject.startPoint; + } + } + this.files = new Array(); + if (__jsonObject) { + if (__jsonObject.files) { + __jsonObject.files.forEach((item) => { + this.files.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.trackBranch) { + this.trackBranch = __jsonObject.trackBranch; + } + } + if (__jsonObject) { + if (__jsonObject.createNew) { + this.createNew = __jsonObject.createNew; + } + } + + } + + getFiles() : Array { + return this.files; + } + withName(name : string) : org.eclipse.che.api.git.shared.CheckoutRequest { + this.name = name; + return this; + } + setFiles(files : Array) : void { + this.files = files; + } + withFiles(files : Array) : org.eclipse.che.api.git.shared.CheckoutRequest { + this.files = files; + return this; + } + getStartPoint() : string { + return this.startPoint; + } + setStartPoint(startPoint : string) : void { + this.startPoint = startPoint; + } + withStartPoint(startPoint : string) : org.eclipse.che.api.git.shared.CheckoutRequest { + this.startPoint = startPoint; + return this; + } + isCreateNew() : boolean { + return this.createNew; + } + isNoTrack() : boolean { + return this.noTrack; + } + withNoTrack(noTrack : boolean) : org.eclipse.che.api.git.shared.CheckoutRequest { + this.noTrack = noTrack; + return this; + } + setCreateNew(createNew : boolean) : void { + this.createNew = createNew; + } + withCreateNew(createNew : boolean) : org.eclipse.che.api.git.shared.CheckoutRequest { + this.createNew = createNew; + return this; + } + getTrackBranch() : string { + return this.trackBranch; + } + setTrackBranch(trackBranch : string) : void { + this.trackBranch = trackBranch; + } + withTrackBranch(trackBranch : string) : org.eclipse.che.api.git.shared.CheckoutRequest { + this.trackBranch = trackBranch; + return this; + } + setNoTrack(noTrack : boolean) : void { + this.noTrack = noTrack; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.noTrack) { + json.noTrack = this.noTrack; + } + if (this.name) { + json.name = this.name; + } + if (this.startPoint) { + json.startPoint = this.startPoint; + } + if (this.files) { + let listArray = []; + this.files.forEach((item) => { + listArray.push(item); + json.files = listArray; + }); + } + if (this.trackBranch) { + json.trackBranch = this.trackBranch; + } + if (this.createNew) { + json.createNew = this.createNew; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface CopyOptions { + setOverWrite(arg0): void; + getOverWrite(): boolean; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class CopyOptionsImpl implements org.eclipse.che.api.project.shared.dto.CopyOptions { + + name : string; + overWrite : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.overWrite) { + this.overWrite = __jsonObject.overWrite; + } + } + + } + + setOverWrite(overWrite : boolean) : void { + this.overWrite = overWrite; + } + getOverWrite() : boolean { + return this.overWrite; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.overWrite) { + json.overWrite = this.overWrite; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface ItemReference { + setContentLength(arg0): void; + getContentLength(): number; + getProject(): string; + withType(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + setType(arg0): void; + setPath(arg0): void; + withName(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + withLinks(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + withPath(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + getModified(): number; + setModified(arg0): void; + withProject(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + withModified(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + getProjectConfig(): org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + withContentLength(arg0): org.eclipse.che.api.project.shared.dto.ItemReference; + setProjectConfig(arg0): void; + getName(): string; + setName(arg0): void; + getType(): string; + getPath(): string; + getAttributes(): Map; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class ItemReferenceImpl implements org.eclipse.che.api.project.shared.dto.ItemReference { + + path : string; + projectConfig : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; + name : string; + project : string; + modified : number; + contentLength : number; + attributes : Map; + links : Array; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.projectConfig) { + this.projectConfig = new org.eclipse.che.api.workspace.shared.dto.ProjectConfigDtoImpl(__jsonObject.projectConfig); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.project) { + this.project = __jsonObject.project; + } + } + if (__jsonObject) { + if (__jsonObject.modified) { + this.modified = __jsonObject.modified; + } + } + if (__jsonObject) { + if (__jsonObject.contentLength) { + this.contentLength = __jsonObject.contentLength; + } + } + this.attributes = new Map(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + setContentLength(contentLength : number) : void { + this.contentLength = contentLength; + } + getContentLength() : number { + return this.contentLength; + } + getProject() : string { + return this.project; + } + withType(type : string) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setPath(path : string) : void { + this.path = path; + } + withName(name : string) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.name = name; + return this; + } + setAttributes(attributes : Map) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.attributes = attributes; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.links = links; + return this; + } + withPath(path : string) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.path = path; + return this; + } + getModified() : number { + return this.modified; + } + setModified(modified : number) : void { + this.modified = modified; + } + withProject(project : string) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.project = project; + return this; + } + withModified(modified : number) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.modified = modified; + return this; + } + getProjectConfig() : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto { + return this.projectConfig; + } + withContentLength(contentLength : number) : org.eclipse.che.api.project.shared.dto.ItemReference { + this.contentLength = contentLength; + return this; + } + setProjectConfig(projectConfig : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto) : void { + this.projectConfig = projectConfig; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getType() : string { + return this.type; + } + getPath() : string { + return this.path; + } + getAttributes() : Map { + return this.attributes; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.projectConfig) { + json.projectConfig = (this.projectConfig as org.eclipse.che.api.workspace.shared.dto.ProjectConfigDtoImpl).toJson(); + } + if (this.name) { + json.name = this.name; + } + if (this.project) { + json.project = this.project; + } + if (this.modified) { + json.modified = this.modified; + } + if (this.contentLength) { + json.contentLength = this.contentLength; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface FieldDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + setType(arg0): void; + withName(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + getVariables(): Array; + setVariables(arg0): void; + withVariables(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + setIsFinal(arg0): void; + withValue(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + withIsFinal(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + isIsStatic(): boolean; + setIsStatic(arg0): void; + withIsStatic(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + isIsTransient(): boolean; + setIsTransient(arg0): void; + withIsTransient(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + isIsVolatile(): boolean; + setIsVolatile(arg0): void; + withIsVolatile(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + isExistInformation(): boolean; + setExistInformation(arg0): void; + withExistInformation(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + getVariablePath(): org.eclipse.che.api.debug.shared.dto.VariablePathDto; + setVariablePath(arg0): void; + withVariablePath(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + setPrimitive(arg0): void; + withPrimitive(arg0): org.eclipse.che.api.debug.shared.dto.FieldDto; + isIsFinal(): boolean; + isPrimitive(): boolean; + getName(): string; + getValue(): string; + setName(arg0): void; + setValue(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class FieldDtoImpl implements org.eclipse.che.api.debug.shared.dto.FieldDto { + + variables : Array; + isStatic : boolean; + variablePath : org.eclipse.che.api.debug.shared.dto.VariablePathDto; + primitive : boolean; + name : string; + isVolatile : boolean; + isFinal : boolean; + type : string; + isTransient : boolean; + existInformation : boolean; + value : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.variables = new Array(); + if (__jsonObject) { + if (__jsonObject.variables) { + __jsonObject.variables.forEach((item) => { + this.variables.push(new org.eclipse.che.api.debug.shared.dto.VariableDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.isStatic) { + this.isStatic = __jsonObject.isStatic; + } + } + if (__jsonObject) { + if (__jsonObject.variablePath) { + this.variablePath = new org.eclipse.che.api.debug.shared.dto.VariablePathDtoImpl(__jsonObject.variablePath); + } + } + if (__jsonObject) { + if (__jsonObject.primitive) { + this.primitive = __jsonObject.primitive; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.isVolatile) { + this.isVolatile = __jsonObject.isVolatile; + } + } + if (__jsonObject) { + if (__jsonObject.isFinal) { + this.isFinal = __jsonObject.isFinal; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.isTransient) { + this.isTransient = __jsonObject.isTransient; + } + } + if (__jsonObject) { + if (__jsonObject.existInformation) { + this.existInformation = __jsonObject.existInformation; + } + } + if (__jsonObject) { + if (__jsonObject.value) { + this.value = __jsonObject.value; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withName(name : string) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.name = name; + return this; + } + getVariables() : Array { + return this.variables; + } + setVariables(variables : Array) : void { + this.variables = variables; + } + withVariables(variables : Array) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.variables = variables; + return this; + } + setIsFinal(isFinal : boolean) : void { + this.isFinal = isFinal; + } + withValue(value : string) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.value = value; + return this; + } + withIsFinal(isFinal : boolean) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.isFinal = isFinal; + return this; + } + isIsStatic() : boolean { + return this.isStatic; + } + setIsStatic(isStatic : boolean) : void { + this.isStatic = isStatic; + } + withIsStatic(isStatic : boolean) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.isStatic = isStatic; + return this; + } + isIsTransient() : boolean { + return this.isTransient; + } + setIsTransient(isTransient : boolean) : void { + this.isTransient = isTransient; + } + withIsTransient(isTransient : boolean) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.isTransient = isTransient; + return this; + } + isIsVolatile() : boolean { + return this.isVolatile; + } + setIsVolatile(isVolatile : boolean) : void { + this.isVolatile = isVolatile; + } + withIsVolatile(isVolatile : boolean) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.isVolatile = isVolatile; + return this; + } + isExistInformation() : boolean { + return this.existInformation; + } + setExistInformation(existInformation : boolean) : void { + this.existInformation = existInformation; + } + withExistInformation(existInformation : boolean) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.existInformation = existInformation; + return this; + } + getVariablePath() : org.eclipse.che.api.debug.shared.dto.VariablePathDto { + return this.variablePath; + } + setVariablePath(variablePath : org.eclipse.che.api.debug.shared.dto.VariablePathDto) : void { + this.variablePath = variablePath; + } + withVariablePath(variablePath : org.eclipse.che.api.debug.shared.dto.VariablePathDto) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.variablePath = variablePath; + return this; + } + setPrimitive(primitive : boolean) : void { + this.primitive = primitive; + } + withPrimitive(primitive : boolean) : org.eclipse.che.api.debug.shared.dto.FieldDto { + this.primitive = primitive; + return this; + } + isIsFinal() : boolean { + return this.isFinal; + } + isPrimitive() : boolean { + return this.primitive; + } + getName() : string { + return this.name; + } + getValue() : string { + return this.value; + } + setName(name : string) : void { + this.name = name; + } + setValue(value : string) : void { + this.value = value; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.variables) { + let listArray = []; + this.variables.forEach((item) => { + listArray.push((item as org.eclipse.che.api.debug.shared.dto.VariableDtoImpl).toJson()); + json.variables = listArray; + }); + } + if (this.isStatic) { + json.isStatic = this.isStatic; + } + if (this.variablePath) { + json.variablePath = (this.variablePath as org.eclipse.che.api.debug.shared.dto.VariablePathDtoImpl).toJson(); + } + if (this.primitive) { + json.primitive = this.primitive; + } + if (this.name) { + json.name = this.name; + } + if (this.isVolatile) { + json.isVolatile = this.isVolatile; + } + if (this.isFinal) { + json.isFinal = this.isFinal; + } + if (this.type) { + json.type = this.type; + } + if (this.isTransient) { + json.isTransient = this.isTransient; + } + if (this.existInformation) { + json.existInformation = this.existInformation; + } + if (this.value) { + json.value = this.value; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface TagCreateRequest { + setMessage(arg0): void; + setCommit(arg0): void; + getCommit(): string; + isForce(): boolean; + setForce(arg0): void; + getName(): string; + getMessage(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class TagCreateRequestImpl implements org.eclipse.che.api.git.shared.TagCreateRequest { + + commit : string; + name : string; + force : boolean; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.commit) { + this.commit = __jsonObject.commit; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.force) { + this.force = __jsonObject.force; + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + setMessage(message : string) : void { + this.message = message; + } + setCommit(commit : string) : void { + this.commit = commit; + } + getCommit() : string { + return this.commit; + } + isForce() : boolean { + return this.force; + } + setForce(force : boolean) : void { + this.force = force; + } + getName() : string { + return this.name; + } + getMessage() : string { + return this.message; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.commit) { + json.commit = this.commit; + } + if (this.name) { + json.name = this.name; + } + if (this.force) { + json.force = this.force; + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface Branch { + isActive(): boolean; + withName(arg0): org.eclipse.che.api.git.shared.Branch; + withRemote(arg0): org.eclipse.che.api.git.shared.Branch; + withDisplayName(arg0): org.eclipse.che.api.git.shared.Branch; + isRemote(): boolean; + withActive(arg0): org.eclipse.che.api.git.shared.Branch; + getName(): string; + getDisplayName(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class BranchImpl implements org.eclipse.che.api.git.shared.Branch { + + displayName : string; + name : string; + active : boolean; + remote : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.displayName) { + this.displayName = __jsonObject.displayName; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.active) { + this.active = __jsonObject.active; + } + } + if (__jsonObject) { + if (__jsonObject.remote) { + this.remote = __jsonObject.remote; + } + } + + } + + isActive() : boolean { + return this.active; + } + withName(name : string) : org.eclipse.che.api.git.shared.Branch { + this.name = name; + return this; + } + withRemote(remote : boolean) : org.eclipse.che.api.git.shared.Branch { + this.remote = remote; + return this; + } + withDisplayName(displayName : string) : org.eclipse.che.api.git.shared.Branch { + this.displayName = displayName; + return this; + } + isRemote() : boolean { + return this.remote; + } + withActive(active : boolean) : org.eclipse.che.api.git.shared.Branch { + this.active = active; + return this; + } + getName() : string { + return this.name; + } + getDisplayName() : string { + return this.displayName; + } + + toJson() : any { + let json : any = {}; + + if (this.displayName) { + json.displayName = this.displayName; + } + if (this.name) { + json.name = this.name; + } + if (this.active) { + json.active = this.active; + } + if (this.remote) { + json.remote = this.remote; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface MoveRequest { + getSource(): string; + setSource(arg0): void; + getTarget(): string; + setTarget(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class MoveRequestImpl implements org.eclipse.che.api.git.shared.MoveRequest { + + source : string; + target : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.source) { + this.source = __jsonObject.source; + } + } + if (__jsonObject) { + if (__jsonObject.target) { + this.target = __jsonObject.target; + } + } + + } + + getSource() : string { + return this.source; + } + setSource(source : string) : void { + this.source = source; + } + getTarget() : string { + return this.target; + } + setTarget(target : string) : void { + this.target = target; + } + + toJson() : any { + let json : any = {}; + + if (this.source) { + json.source = this.source; + } + if (this.target) { + json.target = this.target; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export interface PomModifiedEventDto { + withPath(arg0): org.eclipse.che.api.project.shared.dto.event.PomModifiedEventDto; + getPath(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto.event { + + export class PomModifiedEventDtoImpl implements org.eclipse.che.api.project.shared.dto.event.PomModifiedEventDto { + + path : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + + } + + withPath(path : string) : org.eclipse.che.api.project.shared.dto.event.PomModifiedEventDto { + this.path = path; + return this; + } + getPath() : string { + return this.path; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export interface JsonRpcResponse { + withResult(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; + getError(): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError; + getJsonrpc(): string; + withJsonrpc(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; + withId(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; + withError(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse; + getId(): number; + getResult(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export class JsonRpcResponseImpl implements org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse { + + result : string; + id : number; + error : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError; + jsonrpc : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.result) { + this.result = __jsonObject.result; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.error) { + this.error = new org.eclipse.che.api.core.jsonrpc.shared.JsonRpcErrorImpl(__jsonObject.error); + } + } + if (__jsonObject) { + if (__jsonObject.jsonrpc) { + this.jsonrpc = __jsonObject.jsonrpc; + } + } + + } + + withResult(result : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse { + this.result = result; + return this; + } + getError() : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError { + return this.error; + } + getJsonrpc() : string { + return this.jsonrpc; + } + withJsonrpc(jsonrpc : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse { + this.jsonrpc = jsonrpc; + return this; + } + withId(id : number) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse { + this.id = id; + return this; + } + withError(error : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcError) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcResponse { + this.error = error; + return this; + } + getId() : number { + return this.id; + } + getResult() : string { + return this.result; + } + + toJson() : any { + let json : any = {}; + + if (this.result) { + json.result = this.result; + } + if (this.id) { + json.id = this.id; + } + if (this.error) { + json.error = (this.error as org.eclipse.che.api.core.jsonrpc.shared.JsonRpcErrorImpl).toJson(); + } + if (this.jsonrpc) { + json.jsonrpc = this.jsonrpc; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface PullResponse { + getCommandOutput(): string; + setCommandOutput(arg0): void; + withCommandOutput(arg0): org.eclipse.che.api.git.shared.PullResponse; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class PullResponseImpl implements org.eclipse.che.api.git.shared.PullResponse { + + commandOutput : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.commandOutput) { + this.commandOutput = __jsonObject.commandOutput; + } + } + + } + + getCommandOutput() : string { + return this.commandOutput; + } + setCommandOutput(commandOutput : string) : void { + this.commandOutput = commandOutput; + } + withCommandOutput(commandOutput : string) : org.eclipse.che.api.git.shared.PullResponse { + this.commandOutput = commandOutput; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.commandOutput) { + json.commandOutput = this.commandOutput; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface TreeElement { + setNode(arg0): void; + getChildren(): Array; + setChildren(arg0): void; + withChildren(arg0): org.eclipse.che.api.project.shared.dto.TreeElement; + withNode(arg0): org.eclipse.che.api.project.shared.dto.TreeElement; + getNode(): org.eclipse.che.api.project.shared.dto.ItemReference; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class TreeElementImpl implements org.eclipse.che.api.project.shared.dto.TreeElement { + + node : org.eclipse.che.api.project.shared.dto.ItemReference; + children : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.node) { + this.node = new org.eclipse.che.api.project.shared.dto.ItemReferenceImpl(__jsonObject.node); + } + } + this.children = new Array(); + if (__jsonObject) { + if (__jsonObject.children) { + __jsonObject.children.forEach((item) => { + this.children.push(new org.eclipse.che.api.project.shared.dto.TreeElementImpl(item)); + }); + } + } + + } + + setNode(node : org.eclipse.che.api.project.shared.dto.ItemReference) : void { + this.node = node; + } + getChildren() : Array { + return this.children; + } + setChildren(children : Array) : void { + this.children = children; + } + withChildren(children : Array) : org.eclipse.che.api.project.shared.dto.TreeElement { + this.children = children; + return this; + } + withNode(node : org.eclipse.che.api.project.shared.dto.ItemReference) : org.eclipse.che.api.project.shared.dto.TreeElement { + this.node = node; + return this; + } + getNode() : org.eclipse.che.api.project.shared.dto.ItemReference { + return this.node; + } + + toJson() : any { + let json : any = {}; + + if (this.node) { + json.node = (this.node as org.eclipse.che.api.project.shared.dto.ItemReferenceImpl).toJson(); + } + if (this.children) { + let listArray = []; + this.children.forEach((item) => { + listArray.push((item as org.eclipse.che.api.project.shared.dto.TreeElementImpl).toJson()); + json.children = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface AttributeDto { + isRequired(): boolean; + getDescription(): string; + withDescription(arg0): org.eclipse.che.api.project.shared.dto.AttributeDto; + withName(arg0): org.eclipse.che.api.project.shared.dto.AttributeDto; + withRequired(arg0): org.eclipse.che.api.project.shared.dto.AttributeDto; + withValue(arg0): org.eclipse.che.api.project.shared.dto.AttributeDto; + isVariable(): boolean; + withVariable(arg0): org.eclipse.che.api.project.shared.dto.AttributeDto; + getName(): string; + getValue(): org.eclipse.che.api.project.shared.dto.ValueDto; + getProjectType(): string; + getId(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class AttributeDtoImpl implements org.eclipse.che.api.project.shared.dto.AttributeDto { + + name : string; + variable : boolean; + projectType : string; + description : string; + id : string; + value : org.eclipse.che.api.project.shared.dto.ValueDto; + required : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.variable) { + this.variable = __jsonObject.variable; + } + } + if (__jsonObject) { + if (__jsonObject.projectType) { + this.projectType = __jsonObject.projectType; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.value) { + this.value = new org.eclipse.che.api.project.shared.dto.ValueDtoImpl(__jsonObject.value); + } + } + if (__jsonObject) { + if (__jsonObject.required) { + this.required = __jsonObject.required; + } + } + + } + + isRequired() : boolean { + return this.required; + } + getDescription() : string { + return this.description; + } + withDescription(description : string) : org.eclipse.che.api.project.shared.dto.AttributeDto { + this.description = description; + return this; + } + withName(name : string) : org.eclipse.che.api.project.shared.dto.AttributeDto { + this.name = name; + return this; + } + withRequired(required : boolean) : org.eclipse.che.api.project.shared.dto.AttributeDto { + this.required = required; + return this; + } + withValue(value : org.eclipse.che.api.project.shared.dto.ValueDto) : org.eclipse.che.api.project.shared.dto.AttributeDto { + this.value = value; + return this; + } + isVariable() : boolean { + return this.variable; + } + withVariable(variable : boolean) : org.eclipse.che.api.project.shared.dto.AttributeDto { + this.variable = variable; + return this; + } + getName() : string { + return this.name; + } + getValue() : org.eclipse.che.api.project.shared.dto.ValueDto { + return this.value; + } + getProjectType() : string { + return this.projectType; + } + getId() : string { + return this.id; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.variable) { + json.variable = this.variable; + } + if (this.projectType) { + json.projectType = this.projectType; + } + if (this.description) { + json.description = this.description; + } + if (this.id) { + json.id = this.id; + } + if (this.value) { + json.value = (this.value as org.eclipse.che.api.project.shared.dto.ValueDtoImpl).toJson(); + } + if (this.required) { + json.required = this.required; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface IndexFile { + setPath(arg0): void; + withPath(arg0): org.eclipse.che.api.git.shared.IndexFile; + isIndexed(): boolean; + setIndexed(arg0): void; + withIndexed(arg0): org.eclipse.che.api.git.shared.IndexFile; + getPath(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class IndexFileImpl implements org.eclipse.che.api.git.shared.IndexFile { + + path : string; + indexed : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.path) { + this.path = __jsonObject.path; + } + } + if (__jsonObject) { + if (__jsonObject.indexed) { + this.indexed = __jsonObject.indexed; + } + } + + } + + setPath(path : string) : void { + this.path = path; + } + withPath(path : string) : org.eclipse.che.api.git.shared.IndexFile { + this.path = path; + return this; + } + isIndexed() : boolean { + return this.indexed; + } + setIndexed(indexed : boolean) : void { + this.indexed = indexed; + } + withIndexed(indexed : boolean) : org.eclipse.che.api.git.shared.IndexFile { + this.indexed = indexed; + return this; + } + getPath() : string { + return this.path; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + json.path = this.path; + } + if (this.indexed) { + json.indexed = this.indexed; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface DiffCommitFile { + getOldPath(): string; + setChangeType(arg0): void; + withChangeType(arg0): org.eclipse.che.api.git.shared.DiffCommitFile; + setOldPath(arg0): void; + getNewPath(): string; + getChangeType(): string; + setNewPath(arg0): void; + withNewPath(arg0): org.eclipse.che.api.git.shared.DiffCommitFile; + withOldPath(arg0): org.eclipse.che.api.git.shared.DiffCommitFile; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class DiffCommitFileImpl implements org.eclipse.che.api.git.shared.DiffCommitFile { + + changeType : string; + oldPath : string; + newPath : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.changeType) { + this.changeType = __jsonObject.changeType; + } + } + if (__jsonObject) { + if (__jsonObject.oldPath) { + this.oldPath = __jsonObject.oldPath; + } + } + if (__jsonObject) { + if (__jsonObject.newPath) { + this.newPath = __jsonObject.newPath; + } + } + + } + + getOldPath() : string { + return this.oldPath; + } + setChangeType(changeType : string) : void { + this.changeType = changeType; + } + withChangeType(changeType : string) : org.eclipse.che.api.git.shared.DiffCommitFile { + this.changeType = changeType; + return this; + } + setOldPath(oldPath : string) : void { + this.oldPath = oldPath; + } + getNewPath() : string { + return this.newPath; + } + getChangeType() : string { + return this.changeType; + } + setNewPath(newPath : string) : void { + this.newPath = newPath; + } + withNewPath(newPath : string) : org.eclipse.che.api.git.shared.DiffCommitFile { + this.newPath = newPath; + return this; + } + withOldPath(oldPath : string) : org.eclipse.che.api.git.shared.DiffCommitFile { + this.oldPath = oldPath; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.changeType) { + json.changeType = this.changeType; + } + if (this.oldPath) { + json.oldPath = this.oldPath; + } + if (this.newPath) { + json.newPath = this.newPath; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface SimpleValueDto { + getVariables(): Array; + setVariables(arg0): void; + withVariables(arg0): org.eclipse.che.api.debug.shared.dto.SimpleValueDto; + withValue(arg0): org.eclipse.che.api.debug.shared.dto.SimpleValueDto; + getValue(): string; + setValue(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class SimpleValueDtoImpl implements org.eclipse.che.api.debug.shared.dto.SimpleValueDto { + + variables : Array; + value : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.variables = new Array(); + if (__jsonObject) { + if (__jsonObject.variables) { + __jsonObject.variables.forEach((item) => { + this.variables.push(new org.eclipse.che.api.debug.shared.dto.VariableDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.value) { + this.value = __jsonObject.value; + } + } + + } + + getVariables() : Array { + return this.variables; + } + setVariables(variables : Array) : void { + this.variables = variables; + } + withVariables(variables : Array) : org.eclipse.che.api.debug.shared.dto.SimpleValueDto { + this.variables = variables; + return this; + } + withValue(value : string) : org.eclipse.che.api.debug.shared.dto.SimpleValueDto { + this.value = value; + return this; + } + getValue() : string { + return this.value; + } + setValue(value : string) : void { + this.value = value; + } + + toJson() : any { + let json : any = {}; + + if (this.variables) { + let listArray = []; + this.variables.forEach((item) => { + listArray.push((item as org.eclipse.che.api.debug.shared.dto.VariableDtoImpl).toJson()); + json.variables = listArray; + }); + } + if (this.value) { + json.value = this.value; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface SnapshotDto { + setDescription(arg0): void; + withType(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + setType(arg0): void; + withDescription(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + setId(arg0): void; + withLinks(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + withId(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + setWorkspaceId(arg0): void; + withWorkspaceId(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + withDev(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + setDev(arg0): void; + withMachineName(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + setMachineName(arg0): void; + withCreationDate(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + withEnvName(arg0): org.eclipse.che.api.machine.shared.dto.SnapshotDto; + setEnvName(arg0): void; + setCreationDate(arg0): void; + getDescription(): string; + getWorkspaceId(): string; + isDev(): boolean; + getMachineName(): string; + getCreationDate(): number; + getEnvName(): string; + getId(): string; + getType(): string; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class SnapshotDtoImpl implements org.eclipse.che.api.machine.shared.dto.SnapshotDto { + + dev : boolean; + envName : string; + description : string; + links : Array; + id : string; + type : string; + creationDate : number; + machineName : string; + workspaceId : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.dev) { + this.dev = __jsonObject.dev; + } + } + if (__jsonObject) { + if (__jsonObject.envName) { + this.envName = __jsonObject.envName; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.creationDate) { + this.creationDate = __jsonObject.creationDate; + } + } + if (__jsonObject) { + if (__jsonObject.machineName) { + this.machineName = __jsonObject.machineName; + } + } + if (__jsonObject) { + if (__jsonObject.workspaceId) { + this.workspaceId = __jsonObject.workspaceId; + } + } + + } + + setDescription(description : string) : void { + this.description = description; + } + withType(type : string) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withDescription(description : string) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.description = description; + return this; + } + setId(id : string) : void { + this.id = id; + } + withLinks(links : Array) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.links = links; + return this; + } + withId(id : string) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.id = id; + return this; + } + setWorkspaceId(workspaceId : string) : void { + this.workspaceId = workspaceId; + } + withWorkspaceId(workspaceId : string) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.workspaceId = workspaceId; + return this; + } + withDev(dev : boolean) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.dev = dev; + return this; + } + setDev(dev : boolean) : void { + this.dev = dev; + } + withMachineName(machineName : string) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.machineName = machineName; + return this; + } + setMachineName(machineName : string) : void { + this.machineName = machineName; + } + withCreationDate(creationDate : number) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.creationDate = creationDate; + return this; + } + withEnvName(envName : string) : org.eclipse.che.api.machine.shared.dto.SnapshotDto { + this.envName = envName; + return this; + } + setEnvName(envName : string) : void { + this.envName = envName; + } + setCreationDate(creationDate : number) : void { + this.creationDate = creationDate; + } + getDescription() : string { + return this.description; + } + getWorkspaceId() : string { + return this.workspaceId; + } + isDev() : boolean { + return this.dev; + } + getMachineName() : string { + return this.machineName; + } + getCreationDate() : number { + return this.creationDate; + } + getEnvName() : string { + return this.envName; + } + getId() : string { + return this.id; + } + getType() : string { + return this.type; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.dev) { + json.dev = this.dev; + } + if (this.envName) { + json.envName = this.envName; + } + if (this.description) { + json.description = this.description; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.id) { + json.id = this.id; + } + if (this.type) { + json.type = this.type; + } + if (this.creationDate) { + json.creationDate = this.creationDate; + } + if (this.machineName) { + json.machineName = this.machineName; + } + if (this.workspaceId) { + json.workspaceId = this.workspaceId; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface ProjectUpdate { + getDescription(): string; + setDescription(arg0): void; + withType(arg0): org.eclipse.che.api.project.shared.dto.ProjectUpdate; + setType(arg0): void; + withDescription(arg0): org.eclipse.che.api.project.shared.dto.ProjectUpdate; + setAttributes(arg0): void; + withAttributes(arg0): org.eclipse.che.api.project.shared.dto.ProjectUpdate; + setRecipe(arg0): void; + withRecipe(arg0): org.eclipse.che.api.project.shared.dto.ProjectUpdate; + getMixins(): Array; + setMixins(arg0): void; + withMixins(arg0): org.eclipse.che.api.project.shared.dto.ProjectUpdate; + getRecipe(): string; + setVisibility(arg0): void; + withVisibility(arg0): org.eclipse.che.api.project.shared.dto.ProjectUpdate; + getVisibility(): string; + getContentRoot(): string; + setContentRoot(arg0): void; + withContentRoot(arg0): org.eclipse.che.api.project.shared.dto.ProjectUpdate; + getType(): string; + getAttributes(): Map>; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class ProjectUpdateImpl implements org.eclipse.che.api.project.shared.dto.ProjectUpdate { + + mixins : Array; + visibility : string; + contentRoot : string; + recipe : string; + description : string; + attributes : Map>; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.mixins = new Array(); + if (__jsonObject) { + if (__jsonObject.mixins) { + __jsonObject.mixins.forEach((item) => { + this.mixins.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.visibility) { + this.visibility = __jsonObject.visibility; + } + } + if (__jsonObject) { + if (__jsonObject.contentRoot) { + this.contentRoot = __jsonObject.contentRoot; + } + } + if (__jsonObject) { + if (__jsonObject.recipe) { + this.recipe = __jsonObject.recipe; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.attributes = new Map>(); + if (__jsonObject) { + if (__jsonObject.attributes) { + let tmp : Array = Object.keys(__jsonObject.attributes); + tmp.forEach((key) => { + this.attributes.set(key, __jsonObject.attributes[key]); + }); + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withType(type : string) : org.eclipse.che.api.project.shared.dto.ProjectUpdate { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withDescription(description : string) : org.eclipse.che.api.project.shared.dto.ProjectUpdate { + this.description = description; + return this; + } + setAttributes(attributes : Map>) : void { + this.attributes = attributes; + } + withAttributes(attributes : Map>) : org.eclipse.che.api.project.shared.dto.ProjectUpdate { + this.attributes = attributes; + return this; + } + setRecipe(recipe : string) : void { + this.recipe = recipe; + } + withRecipe(recipe : string) : org.eclipse.che.api.project.shared.dto.ProjectUpdate { + this.recipe = recipe; + return this; + } + getMixins() : Array { + return this.mixins; + } + setMixins(mixins : Array) : void { + this.mixins = mixins; + } + withMixins(mixins : Array) : org.eclipse.che.api.project.shared.dto.ProjectUpdate { + this.mixins = mixins; + return this; + } + getRecipe() : string { + return this.recipe; + } + setVisibility(visibility : string) : void { + this.visibility = visibility; + } + withVisibility(visibility : string) : org.eclipse.che.api.project.shared.dto.ProjectUpdate { + this.visibility = visibility; + return this; + } + getVisibility() : string { + return this.visibility; + } + getContentRoot() : string { + return this.contentRoot; + } + setContentRoot(contentRoot : string) : void { + this.contentRoot = contentRoot; + } + withContentRoot(contentRoot : string) : org.eclipse.che.api.project.shared.dto.ProjectUpdate { + this.contentRoot = contentRoot; + return this; + } + getType() : string { + return this.type; + } + getAttributes() : Map> { + return this.attributes; + } + + toJson() : any { + let json : any = {}; + + if (this.mixins) { + let listArray = []; + this.mixins.forEach((item) => { + listArray.push(item); + json.mixins = listArray; + }); + } + if (this.visibility) { + json.visibility = this.visibility; + } + if (this.contentRoot) { + json.contentRoot = this.contentRoot; + } + if (this.recipe) { + json.recipe = this.recipe; + } + if (this.description) { + json.description = this.description; + } + if (this.attributes) { + let tmpMap : any = {}; + for (const [key, value] of this.attributes.entries()) { + tmpMap[key] = value; + } + json.attributes = tmpMap; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export interface AttributeDescriptor { + getValues(): Array; + setRequired(arg0): void; + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.project.shared.dto.AttributeDescriptor; + setVariable(arg0): void; + withName(arg0): org.eclipse.che.api.project.shared.dto.AttributeDescriptor; + withRequired(arg0): org.eclipse.che.api.project.shared.dto.AttributeDescriptor; + withVariable(arg0): org.eclipse.che.api.project.shared.dto.AttributeDescriptor; + getRequired(): boolean; + setValues(arg0): void; + withValues(arg0): org.eclipse.che.api.project.shared.dto.AttributeDescriptor; + getVariable(): boolean; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.project.shared.dto { + + export class AttributeDescriptorImpl implements org.eclipse.che.api.project.shared.dto.AttributeDescriptor { + + values : Array; + variable : boolean; + name : string; + description : string; + required : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.values = new Array(); + if (__jsonObject) { + if (__jsonObject.values) { + __jsonObject.values.forEach((item) => { + this.values.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.variable) { + this.variable = __jsonObject.variable; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + if (__jsonObject) { + if (__jsonObject.required) { + this.required = __jsonObject.required; + } + } + + } + + getValues() : Array { + return this.values; + } + setRequired(required : boolean) : void { + this.required = required; + } + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.project.shared.dto.AttributeDescriptor { + this.description = description; + return this; + } + setVariable(variable : boolean) : void { + this.variable = variable; + } + withName(name : string) : org.eclipse.che.api.project.shared.dto.AttributeDescriptor { + this.name = name; + return this; + } + withRequired(required : boolean) : org.eclipse.che.api.project.shared.dto.AttributeDescriptor { + this.required = required; + return this; + } + withVariable(variable : boolean) : org.eclipse.che.api.project.shared.dto.AttributeDescriptor { + this.variable = variable; + return this; + } + getRequired() : boolean { + return this.required; + } + setValues(values : Array) : void { + this.values = values; + } + withValues(values : Array) : org.eclipse.che.api.project.shared.dto.AttributeDescriptor { + this.values = values; + return this; + } + getVariable() : boolean { + return this.variable; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.values) { + let listArray = []; + this.values.forEach((item) => { + listArray.push(item); + json.values = listArray; + }); + } + if (this.variable) { + json.variable = this.variable; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.required) { + json.required = this.required; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface ResetRequest { + setType(arg0): void; + setCommit(arg0): void; + withCommit(arg0): org.eclipse.che.api.git.shared.ResetRequest; + getFilePattern(): Array; + setFilePattern(arg0): void; + withFilePattern(arg0): org.eclipse.che.api.git.shared.ResetRequest; + getCommit(): string; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class ResetRequestImpl implements org.eclipse.che.api.git.shared.ResetRequest { + + filePattern : Array; + commit : string; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.filePattern = new Array(); + if (__jsonObject) { + if (__jsonObject.filePattern) { + __jsonObject.filePattern.forEach((item) => { + this.filePattern.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.commit) { + this.commit = __jsonObject.commit; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + setType(type : string) : void { + this.type = type; + } + setCommit(commit : string) : void { + this.commit = commit; + } + withCommit(commit : string) : org.eclipse.che.api.git.shared.ResetRequest { + this.commit = commit; + return this; + } + getFilePattern() : Array { + return this.filePattern; + } + setFilePattern(filePattern : Array) : void { + this.filePattern = filePattern; + } + withFilePattern(filePattern : Array) : org.eclipse.che.api.git.shared.ResetRequest { + this.filePattern = filePattern; + return this; + } + getCommit() : string { + return this.commit; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.filePattern) { + let listArray = []; + this.filePattern.forEach((item) => { + listArray.push(item); + json.filePattern = listArray; + }); + } + if (this.commit) { + json.commit = this.commit; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.stack { + + export interface StackSourceDto { + withType(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto; + setType(arg0): void; + withOrigin(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto; + setOrigin(arg0): void; + getOrigin(): string; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.stack { + + export class StackSourceDtoImpl implements org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto { + + origin : string; + type : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.origin) { + this.origin = __jsonObject.origin; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + + } + + withType(type : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withOrigin(origin : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackSourceDto { + this.origin = origin; + return this; + } + setOrigin(origin : string) : void { + this.origin = origin; + } + getOrigin() : string { + return this.origin; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.origin) { + json.origin = this.origin; + } + if (this.type) { + json.type = this.type; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface GitCheckoutEvent { + getWorkspaceId(): string; + setWorkspaceId(arg0): void; + withWorkspaceId(arg0): org.eclipse.che.api.git.shared.GitCheckoutEvent; + getBranchRef(): string; + setBranchRef(arg0): void; + withBranchRef(arg0): org.eclipse.che.api.git.shared.GitCheckoutEvent; + getProjectName(): string; + setProjectName(arg0): void; + withProjectName(arg0): org.eclipse.che.api.git.shared.GitCheckoutEvent; + setCheckoutOnly(arg0): void; + withCheckoutOnly(arg0): org.eclipse.che.api.git.shared.GitCheckoutEvent; + isCheckoutOnly(): boolean; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class GitCheckoutEventImpl implements org.eclipse.che.api.git.shared.GitCheckoutEvent { + + branchRef : string; + projectName : string; + checkoutOnly : boolean; + workspaceId : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.branchRef) { + this.branchRef = __jsonObject.branchRef; + } + } + if (__jsonObject) { + if (__jsonObject.projectName) { + this.projectName = __jsonObject.projectName; + } + } + if (__jsonObject) { + if (__jsonObject.checkoutOnly) { + this.checkoutOnly = __jsonObject.checkoutOnly; + } + } + if (__jsonObject) { + if (__jsonObject.workspaceId) { + this.workspaceId = __jsonObject.workspaceId; + } + } + + } + + getWorkspaceId() : string { + return this.workspaceId; + } + setWorkspaceId(workspaceId : string) : void { + this.workspaceId = workspaceId; + } + withWorkspaceId(workspaceId : string) : org.eclipse.che.api.git.shared.GitCheckoutEvent { + this.workspaceId = workspaceId; + return this; + } + getBranchRef() : string { + return this.branchRef; + } + setBranchRef(branchRef : string) : void { + this.branchRef = branchRef; + } + withBranchRef(branchRef : string) : org.eclipse.che.api.git.shared.GitCheckoutEvent { + this.branchRef = branchRef; + return this; + } + getProjectName() : string { + return this.projectName; + } + setProjectName(projectName : string) : void { + this.projectName = projectName; + } + withProjectName(projectName : string) : org.eclipse.che.api.git.shared.GitCheckoutEvent { + this.projectName = projectName; + return this; + } + setCheckoutOnly(checkoutOnly : boolean) : void { + this.checkoutOnly = checkoutOnly; + } + withCheckoutOnly(checkoutOnly : boolean) : org.eclipse.che.api.git.shared.GitCheckoutEvent { + this.checkoutOnly = checkoutOnly; + return this; + } + isCheckoutOnly() : boolean { + return this.checkoutOnly; + } + + toJson() : any { + let json : any = {}; + + if (this.branchRef) { + json.branchRef = this.branchRef; + } + if (this.projectName) { + json.projectName = this.projectName; + } + if (this.checkoutOnly) { + json.checkoutOnly = this.checkoutOnly; + } + if (this.workspaceId) { + json.workspaceId = this.workspaceId; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface RemoteReference { + setReferenceName(arg0): void; + withReferenceName(arg0): org.eclipse.che.api.git.shared.RemoteReference; + setCommitId(arg0): void; + withCommitId(arg0): org.eclipse.che.api.git.shared.RemoteReference; + getReferenceName(): string; + getCommitId(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RemoteReferenceImpl implements org.eclipse.che.api.git.shared.RemoteReference { + + commitId : string; + referenceName : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.commitId) { + this.commitId = __jsonObject.commitId; + } + } + if (__jsonObject) { + if (__jsonObject.referenceName) { + this.referenceName = __jsonObject.referenceName; + } + } + + } + + setReferenceName(referenceName : string) : void { + this.referenceName = referenceName; + } + withReferenceName(referenceName : string) : org.eclipse.che.api.git.shared.RemoteReference { + this.referenceName = referenceName; + return this; + } + setCommitId(commitId : string) : void { + this.commitId = commitId; + } + withCommitId(commitId : string) : org.eclipse.che.api.git.shared.RemoteReference { + this.commitId = commitId; + return this; + } + getReferenceName() : string { + return this.referenceName; + } + getCommitId() : string { + return this.commitId; + } + + toJson() : any { + let json : any = {}; + + if (this.commitId) { + json.commitId = this.commitId; + } + if (this.referenceName) { + json.referenceName = this.referenceName; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.event { + + export interface WorkspaceStatusEvent { + getEventType(): string; + getError(): string; + setEventType(arg0): void; + withError(arg0): org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent; + withEventType(arg0): org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent; + getWorkspaceId(): string; + setWorkspaceId(arg0): void; + withWorkspaceId(arg0): org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent; + setError(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.event { + + export class WorkspaceStatusEventImpl implements org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent { + + eventType : string; + error : string; + workspaceId : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.eventType) { + this.eventType = __jsonObject.eventType; + } + } + if (__jsonObject) { + if (__jsonObject.error) { + this.error = __jsonObject.error; + } + } + if (__jsonObject) { + if (__jsonObject.workspaceId) { + this.workspaceId = __jsonObject.workspaceId; + } + } + + } + + getEventType() : string { + return this.eventType; + } + getError() : string { + return this.error; + } + setEventType(eventType : string) : void { + this.eventType = eventType; + } + withError(error : string) : org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent { + this.error = error; + return this; + } + withEventType(eventType : string) : org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent { + this.eventType = eventType; + return this; + } + getWorkspaceId() : string { + return this.workspaceId; + } + setWorkspaceId(workspaceId : string) : void { + this.workspaceId = workspaceId; + } + withWorkspaceId(workspaceId : string) : org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent { + this.workspaceId = workspaceId; + return this; + } + setError(error : string) : void { + this.error = error; + } + + toJson() : any { + let json : any = {}; + + if (this.eventType) { + json.eventType = this.eventType; + } + if (this.error) { + json.error = this.error; + } + if (this.workspaceId) { + json.workspaceId = this.workspaceId; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface MachineLimitsDto { + withRam(arg0): org.eclipse.che.api.machine.shared.dto.MachineLimitsDto; + getRam(): number; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class MachineLimitsDtoImpl implements org.eclipse.che.api.machine.shared.dto.MachineLimitsDto { + + ram : number; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.ram) { + this.ram = __jsonObject.ram; + } + } + + } + + withRam(ram : number) : org.eclipse.che.api.machine.shared.dto.MachineLimitsDto { + this.ram = ram; + return this; + } + getRam() : number { + return this.ram; + } + + toJson() : any { + let json : any = {}; + + if (this.ram) { + json.ram = this.ram; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface ConfigRequest { + getConfigEntries(): Map; + withConfigEntries(arg0): org.eclipse.che.api.git.shared.ConfigRequest; + setConfigEntries(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class ConfigRequestImpl implements org.eclipse.che.api.git.shared.ConfigRequest { + + configEntries : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.configEntries = new Map(); + if (__jsonObject) { + if (__jsonObject.configEntries) { + let tmp : Array = Object.keys(__jsonObject.configEntries); + tmp.forEach((key) => { + this.configEntries.set(key, __jsonObject.configEntries[key]); + }); + } + } + + } + + getConfigEntries() : Map { + return this.configEntries; + } + withConfigEntries(configEntries : Map) : org.eclipse.che.api.git.shared.ConfigRequest { + this.configEntries = configEntries; + return this; + } + setConfigEntries(configEntries : Map) : void { + this.configEntries = configEntries; + } + + toJson() : any { + let json : any = {}; + + if (this.configEntries) { + let tmpMap : any = {}; + for (const [key, value] of this.configEntries.entries()) { + tmpMap[key] = value; + } + json.configEntries = tmpMap; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface RemoteAddRequest { + getUrl(): string; + setUrl(arg0): void; + getBranches(): Array; + setBranches(arg0): void; + withName(arg0): org.eclipse.che.api.git.shared.RemoteAddRequest; + withUrl(arg0): org.eclipse.che.api.git.shared.RemoteAddRequest; + getName(): string; + setName(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RemoteAddRequestImpl implements org.eclipse.che.api.git.shared.RemoteAddRequest { + + name : string; + branches : Array; + url : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + this.branches = new Array(); + if (__jsonObject) { + if (__jsonObject.branches) { + __jsonObject.branches.forEach((item) => { + this.branches.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.url) { + this.url = __jsonObject.url; + } + } + + } + + getUrl() : string { + return this.url; + } + setUrl(url : string) : void { + this.url = url; + } + getBranches() : Array { + return this.branches; + } + setBranches(branches : Array) : void { + this.branches = branches; + } + withName(name : string) : org.eclipse.che.api.git.shared.RemoteAddRequest { + this.name = name; + return this; + } + withUrl(url : string) : org.eclipse.che.api.git.shared.RemoteAddRequest { + this.url = url; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.branches) { + let listArray = []; + this.branches.forEach((item) => { + listArray.push(item); + json.branches = listArray; + }); + } + if (this.url) { + json.url = this.url; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface Tag { + withName(arg0): org.eclipse.che.api.git.shared.Tag; + getName(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class TagImpl implements org.eclipse.che.api.git.shared.Tag { + + name : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + + } + + withName(name : string) : org.eclipse.che.api.git.shared.Tag { + this.name = name; + return this; + } + getName() : string { + return this.name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface WorkspaceConfigDto { + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + getProjects(): Array; + setProjects(arg0): void; + withName(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + withLinks(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + getCommands(): Array; + setCommands(arg0): void; + withCommands(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + getEnvironments(): Map; + setEnvironments(arg0): void; + withEnvironments(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + withProjects(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + getDefaultEnv(): string; + setDefaultEnv(arg0): void; + withDefaultEnv(arg0): org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; + getName(): string; + setName(arg0): void; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class WorkspaceConfigDtoImpl implements org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + + projects : Array; + environments : Map; + name : string; + description : string; + links : Array; + commands : Array; + defaultEnv : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.projects = new Array(); + if (__jsonObject) { + if (__jsonObject.projects) { + __jsonObject.projects.forEach((item) => { + this.projects.push(new org.eclipse.che.api.workspace.shared.dto.ProjectConfigDtoImpl(item)); + }); + } + } + this.environments = new Map(); + if (__jsonObject) { + if (__jsonObject.environments) { + let tmp : Array = Object.keys(__jsonObject.environments); + tmp.forEach((key) => { + this.environments.set(key, new org.eclipse.che.api.workspace.shared.dto.EnvironmentDtoImpl(__jsonObject.environments[key])); + }); + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + this.commands = new Array(); + if (__jsonObject) { + if (__jsonObject.commands) { + __jsonObject.commands.forEach((item) => { + this.commands.push(new org.eclipse.che.api.machine.shared.dto.CommandDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.defaultEnv) { + this.defaultEnv = __jsonObject.defaultEnv; + } + } + + } + + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + this.description = description; + return this; + } + getProjects() : Array { + return this.projects; + } + setProjects(projects : Array) : void { + this.projects = projects; + } + withName(name : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + this.name = name; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + this.links = links; + return this; + } + getCommands() : Array { + return this.commands; + } + setCommands(commands : Array) : void { + this.commands = commands; + } + withCommands(commands : Array) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + this.commands = commands; + return this; + } + getEnvironments() : Map { + return this.environments; + } + setEnvironments(environments : Map) : void { + this.environments = environments; + } + withEnvironments(environments : Map) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + this.environments = environments; + return this; + } + withProjects(projects : Array) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + this.projects = projects; + return this; + } + getDefaultEnv() : string { + return this.defaultEnv; + } + setDefaultEnv(defaultEnv : string) : void { + this.defaultEnv = defaultEnv; + } + withDefaultEnv(defaultEnv : string) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + this.defaultEnv = defaultEnv; + return this; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.projects) { + let listArray = []; + this.projects.forEach((item) => { + listArray.push((item as org.eclipse.che.api.workspace.shared.dto.ProjectConfigDtoImpl).toJson()); + json.projects = listArray; + }); + } + if (this.environments) { + let tmpMap : any = {}; + for (const [key, value] of this.environments.entries()) { + tmpMap[key] = (value as org.eclipse.che.api.workspace.shared.dto.EnvironmentDtoImpl).toJson(); + } + json.environments = tmpMap; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.commands) { + let listArray = []; + this.commands.forEach((item) => { + listArray.push((item as org.eclipse.che.api.machine.shared.dto.CommandDtoImpl).toJson()); + json.commands = listArray; + }); + } + if (this.defaultEnv) { + json.defaultEnv = this.defaultEnv; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface RebaseRequest { + getBranch(): string; + setBranch(arg0): void; + setOperation(arg0): void; + getOperation(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RebaseRequestImpl implements org.eclipse.che.api.git.shared.RebaseRequest { + + branch : string; + operation : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.branch) { + this.branch = __jsonObject.branch; + } + } + if (__jsonObject) { + if (__jsonObject.operation) { + this.operation = __jsonObject.operation; + } + } + + } + + getBranch() : string { + return this.branch; + } + setBranch(branch : string) : void { + this.branch = branch; + } + setOperation(operation : string) : void { + this.operation = operation; + } + getOperation() : string { + return this.operation; + } + + toJson() : any { + let json : any = {}; + + if (this.branch) { + json.branch = this.branch; + } + if (this.operation) { + json.operation = this.operation; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.stack { + + export interface StackComponentDto { + setVersion(arg0): void; + withName(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDto; + withVersion(arg0): org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDto; + setName(arg0): void; + getVersion(): string; + getName(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto.stack { + + export class StackComponentDtoImpl implements org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDto { + + name : string; + version : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.version) { + this.version = __jsonObject.version; + } + } + + } + + setVersion(version : string) : void { + this.version = version; + } + withName(name : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDto { + this.name = name; + return this; + } + withVersion(version : string) : org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDto { + this.version = version; + return this; + } + setName(name : string) : void { + this.name = name; + } + getVersion() : string { + return this.version; + } + getName() : string { + return this.name; + } + + toJson() : any { + let json : any = {}; + + if (this.name) { + json.name = this.name; + } + if (this.version) { + json.version = this.version; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface ServiceDescriptor { + getVersion(): string; + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor; + setVersion(arg0): void; + getHref(): string; + withLinks(arg0): org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor; + withVersion(arg0): org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor; + setHref(arg0): void; + withHref(arg0): org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class ServiceDescriptorImpl implements org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor { + + description : string; + links : Array; + href : string; + version : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.href) { + this.href = __jsonObject.href; + } + } + if (__jsonObject) { + if (__jsonObject.version) { + this.version = __jsonObject.version; + } + } + + } + + getVersion() : string { + return this.version; + } + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor { + this.description = description; + return this; + } + setVersion(version : string) : void { + this.version = version; + } + getHref() : string { + return this.href; + } + withLinks(links : Array) : org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor { + this.links = links; + return this; + } + withVersion(version : string) : org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor { + this.version = version; + return this; + } + setHref(href : string) : void { + this.href = href; + } + withHref(href : string) : org.eclipse.che.api.core.rest.shared.dto.ServiceDescriptor { + this.href = href; + return this; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.description) { + json.description = this.description; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.href) { + json.href = this.href; + } + if (this.version) { + json.version = this.version; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface NewSnapshotDescriptor { + getDescription(): string; + setDescription(arg0): void; + withDescription(arg0): org.eclipse.che.api.machine.shared.dto.NewSnapshotDescriptor; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class NewSnapshotDescriptorImpl implements org.eclipse.che.api.machine.shared.dto.NewSnapshotDescriptor { + + description : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + + } + + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withDescription(description : string) : org.eclipse.che.api.machine.shared.dto.NewSnapshotDescriptor { + this.description = description; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.description) { + json.description = this.description; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export interface JsonRpcObject { + withType(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; + withMessage(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject; + getMessage(): string; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export class JsonRpcObjectImpl implements org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject { + + type : string; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + withType(type : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject { + this.type = type; + return this; + } + withMessage(message : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcObject { + this.message = message; + return this; + } + getMessage() : string { + return this.message; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.type) { + json.type = this.type; + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface RebaseResponse { + getStatus(): string; + setStatus(arg0): void; + withStatus(arg0): org.eclipse.che.api.git.shared.RebaseResponse; + getConflicts(): Array; + setConflicts(arg0): void; + withConflicts(arg0): org.eclipse.che.api.git.shared.RebaseResponse; + getFailed(): Array; + setFailed(arg0): void; + withFailed(arg0): org.eclipse.che.api.git.shared.RebaseResponse; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class RebaseResponseImpl implements org.eclipse.che.api.git.shared.RebaseResponse { + + conflicts : Array; + failed : Array; + status : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.conflicts = new Array(); + if (__jsonObject) { + if (__jsonObject.conflicts) { + __jsonObject.conflicts.forEach((item) => { + this.conflicts.push(item); + }); + } + } + this.failed = new Array(); + if (__jsonObject) { + if (__jsonObject.failed) { + __jsonObject.failed.forEach((item) => { + this.failed.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.status) { + this.status = __jsonObject.status; + } + } + + } + + getStatus() : string { + return this.status; + } + setStatus(status : string) : void { + this.status = status; + } + withStatus(status : string) : org.eclipse.che.api.git.shared.RebaseResponse { + this.status = status; + return this; + } + getConflicts() : Array { + return this.conflicts; + } + setConflicts(conflicts : Array) : void { + this.conflicts = conflicts; + } + withConflicts(conflicts : Array) : org.eclipse.che.api.git.shared.RebaseResponse { + this.conflicts = conflicts; + return this; + } + getFailed() : Array { + return this.failed; + } + setFailed(failed : Array) : void { + this.failed = failed; + } + withFailed(failed : Array) : org.eclipse.che.api.git.shared.RebaseResponse { + this.failed = failed; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.conflicts) { + let listArray = []; + this.conflicts.forEach((item) => { + listArray.push(item); + json.conflicts = listArray; + }); + } + if (this.failed) { + let listArray = []; + this.failed.forEach((item) => { + listArray.push(item); + json.failed = listArray; + }); + } + if (this.status) { + json.status = this.status; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface LocationDto { + setLineNumber(arg0): void; + withTarget(arg0): org.eclipse.che.api.debug.shared.dto.LocationDto; + withLineNumber(arg0): org.eclipse.che.api.debug.shared.dto.LocationDto; + setExternalResource(arg0): void; + setResourcePath(arg0): void; + withResourcePath(arg0): org.eclipse.che.api.debug.shared.dto.LocationDto; + withExternalResource(arg0): org.eclipse.che.api.debug.shared.dto.LocationDto; + setExternalResourceId(arg0): void; + withExternalResourceId(arg0): org.eclipse.che.api.debug.shared.dto.LocationDto; + setResourceProjectPath(arg0): void; + withResourceProjectPath(arg0): org.eclipse.che.api.debug.shared.dto.LocationDto; + setTarget(arg0): void; + getResourcePath(): string; + isExternalResource(): boolean; + getExternalResourceId(): number; + getResourceProjectPath(): string; + getTarget(): string; + getLineNumber(): number; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class LocationDtoImpl implements org.eclipse.che.api.debug.shared.dto.LocationDto { + + externalResourceId : number; + resourcePath : string; + externalResource : boolean; + resourceProjectPath : string; + lineNumber : number; + target : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.externalResourceId) { + this.externalResourceId = __jsonObject.externalResourceId; + } + } + if (__jsonObject) { + if (__jsonObject.resourcePath) { + this.resourcePath = __jsonObject.resourcePath; + } + } + if (__jsonObject) { + if (__jsonObject.externalResource) { + this.externalResource = __jsonObject.externalResource; + } + } + if (__jsonObject) { + if (__jsonObject.resourceProjectPath) { + this.resourceProjectPath = __jsonObject.resourceProjectPath; + } + } + if (__jsonObject) { + if (__jsonObject.lineNumber) { + this.lineNumber = __jsonObject.lineNumber; + } + } + if (__jsonObject) { + if (__jsonObject.target) { + this.target = __jsonObject.target; + } + } + + } + + setLineNumber(lineNumber : number) : void { + this.lineNumber = lineNumber; + } + withTarget(target : string) : org.eclipse.che.api.debug.shared.dto.LocationDto { + this.target = target; + return this; + } + withLineNumber(lineNumber : number) : org.eclipse.che.api.debug.shared.dto.LocationDto { + this.lineNumber = lineNumber; + return this; + } + setExternalResource(externalResource : boolean) : void { + this.externalResource = externalResource; + } + setResourcePath(resourcePath : string) : void { + this.resourcePath = resourcePath; + } + withResourcePath(resourcePath : string) : org.eclipse.che.api.debug.shared.dto.LocationDto { + this.resourcePath = resourcePath; + return this; + } + withExternalResource(externalResource : boolean) : org.eclipse.che.api.debug.shared.dto.LocationDto { + this.externalResource = externalResource; + return this; + } + setExternalResourceId(externalResourceId : number) : void { + this.externalResourceId = externalResourceId; + } + withExternalResourceId(externalResourceId : number) : org.eclipse.che.api.debug.shared.dto.LocationDto { + this.externalResourceId = externalResourceId; + return this; + } + setResourceProjectPath(resourceProjectPath : string) : void { + this.resourceProjectPath = resourceProjectPath; + } + withResourceProjectPath(resourceProjectPath : string) : org.eclipse.che.api.debug.shared.dto.LocationDto { + this.resourceProjectPath = resourceProjectPath; + return this; + } + setTarget(target : string) : void { + this.target = target; + } + getResourcePath() : string { + return this.resourcePath; + } + isExternalResource() : boolean { + return this.externalResource; + } + getExternalResourceId() : number { + return this.externalResourceId; + } + getResourceProjectPath() : string { + return this.resourceProjectPath; + } + getTarget() : string { + return this.target; + } + getLineNumber() : number { + return this.lineNumber; + } + + toJson() : any { + let json : any = {}; + + if (this.externalResourceId) { + json.externalResourceId = this.externalResourceId; + } + if (this.resourcePath) { + json.resourcePath = this.resourcePath; + } + if (this.externalResource) { + json.externalResource = this.externalResource; + } + if (this.resourceProjectPath) { + json.resourceProjectPath = this.resourceProjectPath; + } + if (this.lineNumber) { + json.lineNumber = this.lineNumber; + } + if (this.target) { + json.target = this.target; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export interface JsonRpcRequest { + getParams(): string; + withMethod(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; + withParams(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; + getJsonrpc(): string; + withJsonrpc(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; + withId(arg0): org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest; + getMethod(): string; + getId(): number; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.jsonrpc.shared { + + export class JsonRpcRequestImpl implements org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest { + + method : string; + id : number; + params : string; + jsonrpc : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.method) { + this.method = __jsonObject.method; + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.params) { + this.params = __jsonObject.params; + } + } + if (__jsonObject) { + if (__jsonObject.jsonrpc) { + this.jsonrpc = __jsonObject.jsonrpc; + } + } + + } + + getParams() : string { + return this.params; + } + withMethod(method : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest { + this.method = method; + return this; + } + withParams(params : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest { + this.params = params; + return this; + } + getJsonrpc() : string { + return this.jsonrpc; + } + withJsonrpc(jsonrpc : string) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest { + this.jsonrpc = jsonrpc; + return this; + } + withId(id : number) : org.eclipse.che.api.core.jsonrpc.shared.JsonRpcRequest { + this.id = id; + return this; + } + getMethod() : string { + return this.method; + } + getId() : number { + return this.id; + } + + toJson() : any { + let json : any = {}; + + if (this.method) { + json.method = this.method; + } + if (this.id) { + json.id = this.id; + } + if (this.params) { + json.params = this.params; + } + if (this.jsonrpc) { + json.jsonrpc = this.jsonrpc; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface OnAppClosedDto { + setActions(arg0): void; + withActions(arg0): org.eclipse.che.api.factory.shared.dto.OnAppClosedDto; + getActions(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class OnAppClosedDtoImpl implements org.eclipse.che.api.factory.shared.dto.OnAppClosedDto { + + actions : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.actions = new Array(); + if (__jsonObject) { + if (__jsonObject.actions) { + __jsonObject.actions.forEach((item) => { + this.actions.push(new org.eclipse.che.api.factory.shared.dto.IdeActionDtoImpl(item)); + }); + } + } + + } + + setActions(actions : Array) : void { + this.actions = actions; + } + withActions(actions : Array) : org.eclipse.che.api.factory.shared.dto.OnAppClosedDto { + this.actions = actions; + return this; + } + getActions() : Array { + return this.actions; + } + + toJson() : any { + let json : any = {}; + + if (this.actions) { + let listArray = []; + this.actions.forEach((item) => { + listArray.push((item as org.eclipse.che.api.factory.shared.dto.IdeActionDtoImpl).toJson()); + json.actions = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface IdeDto { + withOnAppClosed(arg0): org.eclipse.che.api.factory.shared.dto.IdeDto; + setOnAppLoaded(arg0): void; + withOnAppLoaded(arg0): org.eclipse.che.api.factory.shared.dto.IdeDto; + getOnAppClosed(): org.eclipse.che.api.factory.shared.dto.OnAppClosedDto; + getOnAppLoaded(): org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto; + setOnAppClosed(arg0): void; + getOnProjectsLoaded(): org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto; + setOnProjectsLoaded(arg0): void; + withOnProjectsLoaded(arg0): org.eclipse.che.api.factory.shared.dto.IdeDto; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class IdeDtoImpl implements org.eclipse.che.api.factory.shared.dto.IdeDto { + + onAppLoaded : org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto; + onProjectsLoaded : org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto; + onAppClosed : org.eclipse.che.api.factory.shared.dto.OnAppClosedDto; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.onAppLoaded) { + this.onAppLoaded = new org.eclipse.che.api.factory.shared.dto.OnAppLoadedDtoImpl(__jsonObject.onAppLoaded); + } + } + if (__jsonObject) { + if (__jsonObject.onProjectsLoaded) { + this.onProjectsLoaded = new org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDtoImpl(__jsonObject.onProjectsLoaded); + } + } + if (__jsonObject) { + if (__jsonObject.onAppClosed) { + this.onAppClosed = new org.eclipse.che.api.factory.shared.dto.OnAppClosedDtoImpl(__jsonObject.onAppClosed); + } + } + + } + + withOnAppClosed(onAppClosed : org.eclipse.che.api.factory.shared.dto.OnAppClosedDto) : org.eclipse.che.api.factory.shared.dto.IdeDto { + this.onAppClosed = onAppClosed; + return this; + } + setOnAppLoaded(onAppLoaded : org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto) : void { + this.onAppLoaded = onAppLoaded; + } + withOnAppLoaded(onAppLoaded : org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto) : org.eclipse.che.api.factory.shared.dto.IdeDto { + this.onAppLoaded = onAppLoaded; + return this; + } + getOnAppClosed() : org.eclipse.che.api.factory.shared.dto.OnAppClosedDto { + return this.onAppClosed; + } + getOnAppLoaded() : org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto { + return this.onAppLoaded; + } + setOnAppClosed(onAppClosed : org.eclipse.che.api.factory.shared.dto.OnAppClosedDto) : void { + this.onAppClosed = onAppClosed; + } + getOnProjectsLoaded() : org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto { + return this.onProjectsLoaded; + } + setOnProjectsLoaded(onProjectsLoaded : org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto) : void { + this.onProjectsLoaded = onProjectsLoaded; + } + withOnProjectsLoaded(onProjectsLoaded : org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto) : org.eclipse.che.api.factory.shared.dto.IdeDto { + this.onProjectsLoaded = onProjectsLoaded; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.onAppLoaded) { + json.onAppLoaded = (this.onAppLoaded as org.eclipse.che.api.factory.shared.dto.OnAppLoadedDtoImpl).toJson(); + } + if (this.onProjectsLoaded) { + json.onProjectsLoaded = (this.onProjectsLoaded as org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDtoImpl).toJson(); + } + if (this.onAppClosed) { + json.onAppClosed = (this.onAppClosed as org.eclipse.che.api.factory.shared.dto.OnAppClosedDtoImpl).toJson(); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface MachineDto { + getConfig(): org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + getLinks(): Array; + withLinks(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + withStatus(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + withId(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + withWorkspaceId(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + withConfig(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + withEnvName(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + withOwner(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + withRuntime(arg0): org.eclipse.che.api.machine.shared.dto.MachineDto; + getRuntime(): org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto; + getStatus(): string; + getWorkspaceId(): string; + getEnvName(): string; + getId(): string; + getOwner(): string; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class MachineDtoImpl implements org.eclipse.che.api.machine.shared.dto.MachineDto { + + owner : string; + envName : string; + runtime : org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto; + links : Array; + id : string; + config : org.eclipse.che.api.machine.shared.dto.MachineConfigDto; + status : string; + workspaceId : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.owner) { + this.owner = __jsonObject.owner; + } + } + if (__jsonObject) { + if (__jsonObject.envName) { + this.envName = __jsonObject.envName; + } + } + if (__jsonObject) { + if (__jsonObject.runtime) { + this.runtime = new org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDtoImpl(__jsonObject.runtime); + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + if (__jsonObject) { + if (__jsonObject.config) { + this.config = new org.eclipse.che.api.machine.shared.dto.MachineConfigDtoImpl(__jsonObject.config); + } + } + if (__jsonObject) { + if (__jsonObject.status) { + this.status = __jsonObject.status; + } + } + if (__jsonObject) { + if (__jsonObject.workspaceId) { + this.workspaceId = __jsonObject.workspaceId; + } + } + + } + + getConfig() : org.eclipse.che.api.machine.shared.dto.MachineConfigDto { + return this.config; + } + getLinks() : Array { + return this.links; + } + withLinks(links : Array) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.links = links; + return this; + } + withStatus(status : string) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.status = status; + return this; + } + withId(id : string) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.id = id; + return this; + } + withWorkspaceId(workspaceId : string) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.workspaceId = workspaceId; + return this; + } + withConfig(config : org.eclipse.che.api.machine.shared.dto.MachineConfigDto) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.config = config; + return this; + } + withEnvName(envName : string) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.envName = envName; + return this; + } + withOwner(owner : string) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.owner = owner; + return this; + } + withRuntime(runtime : org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto) : org.eclipse.che.api.machine.shared.dto.MachineDto { + this.runtime = runtime; + return this; + } + getRuntime() : org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto { + return this.runtime; + } + getStatus() : string { + return this.status; + } + getWorkspaceId() : string { + return this.workspaceId; + } + getEnvName() : string { + return this.envName; + } + getId() : string { + return this.id; + } + getOwner() : string { + return this.owner; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.owner) { + json.owner = this.owner; + } + if (this.envName) { + json.envName = this.envName; + } + if (this.runtime) { + json.runtime = (this.runtime as org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDtoImpl).toJson(); + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.id) { + json.id = this.id; + } + if (this.config) { + json.config = (this.config as org.eclipse.che.api.machine.shared.dto.MachineConfigDtoImpl).toJson(); + } + if (this.status) { + json.status = this.status; + } + if (this.workspaceId) { + json.workspaceId = this.workspaceId; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface MergeRequest { + setCommit(arg0): void; + withCommit(arg0): org.eclipse.che.api.git.shared.MergeRequest; + getCommit(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class MergeRequestImpl implements org.eclipse.che.api.git.shared.MergeRequest { + + commit : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.commit) { + this.commit = __jsonObject.commit; + } + } + + } + + setCommit(commit : string) : void { + this.commit = commit; + } + withCommit(commit : string) : org.eclipse.che.api.git.shared.MergeRequest { + this.commit = commit; + return this; + } + getCommit() : string { + return this.commit; + } + + toJson() : any { + let json : any = {}; + + if (this.commit) { + json.commit = this.commit; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto.event { + + export interface MachineProcessEvent { + getEventType(): string; + getError(): string; + setEventType(arg0): void; + withError(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent; + withEventType(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent; + getProcessId(): number; + getMachineId(): string; + setMachineId(arg0): void; + withMachineId(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent; + setProcessId(arg0): void; + withProcessId(arg0): org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent; + setError(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto.event { + + export class MachineProcessEventImpl implements org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent { + + machineId : string; + processId : number; + eventType : string; + error : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.machineId) { + this.machineId = __jsonObject.machineId; + } + } + if (__jsonObject) { + if (__jsonObject.processId) { + this.processId = __jsonObject.processId; + } + } + if (__jsonObject) { + if (__jsonObject.eventType) { + this.eventType = __jsonObject.eventType; + } + } + if (__jsonObject) { + if (__jsonObject.error) { + this.error = __jsonObject.error; + } + } + + } + + getEventType() : string { + return this.eventType; + } + getError() : string { + return this.error; + } + setEventType(eventType : string) : void { + this.eventType = eventType; + } + withError(error : string) : org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent { + this.error = error; + return this; + } + withEventType(eventType : string) : org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent { + this.eventType = eventType; + return this; + } + getProcessId() : number { + return this.processId; + } + getMachineId() : string { + return this.machineId; + } + setMachineId(machineId : string) : void { + this.machineId = machineId; + } + withMachineId(machineId : string) : org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent { + this.machineId = machineId; + return this; + } + setProcessId(processId : number) : void { + this.processId = processId; + } + withProcessId(processId : number) : org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent { + this.processId = processId; + return this; + } + setError(error : string) : void { + this.error = error; + } + + toJson() : any { + let json : any = {}; + + if (this.machineId) { + json.machineId = this.machineId; + } + if (this.processId) { + json.processId = this.processId; + } + if (this.eventType) { + json.eventType = this.eventType; + } + if (this.error) { + json.error = this.error; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.ssh.shared.dto { + + export interface SshPairDto { + setPrivateKey(arg0): void; + getService(): string; + getPrivateKey(): string; + withName(arg0): org.eclipse.che.api.ssh.shared.dto.SshPairDto; + withPublicKey(arg0): org.eclipse.che.api.ssh.shared.dto.SshPairDto; + withPrivateKey(arg0): org.eclipse.che.api.ssh.shared.dto.SshPairDto; + withLinks(arg0): org.eclipse.che.api.ssh.shared.dto.SshPairDto; + setService(arg0): void; + withService(arg0): org.eclipse.che.api.ssh.shared.dto.SshPairDto; + setPublicKey(arg0): void; + getName(): string; + setName(arg0): void; + getPublicKey(): string; + getLinks(): Array; + setLinks(arg0): void; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.ssh.shared.dto { + + export class SshPairDtoImpl implements org.eclipse.che.api.ssh.shared.dto.SshPairDto { + + privateKey : string; + service : string; + name : string; + links : Array; + publicKey : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.privateKey) { + this.privateKey = __jsonObject.privateKey; + } + } + if (__jsonObject) { + if (__jsonObject.service) { + this.service = __jsonObject.service; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + this.links = new Array(); + if (__jsonObject) { + if (__jsonObject.links) { + __jsonObject.links.forEach((item) => { + this.links.push(new org.eclipse.che.api.core.rest.shared.dto.LinkImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.publicKey) { + this.publicKey = __jsonObject.publicKey; + } + } + + } + + setPrivateKey(privateKey : string) : void { + this.privateKey = privateKey; + } + getService() : string { + return this.service; + } + getPrivateKey() : string { + return this.privateKey; + } + withName(name : string) : org.eclipse.che.api.ssh.shared.dto.SshPairDto { + this.name = name; + return this; + } + withPublicKey(publicKey : string) : org.eclipse.che.api.ssh.shared.dto.SshPairDto { + this.publicKey = publicKey; + return this; + } + withPrivateKey(privateKey : string) : org.eclipse.che.api.ssh.shared.dto.SshPairDto { + this.privateKey = privateKey; + return this; + } + withLinks(links : Array) : org.eclipse.che.api.ssh.shared.dto.SshPairDto { + this.links = links; + return this; + } + setService(service : string) : void { + this.service = service; + } + withService(service : string) : org.eclipse.che.api.ssh.shared.dto.SshPairDto { + this.service = service; + return this; + } + setPublicKey(publicKey : string) : void { + this.publicKey = publicKey; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getPublicKey() : string { + return this.publicKey; + } + getLinks() : Array { + return this.links; + } + setLinks(links : Array) : void { + this.links = links; + } + + toJson() : any { + let json : any = {}; + + if (this.privateKey) { + json.privateKey = this.privateKey; + } + if (this.service) { + json.service = this.service; + } + if (this.name) { + json.name = this.name; + } + if (this.links) { + let listArray = []; + this.links.forEach((item) => { + listArray.push((item as org.eclipse.che.api.core.rest.shared.dto.LinkImpl).toJson()); + json.links = listArray; + }); + } + if (this.publicKey) { + json.publicKey = this.publicKey; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface VariableDto { + withType(arg0): org.eclipse.che.api.debug.shared.dto.VariableDto; + setType(arg0): void; + withName(arg0): org.eclipse.che.api.debug.shared.dto.VariableDto; + getVariables(): Array; + setVariables(arg0): void; + withVariables(arg0): org.eclipse.che.api.debug.shared.dto.VariableDto; + withValue(arg0): org.eclipse.che.api.debug.shared.dto.VariableDto; + isExistInformation(): boolean; + setExistInformation(arg0): void; + withExistInformation(arg0): org.eclipse.che.api.debug.shared.dto.VariableDto; + getVariablePath(): org.eclipse.che.api.debug.shared.dto.VariablePathDto; + setVariablePath(arg0): void; + withVariablePath(arg0): org.eclipse.che.api.debug.shared.dto.VariableDto; + setPrimitive(arg0): void; + withPrimitive(arg0): org.eclipse.che.api.debug.shared.dto.VariableDto; + isPrimitive(): boolean; + getName(): string; + getValue(): string; + setName(arg0): void; + setValue(arg0): void; + getType(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class VariableDtoImpl implements org.eclipse.che.api.debug.shared.dto.VariableDto { + + variables : Array; + variablePath : org.eclipse.che.api.debug.shared.dto.VariablePathDto; + primitive : boolean; + name : string; + type : string; + existInformation : boolean; + value : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.variables = new Array(); + if (__jsonObject) { + if (__jsonObject.variables) { + __jsonObject.variables.forEach((item) => { + this.variables.push(new org.eclipse.che.api.debug.shared.dto.VariableDtoImpl(item)); + }); + } + } + if (__jsonObject) { + if (__jsonObject.variablePath) { + this.variablePath = new org.eclipse.che.api.debug.shared.dto.VariablePathDtoImpl(__jsonObject.variablePath); + } + } + if (__jsonObject) { + if (__jsonObject.primitive) { + this.primitive = __jsonObject.primitive; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.existInformation) { + this.existInformation = __jsonObject.existInformation; + } + } + if (__jsonObject) { + if (__jsonObject.value) { + this.value = __jsonObject.value; + } + } + + } + + withType(type : string) : org.eclipse.che.api.debug.shared.dto.VariableDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withName(name : string) : org.eclipse.che.api.debug.shared.dto.VariableDto { + this.name = name; + return this; + } + getVariables() : Array { + return this.variables; + } + setVariables(variables : Array) : void { + this.variables = variables; + } + withVariables(variables : Array) : org.eclipse.che.api.debug.shared.dto.VariableDto { + this.variables = variables; + return this; + } + withValue(value : string) : org.eclipse.che.api.debug.shared.dto.VariableDto { + this.value = value; + return this; + } + isExistInformation() : boolean { + return this.existInformation; + } + setExistInformation(existInformation : boolean) : void { + this.existInformation = existInformation; + } + withExistInformation(existInformation : boolean) : org.eclipse.che.api.debug.shared.dto.VariableDto { + this.existInformation = existInformation; + return this; + } + getVariablePath() : org.eclipse.che.api.debug.shared.dto.VariablePathDto { + return this.variablePath; + } + setVariablePath(variablePath : org.eclipse.che.api.debug.shared.dto.VariablePathDto) : void { + this.variablePath = variablePath; + } + withVariablePath(variablePath : org.eclipse.che.api.debug.shared.dto.VariablePathDto) : org.eclipse.che.api.debug.shared.dto.VariableDto { + this.variablePath = variablePath; + return this; + } + setPrimitive(primitive : boolean) : void { + this.primitive = primitive; + } + withPrimitive(primitive : boolean) : org.eclipse.che.api.debug.shared.dto.VariableDto { + this.primitive = primitive; + return this; + } + isPrimitive() : boolean { + return this.primitive; + } + getName() : string { + return this.name; + } + getValue() : string { + return this.value; + } + setName(name : string) : void { + this.name = name; + } + setValue(value : string) : void { + this.value = value; + } + getType() : string { + return this.type; + } + + toJson() : any { + let json : any = {}; + + if (this.variables) { + let listArray = []; + this.variables.forEach((item) => { + listArray.push((item as org.eclipse.che.api.debug.shared.dto.VariableDtoImpl).toJson()); + json.variables = listArray; + }); + } + if (this.variablePath) { + json.variablePath = (this.variablePath as org.eclipse.che.api.debug.shared.dto.VariablePathDtoImpl).toJson(); + } + if (this.primitive) { + json.primitive = this.primitive; + } + if (this.name) { + json.name = this.name; + } + if (this.type) { + json.type = this.type; + } + if (this.existInformation) { + json.existInformation = this.existInformation; + } + if (this.value) { + json.value = this.value; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface PushResponse { + getCommandOutput(): string; + withUpdates(arg0): org.eclipse.che.api.git.shared.PushResponse; + setUpdates(arg0): void; + getUpdates(): Array>; + setCommandOutput(arg0): void; + withCommandOutput(arg0): org.eclipse.che.api.git.shared.PushResponse; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class PushResponseImpl implements org.eclipse.che.api.git.shared.PushResponse { + + commandOutput : string; + updates : Array>; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.commandOutput) { + this.commandOutput = __jsonObject.commandOutput; + } + } + this.updates = new Array>(); + if (__jsonObject) { + if (__jsonObject.updates) { + __jsonObject.updates.forEach((item) => { + this.updates.push(item); + }); + } + } + + } + + getCommandOutput() : string { + return this.commandOutput; + } + withUpdates(updates : Array>) : org.eclipse.che.api.git.shared.PushResponse { + this.updates = updates; + return this; + } + setUpdates(updates : Array>) : void { + this.updates = updates; + } + getUpdates() : Array> { + return this.updates; + } + setCommandOutput(commandOutput : string) : void { + this.commandOutput = commandOutput; + } + withCommandOutput(commandOutput : string) : org.eclipse.che.api.git.shared.PushResponse { + this.commandOutput = commandOutput; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.commandOutput) { + json.commandOutput = this.commandOutput; + } + if (this.updates) { + let listArray = []; + this.updates.forEach((item) => { + listArray.push(item); + json.updates = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export interface ServerDto { + getUrl(): string; + setUrl(arg0): void; + setProtocol(arg0): void; + setAddress(arg0): void; + withProperties(arg0): org.eclipse.che.api.machine.shared.dto.ServerDto; + withRef(arg0): org.eclipse.che.api.machine.shared.dto.ServerDto; + withProtocol(arg0): org.eclipse.che.api.machine.shared.dto.ServerDto; + setRef(arg0): void; + withUrl(arg0): org.eclipse.che.api.machine.shared.dto.ServerDto; + withAddress(arg0): org.eclipse.che.api.machine.shared.dto.ServerDto; + getAddress(): string; + getProperties(): org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto; + setProperties(arg0): void; + getProtocol(): string; + getRef(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.machine.shared.dto { + + export class ServerDtoImpl implements org.eclipse.che.api.machine.shared.dto.ServerDto { + + protocol : string; + ref : string; + address : string; + url : string; + properties : org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.protocol) { + this.protocol = __jsonObject.protocol; + } + } + if (__jsonObject) { + if (__jsonObject.ref) { + this.ref = __jsonObject.ref; + } + } + if (__jsonObject) { + if (__jsonObject.address) { + this.address = __jsonObject.address; + } + } + if (__jsonObject) { + if (__jsonObject.url) { + this.url = __jsonObject.url; + } + } + if (__jsonObject) { + if (__jsonObject.properties) { + this.properties = new org.eclipse.che.api.machine.shared.dto.ServerPropertiesDtoImpl(__jsonObject.properties); + } + } + + } + + getUrl() : string { + return this.url; + } + setUrl(url : string) : void { + this.url = url; + } + setProtocol(protocol : string) : void { + this.protocol = protocol; + } + setAddress(address : string) : void { + this.address = address; + } + withProperties(properties : org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto) : org.eclipse.che.api.machine.shared.dto.ServerDto { + this.properties = properties; + return this; + } + withRef(ref : string) : org.eclipse.che.api.machine.shared.dto.ServerDto { + this.ref = ref; + return this; + } + withProtocol(protocol : string) : org.eclipse.che.api.machine.shared.dto.ServerDto { + this.protocol = protocol; + return this; + } + setRef(ref : string) : void { + this.ref = ref; + } + withUrl(url : string) : org.eclipse.che.api.machine.shared.dto.ServerDto { + this.url = url; + return this; + } + withAddress(address : string) : org.eclipse.che.api.machine.shared.dto.ServerDto { + this.address = address; + return this; + } + getAddress() : string { + return this.address; + } + getProperties() : org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto { + return this.properties; + } + setProperties(properties : org.eclipse.che.api.machine.shared.dto.ServerPropertiesDto) : void { + this.properties = properties; + } + getProtocol() : string { + return this.protocol; + } + getRef() : string { + return this.ref; + } + + toJson() : any { + let json : any = {}; + + if (this.protocol) { + json.protocol = this.protocol; + } + if (this.ref) { + json.ref = this.ref; + } + if (this.address) { + json.address = this.address; + } + if (this.url) { + json.url = this.url; + } + if (this.properties) { + json.properties = (this.properties as org.eclipse.che.api.machine.shared.dto.ServerPropertiesDtoImpl).toJson(); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.websocket.shared { + + export interface WebSocketTransmission { + withMessage(arg0): org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; + withProtocol(arg0): org.eclipse.che.api.core.websocket.shared.WebSocketTransmission; + getMessage(): string; + getProtocol(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.websocket.shared { + + export class WebSocketTransmissionImpl implements org.eclipse.che.api.core.websocket.shared.WebSocketTransmission { + + protocol : string; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.protocol) { + this.protocol = __jsonObject.protocol; + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + withMessage(message : string) : org.eclipse.che.api.core.websocket.shared.WebSocketTransmission { + this.message = message; + return this; + } + withProtocol(protocol : string) : org.eclipse.che.api.core.websocket.shared.WebSocketTransmission { + this.protocol = protocol; + return this; + } + getMessage() : string { + return this.message; + } + getProtocol() : string { + return this.protocol; + } + + toJson() : any { + let json : any = {}; + + if (this.protocol) { + json.protocol = this.protocol; + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface SourceStorageDto { + setParameters(arg0): void; + withType(arg0): org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; + setType(arg0): void; + setLocation(arg0): void; + withParameters(arg0): org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; + withLocation(arg0): org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; + getLocation(): string; + getType(): string; + getParameters(): Map; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class SourceStorageDtoImpl implements org.eclipse.che.api.workspace.shared.dto.SourceStorageDto { + + location : string; + type : string; + parameters : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.location) { + this.location = __jsonObject.location; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + this.parameters = new Map(); + if (__jsonObject) { + if (__jsonObject.parameters) { + let tmp : Array = Object.keys(__jsonObject.parameters); + tmp.forEach((key) => { + this.parameters.set(key, __jsonObject.parameters[key]); + }); + } + } + + } + + setParameters(parameters : Map) : void { + this.parameters = parameters; + } + withType(type : string) : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + setLocation(location : string) : void { + this.location = location; + } + withParameters(parameters : Map) : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto { + this.parameters = parameters; + return this; + } + withLocation(location : string) : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto { + this.location = location; + return this; + } + getLocation() : string { + return this.location; + } + getType() : string { + return this.type; + } + getParameters() : Map { + return this.parameters; + } + + toJson() : any { + let json : any = {}; + + if (this.location) { + json.location = this.location; + } + if (this.type) { + json.type = this.type; + } + if (this.parameters) { + let tmpMap : any = {}; + for (const [key, value] of this.parameters.entries()) { + tmpMap[key] = value; + } + json.parameters = tmpMap; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface ConflictExceptionError { + setMessage(arg0): void; + withMessage(arg0): org.eclipse.che.api.git.shared.ConflictExceptionError; + getConflictingPaths(): Array; + withConflictingPaths(arg0): org.eclipse.che.api.git.shared.ConflictExceptionError; + setConflictingPaths(arg0): void; + getMessage(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class ConflictExceptionErrorImpl implements org.eclipse.che.api.git.shared.ConflictExceptionError { + + conflictingPaths : Array; + message : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.conflictingPaths = new Array(); + if (__jsonObject) { + if (__jsonObject.conflictingPaths) { + __jsonObject.conflictingPaths.forEach((item) => { + this.conflictingPaths.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.message) { + this.message = __jsonObject.message; + } + } + + } + + setMessage(message : string) : void { + this.message = message; + } + withMessage(message : string) : org.eclipse.che.api.git.shared.ConflictExceptionError { + this.message = message; + return this; + } + getConflictingPaths() : Array { + return this.conflictingPaths; + } + withConflictingPaths(conflictingPaths : Array) : org.eclipse.che.api.git.shared.ConflictExceptionError { + this.conflictingPaths = conflictingPaths; + return this; + } + setConflictingPaths(conflictingPaths : Array) : void { + this.conflictingPaths = conflictingPaths; + } + getMessage() : string { + return this.message; + } + + toJson() : any { + let json : any = {}; + + if (this.conflictingPaths) { + let listArray = []; + this.conflictingPaths.forEach((item) => { + listArray.push(item); + json.conflictingPaths = listArray; + }); + } + if (this.message) { + json.message = this.message; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export interface IdeActionDto { + setId(arg0): void; + withId(arg0): org.eclipse.che.api.factory.shared.dto.IdeActionDto; + withProperties(arg0): org.eclipse.che.api.factory.shared.dto.IdeActionDto; + getProperties(): Map; + setProperties(arg0): void; + getId(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.factory.shared.dto { + + export class IdeActionDtoImpl implements org.eclipse.che.api.factory.shared.dto.IdeActionDto { + + id : string; + properties : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.id) { + this.id = __jsonObject.id; + } + } + this.properties = new Map(); + if (__jsonObject) { + if (__jsonObject.properties) { + let tmp : Array = Object.keys(__jsonObject.properties); + tmp.forEach((key) => { + this.properties.set(key, __jsonObject.properties[key]); + }); + } + } + + } + + setId(id : string) : void { + this.id = id; + } + withId(id : string) : org.eclipse.che.api.factory.shared.dto.IdeActionDto { + this.id = id; + return this; + } + withProperties(properties : Map) : org.eclipse.che.api.factory.shared.dto.IdeActionDto { + this.properties = properties; + return this; + } + getProperties() : Map { + return this.properties; + } + setProperties(properties : Map) : void { + this.properties = properties; + } + getId() : string { + return this.id; + } + + toJson() : any { + let json : any = {}; + + if (this.id) { + json.id = this.id; + } + if (this.properties) { + let tmpMap : any = {}; + for (const [key, value] of this.properties.entries()) { + tmpMap[key] = value; + } + json.properties = tmpMap; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export interface LinkParameter { + isRequired(): boolean; + setRequired(arg0): void; + getDescription(): string; + setDescription(arg0): void; + withType(arg0): org.eclipse.che.api.core.rest.shared.dto.LinkParameter; + setType(arg0): void; + withDescription(arg0): org.eclipse.che.api.core.rest.shared.dto.LinkParameter; + setDefaultValue(arg0): void; + withName(arg0): org.eclipse.che.api.core.rest.shared.dto.LinkParameter; + withDefaultValue(arg0): org.eclipse.che.api.core.rest.shared.dto.LinkParameter; + withRequired(arg0): org.eclipse.che.api.core.rest.shared.dto.LinkParameter; + getValid(): Array; + withValid(arg0): org.eclipse.che.api.core.rest.shared.dto.LinkParameter; + setValid(arg0): void; + getName(): string; + setName(arg0): void; + getType(): string; + getDefaultValue(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.core.rest.shared.dto { + + export class LinkParameterImpl implements org.eclipse.che.api.core.rest.shared.dto.LinkParameter { + + valid : Array; + defaultValue : string; + name : string; + description : string; + type : string; + required : boolean; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.valid = new Array(); + if (__jsonObject) { + if (__jsonObject.valid) { + __jsonObject.valid.forEach((item) => { + this.valid.push(item); + }); + } + } + if (__jsonObject) { + if (__jsonObject.defaultValue) { + this.defaultValue = __jsonObject.defaultValue; + } + } + if (__jsonObject) { + if (__jsonObject.name) { + this.name = __jsonObject.name; + } + } + if (__jsonObject) { + if (__jsonObject.description) { + this.description = __jsonObject.description; + } + } + if (__jsonObject) { + if (__jsonObject.type) { + this.type = __jsonObject.type; + } + } + if (__jsonObject) { + if (__jsonObject.required) { + this.required = __jsonObject.required; + } + } + + } + + isRequired() : boolean { + return this.required; + } + setRequired(required : boolean) : void { + this.required = required; + } + getDescription() : string { + return this.description; + } + setDescription(description : string) : void { + this.description = description; + } + withType(type : string) : org.eclipse.che.api.core.rest.shared.dto.LinkParameter { + this.type = type; + return this; + } + setType(type : string) : void { + this.type = type; + } + withDescription(description : string) : org.eclipse.che.api.core.rest.shared.dto.LinkParameter { + this.description = description; + return this; + } + setDefaultValue(defaultValue : string) : void { + this.defaultValue = defaultValue; + } + withName(name : string) : org.eclipse.che.api.core.rest.shared.dto.LinkParameter { + this.name = name; + return this; + } + withDefaultValue(defaultValue : string) : org.eclipse.che.api.core.rest.shared.dto.LinkParameter { + this.defaultValue = defaultValue; + return this; + } + withRequired(required : boolean) : org.eclipse.che.api.core.rest.shared.dto.LinkParameter { + this.required = required; + return this; + } + getValid() : Array { + return this.valid; + } + withValid(valid : Array) : org.eclipse.che.api.core.rest.shared.dto.LinkParameter { + this.valid = valid; + return this; + } + setValid(valid : Array) : void { + this.valid = valid; + } + getName() : string { + return this.name; + } + setName(name : string) : void { + this.name = name; + } + getType() : string { + return this.type; + } + getDefaultValue() : string { + return this.defaultValue; + } + + toJson() : any { + let json : any = {}; + + if (this.valid) { + let listArray = []; + this.valid.forEach((item) => { + listArray.push(item); + json.valid = listArray; + }); + } + if (this.defaultValue) { + json.defaultValue = this.defaultValue; + } + if (this.name) { + json.name = this.name; + } + if (this.description) { + json.description = this.description; + } + if (this.type) { + json.type = this.type; + } + if (this.required) { + json.required = this.required; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export interface VariablePathDto { + setPath(arg0): void; + withPath(arg0): org.eclipse.che.api.debug.shared.dto.VariablePathDto; + getPath(): Array; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.debug.shared.dto { + + export class VariablePathDtoImpl implements org.eclipse.che.api.debug.shared.dto.VariablePathDto { + + path : Array; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + this.path = new Array(); + if (__jsonObject) { + if (__jsonObject.path) { + __jsonObject.path.forEach((item) => { + this.path.push(item); + }); + } + } + + } + + setPath(path : Array) : void { + this.path = path; + } + withPath(path : Array) : org.eclipse.che.api.debug.shared.dto.VariablePathDto { + this.path = path; + return this; + } + getPath() : Array { + return this.path; + } + + toJson() : any { + let json : any = {}; + + if (this.path) { + let listArray = []; + this.path.forEach((item) => { + listArray.push(item); + json.path = listArray; + }); + } + + return json; + } + } +} + + +export module org.eclipse.che.api.git.shared { + + export interface PullRequest { + setTimeout(arg0): void; + getTimeout(): number; + setPassword(arg0): void; + getUsername(): string; + getPassword(): string; + setUsername(arg0): void; + setRemote(arg0): void; + withRemote(arg0): org.eclipse.che.api.git.shared.PullRequest; + withPassword(arg0): org.eclipse.che.api.git.shared.PullRequest; + getRefSpec(): string; + setRefSpec(arg0): void; + withRefSpec(arg0): org.eclipse.che.api.git.shared.PullRequest; + getRemote(): string; + withTimeout(arg0): org.eclipse.che.api.git.shared.PullRequest; + withUsername(arg0): org.eclipse.che.api.git.shared.PullRequest; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.git.shared { + + export class PullRequestImpl implements org.eclipse.che.api.git.shared.PullRequest { + + password : string; + refSpec : string; + remote : string; + timeout : number; + username : string; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.password) { + this.password = __jsonObject.password; + } + } + if (__jsonObject) { + if (__jsonObject.refSpec) { + this.refSpec = __jsonObject.refSpec; + } + } + if (__jsonObject) { + if (__jsonObject.remote) { + this.remote = __jsonObject.remote; + } + } + if (__jsonObject) { + if (__jsonObject.timeout) { + this.timeout = __jsonObject.timeout; + } + } + if (__jsonObject) { + if (__jsonObject.username) { + this.username = __jsonObject.username; + } + } + + } + + setTimeout(timeout : number) : void { + this.timeout = timeout; + } + getTimeout() : number { + return this.timeout; + } + setPassword(password : string) : void { + this.password = password; + } + getUsername() : string { + return this.username; + } + getPassword() : string { + return this.password; + } + setUsername(username : string) : void { + this.username = username; + } + setRemote(remote : string) : void { + this.remote = remote; + } + withRemote(remote : string) : org.eclipse.che.api.git.shared.PullRequest { + this.remote = remote; + return this; + } + withPassword(password : string) : org.eclipse.che.api.git.shared.PullRequest { + this.password = password; + return this; + } + getRefSpec() : string { + return this.refSpec; + } + setRefSpec(refSpec : string) : void { + this.refSpec = refSpec; + } + withRefSpec(refSpec : string) : org.eclipse.che.api.git.shared.PullRequest { + this.refSpec = refSpec; + return this; + } + getRemote() : string { + return this.remote; + } + withTimeout(timeout : number) : org.eclipse.che.api.git.shared.PullRequest { + this.timeout = timeout; + return this; + } + withUsername(username : string) : org.eclipse.che.api.git.shared.PullRequest { + this.username = username; + return this; + } + + toJson() : any { + let json : any = {}; + + if (this.password) { + json.password = this.password; + } + if (this.refSpec) { + json.refSpec = this.refSpec; + } + if (this.remote) { + json.remote = this.remote; + } + if (this.timeout) { + json.timeout = this.timeout; + } + if (this.username) { + json.username = this.username; + } + + return json; + } + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export interface ServerConf2Dto { + setProtocol(arg0): void; + setPort(arg0): void; + withProperties(arg0): org.eclipse.che.api.workspace.shared.dto.ServerConf2Dto; + withPort(arg0): org.eclipse.che.api.workspace.shared.dto.ServerConf2Dto; + withProtocol(arg0): org.eclipse.che.api.workspace.shared.dto.ServerConf2Dto; + getProperties(): Map; + setProperties(arg0): void; + getProtocol(): string; + getPort(): string; + + toJson() : any; + } +} + + +export module org.eclipse.che.api.workspace.shared.dto { + + export class ServerConf2DtoImpl implements org.eclipse.che.api.workspace.shared.dto.ServerConf2Dto { + + protocol : string; + port : string; + properties : Map; + + __jsonObject : any; + + constructor(__jsonObject?: any) { + this.__jsonObject = __jsonObject; + if (__jsonObject) { + if (__jsonObject.protocol) { + this.protocol = __jsonObject.protocol; + } + } + if (__jsonObject) { + if (__jsonObject.port) { + this.port = __jsonObject.port; + } + } + this.properties = new Map(); + if (__jsonObject) { + if (__jsonObject.properties) { + let tmp : Array = Object.keys(__jsonObject.properties); + tmp.forEach((key) => { + this.properties.set(key, __jsonObject.properties[key]); + }); + } + } + + } + + setProtocol(protocol : string) : void { + this.protocol = protocol; + } + setPort(port : string) : void { + this.port = port; + } + withProperties(properties : Map) : org.eclipse.che.api.workspace.shared.dto.ServerConf2Dto { + this.properties = properties; + return this; + } + withPort(port : string) : org.eclipse.che.api.workspace.shared.dto.ServerConf2Dto { + this.port = port; + return this; + } + withProtocol(protocol : string) : org.eclipse.che.api.workspace.shared.dto.ServerConf2Dto { + this.protocol = protocol; + return this; + } + getProperties() : Map { + return this.properties; + } + setProperties(properties : Map) : void { + this.properties = properties; + } + getProtocol() : string { + return this.protocol; + } + getPort() : string { + return this.port; + } + + toJson() : any { + let json : any = {}; + + if (this.protocol) { + json.protocol = this.protocol; + } + if (this.port) { + json.port = this.port; + } + if (this.properties) { + let tmpMap : any = {}; + for (const [key, value] of this.properties.entries()) { + tmpMap[key] = value; + } + json.properties = tmpMap; + } + + return json; + } + } +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/auth/auth-data.ts b/dockerfiles/lib-typescript/src/api/wsmaster/auth/auth-data.ts new file mode 100644 index 00000000000..a5dc4b07ac5 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/auth/auth-data.ts @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {RemoteIp} from "../../../spi/docker/remoteip"; +import {Log} from "../../../spi/log/log"; +/** + * Defines a way to store the auth data in order to deal with remote REST or Websocket API + * @author Florent Benoit + */ +export class AuthData { + + + DEFAULT_TOKEN : string = ''; + DEFAULT_HOSTNAME : string = new RemoteIp().getIp(); + DEFAULT_PORT : number = 8080; + + printInfo : boolean = true; + + hostname : string; + port : number; + token : string; + secured : boolean; + + username: string; + password: string; + + constructor(hostname?: string, port? : number, token? : string) { + this.secured = false; + if (hostname) { + this.hostname = hostname; + } else { + this.hostname = this.DEFAULT_HOSTNAME; + } + + if (port) { + this.port = port; + } else { + // handle CHE_PORT if any + if (process.env.CHE_PORT) { + this.port = process.env.CHE_PORT; + } else { + this.port = this.DEFAULT_PORT; + } + } + + + if (token) { + this.token = token; + } else { + this.token = this.DEFAULT_TOKEN; + } + + } + + + getHostname() : string { + return this.hostname; + } + + getPort() : number { + return this.port; + } + + isSecured() : boolean { + return this.secured; + } + + getToken(): string { + return this.token; + } + + + login() : Promise { + + // no auth, return a dummy promise + if (!this.username && !this.password) { + return new Promise((resolve, reject) => { + resolve(true); + }); + } + + + var http:any; + if (this.isSecured()) { + http = require('https'); + } else { + http = require('http'); + } + + var securedOrNot:string; + if (this.isSecured()) { + securedOrNot = ' using SSL.'; + } else { + securedOrNot = '.'; + } + + var logMessage: string = 'Authenticating '; + if (this.username && this.password) { + logMessage += 'as ' + this.username; + } + + if (this.printInfo) { + Log.getLogger().info(logMessage, 'on \"' + this.getHostname() + ':' + this.getPort() + '\"' + securedOrNot); + } + + var options = { + hostname: this.hostname, + port: this.port, + path: '/api/auth/login', + method: 'POST', + headers: { + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': 'application/json;charset=UTF-8' + } + }; + + return new Promise((resolve, reject) => { + var req = http.request(options, (res) => { + res.on('data', (body) => { + if (res.statusCode == 200) { + // token get, continue + this.token = JSON.parse(body).value; + resolve(true); + } else { + // error + reject(body); + } + }); + + }); + + req.on('error', (err) => { + reject('HTTP error: ' + err); + }); + + const auth = { + "username": this.username, + "password": this.password + }; + + req.write(JSON.stringify(auth)); + req.end(); + + }); + } + + static parse(remoteUrl : string, username?: string, password?: string) : AuthData { + if (!remoteUrl) { + let authData: AuthData = new AuthData(); + authData.username = username; + authData.password = password; + return authData; + } + + // extract hostname and port + const url = require('url'); + var urlObject : any = url.parse(remoteUrl); + var port: number; + var isSecured: boolean = false; + // do we have a port ? + if (urlObject && !urlObject.port) { + if ('http:' === urlObject.protocol) { + port = 80; + } else if ('https:' === urlObject.protocol) { + isSecured = true; + port = 443; + } + } else { + port = urlObject.port; + } + + let authData: AuthData = new AuthData(urlObject.hostname, port); + if (isSecured) { + authData.secured = true; + } + + authData.username = username; + authData.password = password; + + return authData; + } + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/machine/machine-service-client.ts b/dockerfiles/lib-typescript/src/api/wsmaster/machine/machine-service-client.ts new file mode 100644 index 00000000000..5600c6878a4 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/machine/machine-service-client.ts @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {org} from "../../../api/dto/che-dto" +import {ProcessTerminatedEventPromiseMessageBusSubscriber} from "./process-terminated-event-promise-subscriber"; +import {ProcesLogOutputMessageBusSubscriber} from "./process-log-output-subscriber"; +import {AuthData} from "../auth/auth-data"; +import {Websocket} from "../../../spi/websocket/websocket"; +import {Workspace} from "../workspace/workspace"; +import {MessageBusSubscriber} from "../../../spi/websocket/messagebus-subscriber"; +import {MessageBus} from "../../../spi/websocket/messagebus"; +import {HttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {DefaultHttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {HttpJsonResponse} from "../../../spi/http/default-http-json-request"; +import {CheFileStructWorkspaceCommand} from "../../../internal/dir/chefile-struct/che-file-struct"; + +/** + * Workspace class allowing to manage a workspace, like create/start/stop, etc operations + * @author Florent Benoit + */ +export class MachineServiceClientImpl { + + /** + * Authentication data + */ + authData : AuthData; + + /** + * websocket. + */ + websocket : Websocket; + + workspace : Workspace; + + constructor(workspace : Workspace, authData : AuthData) { + this.workspace = workspace; + this.authData = authData; + this.websocket = new Websocket(); + } + + + /** + * Create a workspace and return a promise with content of WorkspaceDto in case of success + */ + executeCommand(workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto, + machineId:string, + cheFileStructWorkspaceCommand:CheFileStructWorkspaceCommand, + outputChannel:string, + asynchronous : boolean = true):Promise { + + let command:any = { + "name" : !cheFileStructWorkspaceCommand.name ? "custom-command" : cheFileStructWorkspaceCommand.name, + "type" : !cheFileStructWorkspaceCommand.type ? "custom" : cheFileStructWorkspaceCommand.type, + "commandLine": cheFileStructWorkspaceCommand.commandLine + }; + + let path : string = '/api/workspace/' + workspaceDto.getId() + '/machine/' + machineId + '/command/?outputChannel=' + outputChannel; + // get MessageBus + var displayOutputWorkspaceSubscriber:MessageBusSubscriber = new ProcesLogOutputMessageBusSubscriber(); + let processTerminatedEventPromiseMessageBusSubscriber : ProcessTerminatedEventPromiseMessageBusSubscriber; + let userMachineProcessDto : org.eclipse.che.api.machine.shared.dto.MachineProcessDto; + let userMessageBus : MessageBus; + return this.workspace.getMessageBus(workspaceDto).then((messageBus:MessageBus) => { + userMessageBus = messageBus; + processTerminatedEventPromiseMessageBusSubscriber = new ProcessTerminatedEventPromiseMessageBusSubscriber(messageBus); + + // subscribe to websocket + if (asynchronous) { + messageBus.subscribe(outputChannel, displayOutputWorkspaceSubscriber); + messageBus.subscribe('machine:process:' + machineId, processTerminatedEventPromiseMessageBusSubscriber); + } + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, path, 200).setMethod('POST').setBody(command); + return jsonRequest.request(); + }).then((jsonResponse : HttpJsonResponse) => { + // return response + return jsonResponse.asDto(org.eclipse.che.api.machine.shared.dto.MachineProcessDtoImpl); + }).then((machineProcessDto : org.eclipse.che.api.machine.shared.dto.MachineProcessDto) => { + userMachineProcessDto = machineProcessDto; + // get pid + let pid: number = machineProcessDto.getPid(); + + // subscribe to pid event end + if (asynchronous) { + return processTerminatedEventPromiseMessageBusSubscriber.promise; + } else { + // do not wait the end + userMessageBus.close(); + return true; + } + }).then(() => { + return userMachineProcessDto; + }); + + } + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-log-output-subscriber.ts b/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-log-output-subscriber.ts new file mode 100644 index 00000000000..497418b5f2e --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-log-output-subscriber.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {MessageBusSubscriber} from "../../../spi/websocket/messagebus-subscriber"; +import {StringUtils} from "../../../utils/string-utils"; +import {Log} from "../../../spi/log/log"; +/** + * Class that will display to console all process output messages. + * @author Florent Benoit + */ +export class ProcesLogOutputMessageBusSubscriber implements MessageBusSubscriber { + + handleMessage(message: string) { + if (StringUtils.startsWith(message, '[STDOUT] ')) { + console.log(Log.GREEN + message.substr('[STDOUT] '.length) + Log.NC); + } else if (StringUtils.startsWith(message, '[STDERR] ')) { + console.log(Log.RED + message.substr('[STDERR] '.length) + Log.NC); + } else { + console.log(message); + } + } +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts b/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts new file mode 100644 index 00000000000..ddbd6e74275 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {MessageBusSubscriber} from "../../../spi/websocket/messagebus-subscriber"; +import {MessageBus} from "../../../spi/websocket/messagebus"; +import {Log} from "../../../spi/log/log"; +/** + * Handle a promise that will be resolved when process/command is finished. + * If process has error, promise will be rejected + * @author Florent Benoit + */ +export class ProcessTerminatedEventPromiseMessageBusSubscriber implements MessageBusSubscriber { + + messageBus : MessageBus; + + resolve : any; + reject : any; + promise: Promise; + + constructor(messageBus : MessageBus) { + this.messageBus = messageBus; + this.promise = new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + }); + } + + handleMessage(message: any) { + if ('STOPPED' === message.eventType) { + this.resolve(true); + this.messageBus.close(); + } else if ('ERROR' === message.eventType) { + try { + let stringify: any = JSON.stringify(message); + this.reject('Error when executing the command' + stringify); + } catch (error) { + this.reject('Error when executing the command' + message.toString()); + } + this.messageBus.close(); + } else { + Log.getLogger().debug('Event on command : ', message.eventType); + } + + } + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/domaindto.ts b/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/domaindto.ts new file mode 100644 index 00000000000..cb9684e6f00 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/domaindto.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +export class DomainDto { + + content: any; + + + constructor(domainObject: any) { + this.content = domainObject; + } + + getContent() : any { + return this.content; + } +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/permissiondto.ts b/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/permissiondto.ts new file mode 100644 index 00000000000..074fcb8fafc --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/permissiondto.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +export class PermissionDto { + + content: any; + + + constructor(permissionObject: any) { + this.content = permissionObject; + } + + getContent() : any { + return this.content; + } +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/permissions/permissions.ts b/dockerfiles/lib-typescript/src/api/wsmaster/permissions/permissions.ts new file mode 100644 index 00000000000..45e7cb1aed1 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/permissions/permissions.ts @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {AuthData} from "../auth/auth-data"; +import {DomainDto} from "./dto/domaindto"; +import {HttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {DefaultHttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {HttpJsonResponse} from "../../../spi/http/default-http-json-request"; +import {PermissionDto} from "./dto/permissiondto"; +/** + * Defines communication with remote Permissions API + * @author Florent Benoit + */ +export class Permissions { + + /** + * Authentication data + */ + authData:AuthData; + + + constructor(authData:AuthData) { + this.authData = authData; + } + + + /** + * list all permissions + */ + listPermissions():Promise> { + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/permissions', 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + let domainsDto:Array = new Array(); + JSON.parse(jsonResponse.getData()).forEach((entry)=> { + domainsDto.push(new DomainDto(entry)); + }); + return domainsDto; + }); + } + + + /** + * get permissions for a given domain + */ + getPermission(domain:string):Promise { + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/permissions/' + domain, 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return new PermissionDto(JSON.parse(jsonResponse.getData())); + }, (error) => { + return new PermissionDto({}); + }); + } + + updatePermissions(permissionDto:PermissionDto) { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/permissions', 204); + return jsonRequest.setMethod('POST').setBody(permissionDto.getContent()).request().then((jsonResponse:HttpJsonResponse) => { + return new PermissionDto(jsonResponse.getData()); + }); + } + + + copyCurrentPermissionsToUser(newUserId:string):Promise { + return this.listPermissions().then( + (domainsDto:Array) => { + let adminPermissionsPromises:Array> = new Array>(); + domainsDto.forEach((domain) => { + adminPermissionsPromises.push(this.getPermission(domain.getContent().id)); + }); + return Promise.all(adminPermissionsPromises); + } + ).then((adminsPermissions:Array) => { + + let updatedPermissionsPromises:Array> = new Array>(); + adminsPermissions.forEach((adminPermission:PermissionDto)=> { + if (adminPermission.getContent().domain) { + // we replace the user by the new user + adminPermission.getContent().user = newUserId; + // update permissions + updatedPermissionsPromises.push(this.updatePermissions(adminPermission).then((updatedDto)=> { + return updatedDto; + })); + } + + }); + + return Promise.all(updatedPermissionsPromises); + }).then(() => { + return true; + }); + } +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/project/project.ts b/dockerfiles/lib-typescript/src/api/wsmaster/project/project.ts new file mode 100644 index 00000000000..0b42814f683 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/project/project.ts @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {org} from "../../../api/dto/che-dto" +import {AuthData} from "../auth/auth-data"; +import {Log} from "../../../spi/log/log"; +import {HttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {DefaultHttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {HttpJsonResponse} from "../../../spi/http/default-http-json-request"; + +/** + * Project class allowing to manage a project like updating project-type. + * @author Florent Benoit + */ +export class Project { + + /** + * The HTTP library used to call REST API. + */ + http: any; + + /** + * Authentication data + */ + authData : AuthData; + + /** + * Workspace DTO + */ + workspaceDTO : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + + /** + * Path to the workspace agent + */ + wsAgentPath : string; + + constructor(workspaceDTO: org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) { + this.workspaceDTO = workspaceDTO; + + // search the workspace agent link + let servers : Map = this.workspaceDTO.getRuntime().getDevMachine().getRuntime().getServers(); + + var hrefWsAgent; + for (let server of servers.values()) { + if (server.getRef() === 'wsagent') { + hrefWsAgent = server.getProperties().getInternalUrl(); + } + } + + if (!hrefWsAgent) { + throw new Error('unable to find the workspace agent link from workspace :' + workspaceDTO.getConfig().getName() + " with JSON " + workspaceDTO.toJson()); + } + var urlObject : any = require('url').parse(hrefWsAgent); + + this.authData = AuthData.parse(urlObject); + if (this.authData.isSecured()) { + this.http = require('https'); + } else { + this.http = require('http'); + } + + this.wsAgentPath = urlObject.path; + } + + /** + * Get project details for a given project name + */ + getProject(projectName) : Promise { + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, this.wsAgentPath + '/project/' + projectName, 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.workspace.shared.dto.ProjectConfigDtoImpl); + }); + } + + /** + * Updates the given project with the provided project Type + * @param projectType the type of the project that we want to set + * @param projectDTO a DTO containing all attributes to set as new attributes + * @return a promise with the updated Project DTO + */ + updateType(projectName, projectType) : Promise { + // first get project attributes + return this.getProject(projectName).then((projectDto) => { + // then update the project type + projectDto.setType(projectType); + + // and perform update of all these attributes + return this.update(projectName, projectDto); + }) + + } + + /** + */ + estimateType(projectName, projectType) : Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, this.wsAgentPath + '/project/estimate/' + projectName + '?type=' + projectType, 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.project.shared.dto.SourceEstimationImpl); + }); + + } + + /** + * Updates the given project with the provided DTO + * @param projectName the name of the project that will be updated + * @param projectDTO a DTO containing all attributes to set as new attributes + * @return a promise with the updated Project DTO + */ + update(projectName: string, projectDto: org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto): Promise { + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, this.wsAgentPath + '/project/' + projectName, 200).setMethod("PUT").setBody(projectDto); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.workspace.shared.dto.ProjectConfigDtoImpl); + }); + } + + + /** + * + * @param projectName + * @param sourceStorageDto + * @returns {Promise} + */ + importProject(projectName: string, sourceStorageDto : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto) : Promise { + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, this.wsAgentPath + '/project/import/' + projectName, 204).setMethod("POST").setBody(sourceStorageDto); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return; + }); + } + + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts b/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts new file mode 100644 index 00000000000..adc77fb3ed2 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {org} from "../../../api/dto/che-dto" +import {AuthData} from "../auth/auth-data"; +import {HttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {DefaultHttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {HttpJsonResponse} from "../../../spi/http/default-http-json-request"; + +/** + * SSh class allowing to manage all ssh operations + * @author Florent Benoit + */ +export class Ssh { + + /** + * Authentication data + */ + authData:AuthData; + + constructor(authData:AuthData) { + this.authData = authData; + } + + + /** + * Gets ssh pair by service and name. + * + * @param service + * service name of ssh pair + * @param name + * name of ssh pair + * @return instance of ssh pair + * @throws NotFoundException + * when ssh pair is not found + * @throws ServerException + * when any other error occurs during ssh pair fetching + */ + getPair(service: string, name: string):Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/ssh/' + service + '/' + name, 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.ssh.shared.dto.SshPairDtoImpl); + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/user/user.ts b/dockerfiles/lib-typescript/src/api/wsmaster/user/user.ts new file mode 100644 index 00000000000..c65484152dc --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/user/user.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {org} from "../../../api/dto/che-dto" +import {AuthData} from "../auth/auth-data"; +import {HttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {DefaultHttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {HttpJsonResponse} from "../../../spi/http/default-http-json-request"; + +/** + * Defines communication with remote User API + * @author Florent Benoit + */ +export class User { + + /** + * Authentication data + */ + authData : AuthData; + + + constructor(authData : AuthData) { + this.authData = authData; + } + + + /** + * Create a user and return a promise with content of UserDto in case of success + */ + createUser(name: string, email: string, password : string) : Promise { + + var userData = { + password: password, + name: name, + }; + + if (email) { + userData['email'] = email; + } + var jsonRequest : HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/user', 201).setMethod('POST').setBody(userData); + return jsonRequest.request().then((jsonResponse : HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.user.shared.dto.UserDtoImpl); + }); + } + + + /** + * Removes user based on given user id + * @param userId the id (not email) of the user + * @returns {Promise} + */ + deleteUser(userId: string) : Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/user/' + userId, 204).setMethod('DELETE') + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return true; + }); + } + + /** + * Search user by its username + * @param username the name of the user (not the id) + * @returns {Promise} + */ + findUserName(username : string) : Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/user/find?name=' + username, 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.user.shared.dto.UserDtoImpl); + }); + } + + + + + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts new file mode 100644 index 00000000000..381ebfef65b --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + + +import {MessageBusSubscriber} from "../../../spi/websocket/messagebus-subscriber"; +import {Log} from "../../../spi/log/log"; +/** + * Class that will display to console all workspace output messages. + * @author Florent Benoit + */ +export class WorkspaceDisplayOutputMessageBusSubscriber implements MessageBusSubscriber { + + handleMessage(message: string) { + try { + let stringify = JSON.stringify(message); + Log.getLogger().info(stringify); + } catch (error) { + // maybe parse data to add colors + Log.getLogger().info(message); + } + } + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts new file mode 100644 index 00000000000..c79d9275f26 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {org} from "../../../api/dto/che-dto" +import {MessageBusSubscriber} from "../../../spi/websocket/messagebus-subscriber"; +import {MessageBus} from "../../../spi/websocket/messagebus"; +import {Log} from "../../../spi/log/log"; +/** + * Handle a promise that will be resolved when workspace is started. + * If workspace has error, promise will be rejected + * @author Florent Benoit + */ +export class WorkspaceStartEventPromiseMessageBusSubscriber implements MessageBusSubscriber { + + messageBus : MessageBus; + workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + + resolve : any; + reject : any; + promise: Promise; + + constructor(messageBus : MessageBus, workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) { + this.messageBus = messageBus; + this.workspaceDto = workspaceDto; + this.promise = new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + }); + } + + handleMessage(message: any) { + if ('RUNNING' === message.eventType) { + this.resolve(this.workspaceDto); + this.messageBus.close(); + } else if ('ERROR' === message.eventType) { + try { + let stringify: any = JSON.stringify(message); + this.reject('Error when starting the workspace' + stringify); + } catch (error) { + this.reject('Error when starting the workspace' + message.toString()); + } + this.messageBus.close(); + } else { + Log.getLogger().debug('Event on workspace : ', message.eventType); + } + + } + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts new file mode 100644 index 00000000000..488f2a54671 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {org} from "../../../api/dto/che-dto" +import {MessageBusSubscriber} from "../../../spi/websocket/messagebus-subscriber"; +import {MessageBus} from "../../../spi/websocket/messagebus"; +import {Log} from "../../../spi/log/log"; +/** + * Handle a promise that will be resolved when workspace is stopped. + * If workspace has error, promise will be rejected + * @author Florent Benoit + */ +export class WorkspaceStopEventPromiseMessageBusSubscriber implements MessageBusSubscriber { + + messageBus : MessageBus; + workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + + resolve : any; + reject : any; + promise: Promise; + + constructor(messageBus : MessageBus, workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) { + this.messageBus = messageBus; + this.workspaceDto = workspaceDto; + this.promise = new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + }); + } + + handleMessage(message: any) { + if ('STOPPED' === message.eventType) { + this.resolve(this.workspaceDto); + this.messageBus.close(); + } else if ('ERROR' === message.eventType) { + try { + let stringify: any = JSON.stringify(message); + this.reject('Error when stopping the workspace' + stringify); + } catch (error) { + this.reject('Error when stopping the workspace' + message.toString()); + } + this.messageBus.close(); + + } else { + Log.getLogger().debug('Event on workspace : ', message.eventType); + } + + } + +} diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace.ts b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace.ts new file mode 100644 index 00000000000..793c684b1e8 --- /dev/null +++ b/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace.ts @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {org} from "../../../api/dto/che-dto" +import {AuthData} from "../auth/auth-data"; +import {Websocket} from "../../../spi/websocket/websocket"; +import {HttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {DefaultHttpJsonRequest} from "../../../spi/http/default-http-json-request"; +import {HttpJsonResponse} from "../../../spi/http/default-http-json-request"; +import {WorkspaceStartEventPromiseMessageBusSubscriber} from "./workspace-start-event-promise-subscriber"; +import {MessageBus} from "../../../spi/websocket/messagebus"; +import {MessageBusSubscriber} from "../../../spi/websocket/messagebus-subscriber"; +import {WorkspaceDisplayOutputMessageBusSubscriber} from "./workspace-log-output-subscriber"; +import {Log} from "../../../spi/log/log"; +import {WorkspaceStopEventPromiseMessageBusSubscriber} from "./workspace-stop-event-promise-subscriber"; +import {RecipeBuilder} from "../../../spi/docker/recipebuilder"; +import {CheFileStructWorkspaceCommand} from "../../../internal/dir/chefile-struct/che-file-struct"; + +/** + * Workspace class allowing to manage a workspace, like create/start/stop, etc operations + * @author Florent Benoit + */ +export class Workspace { + + /** + * Authentication data + */ + authData:AuthData; + + /** + * websocket. + */ + websocket:Websocket; + + constructor(authData:AuthData) { + this.authData = authData; + this.websocket = new Websocket(); + } + + + + /** + * Get all workspaces + */ + getWorkspaces():Promise> { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace/', 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asArrayDto(org.eclipse.che.api.workspace.shared.dto.WorkspaceDtoImpl); + }); + } + + /** + * Gets a workspace config DTO object from a createWorkspaceConfiguration object + * @param createWorkspaceConfig + */ + getWorkspaceConfigDto(createWorkspaceConfig:CreateWorkspaceConfig) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { + let devMachine : org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto = new org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDtoImpl(); + devMachine.getAgents().push("org.eclipse.che.terminal"); + devMachine.getAgents().push("org.eclipse.che.ws-agent"); + devMachine.getAgents().push("org.eclipse.che.ssh"); + devMachine.getAttributes().set("memoryLimitBytes", "2147483648"); + + let defaultEnvironment : org.eclipse.che.api.workspace.shared.dto.EnvironmentDto = new org.eclipse.che.api.workspace.shared.dto.EnvironmentDtoImpl(); + defaultEnvironment.getMachines().set("dev-machine", devMachine); + defaultEnvironment.setRecipe(new org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDtoImpl(createWorkspaceConfig.machineConfigSource)); + + + let commandsToCreate : Array = new Array; + createWorkspaceConfig.commands.forEach(commandConfig => { + let command : org.eclipse.che.api.machine.shared.dto.CommandDto = new org.eclipse.che.api.machine.shared.dto.CommandDtoImpl(); + command.withCommandLine(commandConfig.commandLine).withName(commandConfig.name).withType(commandConfig.type); + if (commandConfig.attributes.previewUrl) { + command.getAttributes().set("previewUrl", commandConfig.attributes.previewUrl); + } + commandsToCreate.push(command); + }); + + let workspaceConfigDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto = new org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDtoImpl(); + workspaceConfigDto.withDefaultEnv("default").withName(createWorkspaceConfig.name).withCommands(commandsToCreate); + workspaceConfigDto.getEnvironments().set("default", defaultEnvironment); + + return workspaceConfigDto; + } + + + /** + * Create a workspace and return a promise with content of WorkspaceDto in case of success + */ + createWorkspace(createWorkspaceConfig:CreateWorkspaceConfig):Promise { + + let workspaceConfigDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto = this.getWorkspaceConfigDto(createWorkspaceConfig); + + // TODO use ram ? + //createWorkspaceConfig.ram + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace?account=', 201).setMethod('POST').setBody(workspaceConfigDto); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.workspace.shared.dto.WorkspaceDtoImpl); + }); + + } + + + /** + * Start a workspace and provide a Promise with WorkspaceDto. + */ + startWorkspace(workspaceId:string, displayLog?:boolean):Promise { + + var callbackSubscriber:WorkspaceStartEventPromiseMessageBusSubscriber; + let userWorkspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + // get workspace DTO + return this.getWorkspace(workspaceId).then((workspaceDto) => { + userWorkspaceDto = workspaceDto; + return this.getMessageBus(workspaceDto); + }).then((messageBus: MessageBus) => { + var displayOutputWorkspaceSubscriber:MessageBusSubscriber = new WorkspaceDisplayOutputMessageBusSubscriber(); + callbackSubscriber = new WorkspaceStartEventPromiseMessageBusSubscriber(messageBus, userWorkspaceDto); + messageBus.subscribe('workspace:' + workspaceId, callbackSubscriber); + let channel:string = 'machine:status:' + workspaceId + ':default'; + messageBus.subscribe(channel, callbackSubscriber); + if (displayLog) { + messageBus.subscribe('workspace:' + workspaceId + ':ext-server:output', displayOutputWorkspaceSubscriber); + messageBus.subscribe('workspace:' + workspaceId + ':environment_output', displayOutputWorkspaceSubscriber); + messageBus.subscribe(workspaceId + ':default:default', displayOutputWorkspaceSubscriber); + } + return userWorkspaceDto; + }).then((workspaceDto) => { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace/' + workspaceId + '/runtime?environment=default', 200).setMethod('POST'); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.workspace.shared.dto.WorkspaceDtoImpl); + }).then((workspaceDto) => { + return callbackSubscriber.promise; + }).then(() => { + return this.getWorkspace(workspaceId); + }); + }); + + + } + + + /** + * Search a workspace data by returning a Promise with WorkspaceDto. + */ + searchWorkspace(key:string):Promise { + Log.getLogger().debug('search workspace with key', key); + + // if workspace key is too short it's a workspace name + if (key && key.length < 21) { + if (key.indexOf(":") < 0) { + key = ":" + key; + } + } + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace/' + key, 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + Log.getLogger().debug('got workspace with key', key, 'result: ', jsonResponse.getData()); + return jsonResponse.asDto(org.eclipse.che.api.workspace.shared.dto.WorkspaceDtoImpl); + }); + } + + /** + * Search a workspace data by returning a Promise with WorkspaceDto. + */ + existsWorkspace(key:string):Promise { + Log.getLogger().debug('search workspace with key', key); + + return this.searchWorkspace(key).catch((error) => { + return undefined; + }) + } + + /** + * Get a workspace data by returning a Promise with WorkspaceDto. + */ + getWorkspace(workspaceId:string):Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace/' + workspaceId, 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return jsonResponse.asDto(org.eclipse.che.api.workspace.shared.dto.WorkspaceDtoImpl); + }); + } + + + getMessageBus(workspaceDto:org.eclipse.che.api.workspace.shared.dto.WorkspaceDto): Promise { + // get id + let workspaceId:string = workspaceDto.getId(); + + var protocol:string; + if (this.authData.isSecured()) { + protocol = 'wss'; + } else { + protocol = 'ws'; + } + + // get links for WS + var link:string; + workspaceDto.getLinks().forEach(workspaceLink => { + if ('get workspace events channel' === workspaceLink.getRel()) { + link = workspaceLink.getHref(); + } + }); + + return this.websocket.getMessageBus(link + '?token=' + this.authData.getToken()); + } + + + /** + * Delete a workspace and returns a Promise with WorkspaceDto. + */ + deleteWorkspace(workspaceId:string):Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace/' + workspaceId, 204).setMethod('DELETE'); + return this.getWorkspace(workspaceId).then((workspaceDto:org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) => { + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return workspaceDto; + }); + }); + } + + + /** + * Stop a workspace and returns a Promise with WorkspaceDto. + */ + stopWorkspace(workspaceId:string):Promise { + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace/' + workspaceId + '/runtime', 204).setMethod('DELETE'); + var callbackSubscriber:WorkspaceStopEventPromiseMessageBusSubscriber; + + var userWorkspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + // get workspace DTO + return this.getWorkspace(workspaceId).then((workspaceDto) => { + userWorkspaceDto = workspaceDto; + return this.getMessageBus(workspaceDto); + }).then((messageBus : MessageBus) => { + callbackSubscriber = new WorkspaceStopEventPromiseMessageBusSubscriber(messageBus, userWorkspaceDto); + messageBus.subscribe('workspace:' + workspaceId, callbackSubscriber); + return userWorkspaceDto; + }).then((workspaceDto) => { + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return workspaceDto; + }); + }).then((workspaceDto) => { + return callbackSubscriber.promise; + }); + } + + getWorkspaceAgent(workspaceDTO:org.eclipse.che.api.workspace.shared.dto.WorkspaceDto):any { + // search the workspace agent link + let links:Array = workspaceDTO.getRuntime().getLinks(); + var hrefWsAgent; + links.forEach((link) => { + if ('wsagent' === link.rel) { + hrefWsAgent = link.href; + } + }); + return require('url').parse(hrefWsAgent); + } + + /** + * Provides machine token for given workspace + * @param workspaceId the ID of the workspace + * @returns {*} + */ + getMachineToken(workspaceDto:org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) { + + + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/machine/token/' + workspaceDto.getId(), 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return JSON.parse(jsonResponse.getData()).machineToken; + }); + + } + +} + +export class CreateWorkspaceConfig { + ram : number = 2048; + machineConfigSource : any = {"contentType": "text/x-dockerfile", "type": "dockerfile", "content": RecipeBuilder.DEFAULT_DOCKERFILE_CONTENT}; + name: string = "default"; + commands: Array = []; + +} diff --git a/dockerfiles/lib-typescript/src/index.ts b/dockerfiles/lib-typescript/src/index.ts new file mode 100644 index 00000000000..54ff3bbaed6 --- /dev/null +++ b/dockerfiles/lib-typescript/src/index.ts @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {Argument} from "./spi/decorator/parameter"; +import {Parameter} from "./spi/decorator/parameter"; +import {ArgumentProcessor} from "./spi/decorator/argument-processor"; +import {Log} from "./spi/log/log"; +import {CheDir} from "./internal/dir/che-dir"; +import {CheTest} from "./internal/test/che-test"; +import {CheAction} from "./internal/action/che-action"; +/** + * Entry point of this library providing commands. + * @author Florent Benoit + */ +export class EntryPoint { + + args: Array; + + @Argument({description: "Name of the command to execute from this entry point."}) + commandName : string; + + @Parameter({names: ["--logger-debug"], description: "Enable the logger in debug mode"}) + debugLogger : boolean; + + @Parameter({names: ["--logger-prefix-off"], description: "Disable prefix mode in logging"}) + prefixOffLogger : boolean; + + constructor() { + this.args = ArgumentProcessor.inject(this, process.argv.slice(2)); + + process.on('SIGINT', () => { + Log.getLogger().warn('CTRL-C hit, exiting...'); + process.exit(1); + }); + + } + + /** + * Run this entry point and analyze args to dispatch to the correct entry. + */ + run() : void { + + // turn into debugging mode + if (this.debugLogger) { + Log.enableDebug(); + } + + if (this.prefixOffLogger) { + Log.disablePrefix(); + } + + + var promise : Promise; + + switch(this.commandName) { + case 'che-test': + let cheTest: CheTest = new CheTest(this.args); + promise = cheTest.run(); + break; + case 'che-action': + let cheAction: CheAction = new CheAction(this.args); + promise = cheAction.run(); + break; + case 'che-dir': + let cheDir: CheDir = new CheDir(this.args); + promise = cheDir.run(); + break; + default: + Log.getLogger().error('Invalid choice of command-name'); + process.exit(1); + } + + // handle error of the promise + promise.catch((error) => { + try { + let errorMessage = JSON.parse(error); + if (errorMessage.message) { + Log.getLogger().error(errorMessage.message); + } else { + Log.getLogger().error(error.toString()); + } + } catch (e) { + Log.getLogger().error(error.toString()); + if (error instanceof TypeError || error instanceof SyntaxError) { + console.log(error.stack); + } + } + process.exit(1); + }); + + } + +} + + +// call run method +new EntryPoint().run(); diff --git a/dockerfiles/lib-typescript/src/internal/action/che-action.ts b/dockerfiles/lib-typescript/src/internal/action/che-action.ts new file mode 100644 index 00000000000..ab25956db81 --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/che-action.ts @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {Argument} from "../../spi/decorator/parameter"; +import {ArgumentProcessor} from "../../spi/decorator/argument-processor"; +import {CreateStartWorkspaceAction} from "./impl/create-start-workspace-action"; +import {RemoveUserAction} from "./impl/remove-user-action"; +import {AddUserAction} from "./impl/add-user-action"; +import {ExecuteCommandAction} from "./impl/execute-command-action"; +import {Log} from "../../spi/log/log"; +import {ListWorkspacesAction} from "./impl/list-workspaces-action"; +import {ProductName} from "../../utils/product-name"; +import {WorkspaceSshAction} from "./impl/workspace-ssh-action"; +import {GetSshDataAction} from "./impl/get-ssh-action"; +/** + * Entrypoint for the Actions. + * @author Florent Benoit + */ +export class CheAction { + + /** + * This action name will be injected automatically. + */ + @Argument({description: "Name of the action to execute"}) + actionName : string; + + /** + * Parsing of arguments. + */ + args : Array; + + /** + * Map of tests that are available. + */ + mapOfActions : Map = CheAction.init(); + + /** + * Analyze the arguments by injecting parameters/arguments and define the list of test classes. + * @param args + */ + constructor(args:Array) { + this.args = ArgumentProcessor.inject(this, args); + } + + + static init() : Map { + Log.context = ProductName.getDisplayName() + '(action)'; + let actionMap : Map = new Map(); + actionMap.set('create-start-workspace', CreateStartWorkspaceAction); + actionMap.set('add-user', AddUserAction); + actionMap.set('remove-user', RemoveUserAction); + actionMap.set('execute-command', ExecuteCommandAction); + actionMap.set('list-workspaces', ListWorkspacesAction); + actionMap.set('workspace-ssh', WorkspaceSshAction); + actionMap.set('get-ssh-data', GetSshDataAction); + + return actionMap; + } + + /** + * Run this che-test entry point. + * When a test is found, build an instance of the test and call run() method which returns a promise + */ + run() : Promise { + let classOfAction: any = this.mapOfActions.get(this.actionName); + if (classOfAction) { + Log.context = ProductName.getDisplayName() + '(action/' + this.actionName + ')'; + var instance = new classOfAction(this.args); + return instance.run(); + } else { + // The given action name has not been found, display available actions + Log.getLogger().error("No action exists with provided name '" + this.actionName + "'."); + this.help(); + process.exit(1); + } + } + + + help() : void { + Log.getLogger().info("Available actions are : "); + for (var [key, value] of this.mapOfActions.entries()) { + Log.getLogger().info('\u001b[1m' + key + '\u001b[0m'); + ArgumentProcessor.help(Object.create(value.prototype)); + } + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/add-user-action.ts b/dockerfiles/lib-typescript/src/internal/action/impl/add-user-action.ts new file mode 100644 index 00000000000..d88c8ef57b7 --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/impl/add-user-action.ts @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +// imports +import {org} from "../../../api/dto/che-dto" +import {Argument} from "../../../spi/decorator/parameter"; +import {Parameter} from "../../../spi/decorator/parameter"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {User} from "../../../api/wsmaster/user/user"; +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {Log} from "../../../spi/log/log"; +import {Permissions} from "../../../api/wsmaster/permissions/permissions"; +/** + * This class is handling the add of a user and also consider to add user as being admin. + * @author Florent Benoit + */ +export class AddUserAction { + + @Argument({description: "Name of the user to create"}) + userToAdd : string; + + @Argument({description: "Email of the user to create"}) + emailToAdd : string; + + @Argument({description: "Password of the user to create "}) + passwordToAdd : string; + + @Parameter({names: ["-s", "--url"], description: "Defines the url to be used"}) + url : string; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + @Parameter({names: ["-a", "--admin"], description: "Grant admin role to the user"}) + admin : boolean; + + + authData: AuthData; + user: User; + + constructor(args:Array) { + ArgumentProcessor.inject(this, args); + this.authData = AuthData.parse(this.url, this.username, this.password); + this.user = new User(this.authData); + } + + run() : Promise { + // first, login + return this.authData.login().then(() => { + // then create user + Log.getLogger().info('Creating user ' + this.userToAdd); + return this.user.createUser(this.userToAdd, this.emailToAdd, this.passwordToAdd).then((userDto : org.eclipse.che.api.user.shared.dto.UserDto) => { + Log.getLogger().info('User', this.userToAdd, 'created with id', userDto.getId()); + + // if user should not be addes as admin, job is done + if (!this.admin) { + return Promise.resolve(true); + } else { + let permissions: Permissions = new Permissions(this.authData); + return permissions.copyCurrentPermissionsToUser(userDto.getId()); + } + }) + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/create-start-workspace-action.ts b/dockerfiles/lib-typescript/src/internal/action/impl/create-start-workspace-action.ts new file mode 100644 index 00000000000..04f8b027b69 --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/impl/create-start-workspace-action.ts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +// imports + +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {Workspace} from "../../../api/wsmaster/workspace/workspace"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {Parameter} from "../../../spi/decorator/parameter"; +import {CreateWorkspaceConfig} from "../../../api/wsmaster/workspace/workspace"; +import {Log} from "../../../spi/log/log"; +/** + * This class is managing a post-check operation by creating a workspace, starting it and displaying the log data. + * @author Florent Benoit + */ +export class CreateStartWorkspaceAction { + + @Parameter({names: ["-s", "--url"], description: "Defines the url to be used"}) + url : string; + + @Parameter({names: ["-q", "--quiet"], description: "Run in quiet mode for this test."}) + isQuiet : boolean = false; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + authData: AuthData; + workspace: Workspace; + + constructor(args:Array) { + let updatedArgs = ArgumentProcessor.inject(this, args); + + this.authData = AuthData.parse(this.url, this.username, this.password); + this.workspace = new Workspace(this.authData); + } + + run() : Promise { + // first, login + return this.authData.login().then(() => { + // then create the workspace + let createWorkspaceConfig: CreateWorkspaceConfig = new CreateWorkspaceConfig(); + createWorkspaceConfig.name = 'your-first-workspace'; + Log.getLogger().info('Generating '+ createWorkspaceConfig.name + ' workspace'); + return this.workspace.createWorkspace(createWorkspaceConfig) + .then(workspaceDto => { + // then start it + Log.getLogger().info('Starting workspace runtime'); + return this.workspace.startWorkspace(workspaceDto.getId(), !this.isQuiet); + }).then((workspaceDto) => { + var ideUrl: string; + workspaceDto.getLinks().forEach((link) => { + if ('ide url' === link.getRel()) { + ideUrl = link.getHref(); + } + }); + + Log.getLogger().info(ideUrl); + }); + + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/execute-command-action.ts b/dockerfiles/lib-typescript/src/internal/action/impl/execute-command-action.ts new file mode 100644 index 00000000000..ff13821959f --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/impl/execute-command-action.ts @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +// imports +import {org} from "../../../api/dto/che-dto" +import {Argument} from "../../../spi/decorator/parameter"; +import {Parameter} from "../../../spi/decorator/parameter"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {Workspace} from "../../../api/wsmaster/workspace/workspace"; +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {Log} from "../../../spi/log/log"; +import {MachineServiceClientImpl} from "../../../api/wsmaster/machine/machine-service-client"; +import {UUID} from "../../../utils/uuid"; +import {CheFileStructWorkspaceCommand} from "../../dir/chefile-struct/che-file-struct"; +import {CheFileStructWorkspaceCommandImpl} from "../../dir/chefile-struct/che-file-struct"; +/** + * This class is handling the removal of a user + * @author Florent Benoit + */ +export class ExecuteCommandAction { + + @Argument({description: "Defines the workspace to be used"}) + workspaceName : string; + + + @Parameter({names: ["-s", "--url"], description: "Defines the url to be used"}) + url : string; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + + args: Array; + authData: AuthData; + + workspace : Workspace; + constructor(args:Array) { + this.args = ArgumentProcessor.inject(this, args); + this.authData = AuthData.parse(this.url, this.username, this.password); + // disable printing info + this.authData.printInfo = false; + Log.disablePrefix(); + this.workspace = new Workspace(this.authData); + } + + run() : Promise { + // first, login + return this.authData.login().then(() => { + + // then, search workspace + return this.workspace.searchWorkspace(this.workspaceName).then((workspaceDto) => { + + // check status + if ('RUNNING' !== workspaceDto.getStatus()) { + throw new Error('Workspace should be in running state. Current state is ' + workspaceDto.getStatus()); + } + + // get dev machine + let machineId : string = workspaceDto.getRuntime().getDevMachine().getId(); + + // now, execute command + let uuid : string = UUID.build(); + let channel : string = 'process:output:' + uuid; + let machineServiceClient : MachineServiceClientImpl = new MachineServiceClientImpl(this.workspace, this.authData); + + let workspaceCommand : CheFileStructWorkspaceCommand = new CheFileStructWorkspaceCommandImpl(); + workspaceCommand.commandLine = this.args.join(" "); + return machineServiceClient.executeCommand(workspaceDto, machineId, workspaceCommand, channel); + }).then((machineProcessDto: org.eclipse.che.api.machine.shared.dto.MachineProcessDto) => { + // command executed + }); + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/get-ssh-action.ts b/dockerfiles/lib-typescript/src/internal/action/impl/get-ssh-action.ts new file mode 100644 index 00000000000..7816583f64c --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/impl/get-ssh-action.ts @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +// imports +import {org} from "../../../api/dto/che-dto" +import {Argument} from "../../../spi/decorator/parameter"; +import {Parameter} from "../../../spi/decorator/parameter"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {Workspace} from "../../../api/wsmaster/workspace/workspace"; +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {Log} from "../../../spi/log/log"; +import {MachineServiceClientImpl} from "../../../api/wsmaster/machine/machine-service-client"; +import {UUID} from "../../../utils/uuid"; +import {CheFileStructWorkspaceCommand} from "../../dir/chefile-struct/che-file-struct"; +import {CheFileStructWorkspaceCommandImpl} from "../../dir/chefile-struct/che-file-struct"; +import {Ssh} from "../../../api/wsmaster/ssh/ssh"; +/** + * This class is handling the retrieval of default private ssh key of a workspace, login name and port to use + * @author Florent Benoit + */ +export class GetSshDataAction { + + @Argument({description: "Defines the workspace to be used. use workspaceId or :workspaceName as argument"}) + workspaceName : string; + + + @Parameter({names: ["-s", "--url"], description: "Defines the url to be used"}) + url : string; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + + args: Array; + authData: AuthData; + + fs = require('fs'); + path = require('path'); + + + workspace : Workspace; + constructor(args:Array) { + this.args = ArgumentProcessor.inject(this, args); + this.authData = AuthData.parse(this.url, this.username, this.password); + // disable printing info + this.authData.printInfo = false; + Log.disablePrefix(); + this.workspace = new Workspace(this.authData); + } + + run() : Promise { + // first, login + return this.authData.login().then(() => { + + let foundWorkspaceDTO : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + + // then, search workspace + return this.workspace.searchWorkspace(this.workspaceName).then((workspaceDto) => { + + // check status + if ('RUNNING' !== workspaceDto.getStatus()) { + throw new Error('Workspace should be in running state. Current state is ' + workspaceDto.getStatus()); + } + + // Check ssh agent is there + let defaultEnv:string = workspaceDto.getConfig().getDefaultEnv(); + let agents:Array = workspaceDto.getConfig().getEnvironments().get(defaultEnv).getMachines().get("dev-machine").getAgents(); + + if (agents.indexOf('org.eclipse.che.ssh') === -1) { + return Promise.reject("The SSH agent (org.eclipse.che.ssh) has been disabled for this workspace.") + } + + foundWorkspaceDTO = workspaceDto; + + }).then((sshPairDto : org.eclipse.che.api.ssh.shared.dto.SshPairDto) => { + + // need to get ssh key for the workspace + let ssh:Ssh = new Ssh(this.authData); + return ssh.getPair("workspace", foundWorkspaceDTO.getId()); + }).then((sshPairDto : org.eclipse.che.api.ssh.shared.dto.SshPairDto) => { + + let runtime : org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto = foundWorkspaceDTO.getRuntime().getDevMachine().getRuntime(); + let user : string = runtime.getProperties().get("config.user"); + if (user === "") { + // user is root if not defined + user = "root"; + } + let address: Array = runtime.getServers().get("22/tcp").getProperties().getInternalAddress().split(":"); + let ip:string = address[0]; + let port:string = address[1]; + + Log.getLogger().direct("SSH_IP=" + ip); + Log.getLogger().direct("SSH_PORT=" + port); + Log.getLogger().direct("SSH_USER=" + user); + Log.getLogger().direct("SSH_PRIVATE_KEY='"); + Log.getLogger().direct(sshPairDto.getPrivateKey()); + Log.getLogger().direct("'"); + + + return Promise.resolve("ok"); + }); + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/list-workspaces-action.ts b/dockerfiles/lib-typescript/src/internal/action/impl/list-workspaces-action.ts new file mode 100644 index 00000000000..aef8ca13068 --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/impl/list-workspaces-action.ts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +// imports +import {org} from "../../../api/dto/che-dto" +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {Workspace} from "../../../api/wsmaster/workspace/workspace"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {Parameter} from "../../../spi/decorator/parameter"; +import {CreateWorkspaceConfig} from "../../../api/wsmaster/workspace/workspace"; +import {Log} from "../../../spi/log/log"; +import {DefaultAsciiArray} from "../../../spi/ascii/default-ascii-array"; +import {AsciiArray} from "../../../spi/ascii/ascii-array"; +import {FormatterMode} from "../../../spi/ascii/formatter-mode"; + +/** + * This class list all workspaces + * @author Florent Benoit + */ +export class ListWorkspacesAction { + + @Parameter({names: ["-s", "--url"], description: "Defines the url to be used"}) + url : string; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + @Parameter({names: ["--formatter"], description: "Defines the formatter of result"}) + formatterMode : FormatterMode; + + @Parameter({names: ["--formatter-skip-titles"], description: "Don't display titles in the output"}) + formatSkipTitles : boolean = false; + + @Parameter({names: ["--formatter-columns"], description: "Specify order and column names that will be displayed"}) + formatColumns : string; + + + authData: AuthData; + workspace: Workspace; + + constructor(args:Array) { + ArgumentProcessor.inject(this, args); + + this.authData = AuthData.parse(this.url, this.username, this.password); + this.workspace = new Workspace(this.authData); + } + + run() : Promise { + + return this.authData.login().then(() => { + return this.workspace.getWorkspaces() + .then((workspaceDtos:Array) => { + + // Create Ascii array + let rows : Array> = new Array>(); + workspaceDtos.forEach((workspaceDto : any) => { + rows.push([workspaceDto.getConfig().getName(), workspaceDto.getId(), workspaceDto.getStatus()]); + }); + + let asciiArray : AsciiArray = new DefaultAsciiArray().withRows(rows).withFormatter(this.formatterMode).withTitles("name", "id", "status").withShowTitles(!this.formatSkipTitles).withFormatColumns(this.formatColumns); + + Log.getLogger().direct(asciiArray.toAscii()); + + }); + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/remove-user-action.ts b/dockerfiles/lib-typescript/src/internal/action/impl/remove-user-action.ts new file mode 100644 index 00000000000..cf858181b31 --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/impl/remove-user-action.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +// imports +import {org} from "../../../api/dto/che-dto" +import {Argument} from "../../../spi/decorator/parameter"; +import {Parameter} from "../../../spi/decorator/parameter"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {User} from "../../../api/wsmaster/user/user"; +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {Log} from "../../../spi/log/log"; + +/** + * This class is handling the removal of a user + * @author Florent Benoit + */ +export class RemoveUserAction { + + @Argument({description: "name of the user to remove"}) + usernameToDelete : string; + + @Parameter({names: ["-s", "--url"], description: "Defines the url to be used"}) + url : string; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + + authData: AuthData; + user: User; + + constructor(args:Array) { + ArgumentProcessor.inject(this, args); + this.authData = AuthData.parse(this.url, this.username, this.password); + this.user = new User(this.authData); + } + + run() : Promise { + // first, login + return this.authData.login().then(() => { + Log.getLogger().info('Searching user with name ' + this.usernameToDelete); + return this.user.findUserName(this.usernameToDelete).then((userDto: org.eclipse.che.api.user.shared.dto.UserDto) => { + // then delete user + Log.getLogger().info('Removing user with name ' + this.usernameToDelete, 'and id', userDto.getId()); + return this.user.deleteUser(userDto.getId()); + }); + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/workspace-ssh-action.ts b/dockerfiles/lib-typescript/src/internal/action/impl/workspace-ssh-action.ts new file mode 100644 index 00000000000..3cf1dcda247 --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/action/impl/workspace-ssh-action.ts @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +// imports +import {org} from "../../../api/dto/che-dto" +import {Argument} from "../../../spi/decorator/parameter"; +import {Parameter} from "../../../spi/decorator/parameter"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {Workspace} from "../../../api/wsmaster/workspace/workspace"; +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {Log} from "../../../spi/log/log"; +import {MachineServiceClientImpl} from "../../../api/wsmaster/machine/machine-service-client"; +import {UUID} from "../../../utils/uuid"; +import {CheFileStructWorkspaceCommand} from "../../dir/chefile-struct/che-file-struct"; +import {CheFileStructWorkspaceCommandImpl} from "../../dir/chefile-struct/che-file-struct"; +import {Ssh} from "../../../api/wsmaster/ssh/ssh"; +/** + * This class is handling the connection to a workspace with default ssh key (or custom one) + * @author Florent Benoit + */ +export class WorkspaceSshAction { + + @Argument({description: "Defines the workspace to be used. use workspaceId, workspaceName or namespace:workspaceName as argument"}) + workspaceName : string; + + + @Parameter({names: ["-s", "--url"], description: "Defines the url to be used"}) + url : string; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + + args: Array; + authData: AuthData; + + fs = require('fs'); + path = require('path'); + + + private machineName : string; + + workspace : Workspace; + constructor(args:Array) { + this.args = ArgumentProcessor.inject(this, args); + this.authData = AuthData.parse(this.url, this.username, this.password); + // disable printing info + this.authData.printInfo = false; + Log.disablePrefix(); + this.workspace = new Workspace(this.authData); + + + // if extra args it's the machine name + if (this.args.length > 0) { + this.machineName = this.args[0]; + } else { + // default to dev-machine if not defined + this.machineName = "dev-machine"; + } + } + + run() : Promise { + // first, login + return this.authData.login().then(() => { + + let foundWorkspaceDTO : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + + let foundConfigMachineDTO; + + // then, search workspace + return this.workspace.searchWorkspace(this.workspaceName).then((workspaceDto) => { + + // check status + if ('RUNNING' !== workspaceDto.getStatus()) { + throw new Error('Workspace should be in running state. Current state is ' + workspaceDto.getStatus()); + } + + // Check ssh agent is there + let defaultEnv:string = workspaceDto.getConfig().getDefaultEnv(); + + let machineConfig : org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto = workspaceDto.getConfig().getEnvironments().get(defaultEnv).getMachines().get(this.machineName); + if (!machineConfig) { + throw new Error("Unable to find a machine named " + this.machineName + " in the workspace '" + this.workspaceName) + } + + let agents:Array = machineConfig.getAgents(); + + if (agents.indexOf('org.eclipse.che.ssh') === -1) { + return Promise.reject("The SSH agent (org.eclipse.che.ssh) has been disabled for this workspace.") + } + + foundWorkspaceDTO = workspaceDto; + + }).then((sshPairDto : org.eclipse.che.api.ssh.shared.dto.SshPairDto) => { + + // need to get ssh key for the workspace + let ssh:Ssh = new Ssh(this.authData); + return ssh.getPair("workspace", foundWorkspaceDTO.getId()); + }).then((sshPairDto : org.eclipse.che.api.ssh.shared.dto.SshPairDto) => { + + let machines : Array = foundWorkspaceDTO.getRuntime().getMachines(); + let runtime: org.eclipse.che.api.machine.shared.dto.MachineRuntimeInfoDto = this.getSelectedMachine(machines).getRuntime(); + let user : string = runtime.getProperties().get("config.user"); + if (user === "") { + // user is root if not defined + user = "root"; + } + let address: Array = runtime.getServers().get("22/tcp").getProperties().getInternalAddress().split(":"); + let ip:string = address[0]; + let port:string = address[1]; + var spawn = require('child_process').spawn; + + let username:string = user + "@" + ip; + let cmd : string = "$(cat >>/tmp/ssh.key < { + Log.getLogger().error(err); + }); + + p.on('exit', () => { + Log.getLogger().info('Ending ssh connection'); + }); + return Promise.resolve("ok"); + }); + }); + } + + private getSelectedMachine(machines : Array) : org.eclipse.che.api.machine.shared.dto.MachineDto { + for(let i : number=0; i; + + cheLauncherImageName : string; + + websocket: Websocket; + authData: AuthData; + workspace: Workspace; + + @Message('internal/dir/che-dir-constant') + i18n : I18n; + + constructor(args) { + this.args = ArgumentProcessor.inject(this, args); + + + this.currentFolder = this.path.resolve(args[0]); + this.folderName = this.path.basename(this.currentFolder); + this.cheFile = this.path.resolve(this.currentFolder, 'Chefile'); + this.dotCheFolder = this.path.resolve(this.currentFolder, '.che'); + this.dotCheIdFile = this.path.resolve(this.dotCheFolder, 'id'); + this.dotCheSshPrivateKeyFile = this.path.resolve(this.dotCheFolder, 'ssh-key.private'); + this.dotCheSshPublicKeyFile = this.path.resolve(this.dotCheFolder, 'ssh-key.public'); + this.workspacesFolder = this.path.resolve(this.dotCheFolder, 'workspaces'); + + this.initDefault(); + + this.websocket = new Websocket(); + + this.authData = new AuthData(); + + // che launcher image name + if (process.env.CHE_LAUNCHER_IMAGE_NAME) { + this.cheLauncherImageName = process.env.CHE_LAUNCHER_IMAGE_NAME + } else { + this.cheLauncherImageName = 'eclipse/che-launcher'; + } + } + + + + initDefault() { + this.chefileStruct = new CheFileStruct(); + this.chefileStruct.server.ip = new RemoteIp().getIp(); + // handle CHE_PORT if any + if (process.env.CHE_PORT) { + this.chefileStruct.server.port = process.env.CHE_PORT; + } else { + this.chefileStruct.server.port = 8080; + } + this.chefileStruct.server.type = 'local'; + + this.chefileStructWorkspace = new CheFileStructWorkspace(); + this.chefileStructWorkspace.name = 'local'; + this.chefileStructWorkspace.ram = 2048; + + try { + this.fs.statSync(this.dotCheIdFile); + // we have a file + this.instanceId = this.fs.readFileSync(this.dotCheIdFile).toString(); + } catch (e) { + this.instanceId = UUID.build(); + this.writeInstanceId(); + } + + /*Object.keys(process.env).forEach((key) => { + Log.getLogger().debug('Env variable', key, process.env[key]); + });*/ + + if (process.env.CHE_HOST_IP) { + this.chefileStruct.server.properties['CHE_HOST_IP'] = process.env.CHE_HOST_IP; + } + + + + } + + + + startsWith(value:string, searchString: string) : boolean { + return value.substr(0, searchString.length) === searchString; + } + + + parseArgument() : Promise { + return new Promise( (resolve, reject) => { + let invalidCommand : string = 'only init, up, down, ssh and status commands are supported.'; + if (this.args.length == 0) { + reject(invalidCommand); + } else if ('init' === this.args[1] + || 'up' === this.args[1] + || 'destroy' === this.args[1] + || 'factory' === this.args[1] + || 'down' === this.args[1] + || 'ssh' === this.args[1] + || 'status' === this.args[1]) { + // return method found based on arguments + resolve(this.args[1]); + } else { + reject('Invalid arguments ' + this.args +': ' + invalidCommand); + } + }); + + } + + run() : Promise { + Log.context = ProductName.getDisplayName() + '(dir)'; + + // call the method analyzed from the argument + return this.parseArgument().then((methodName) => { + return this[methodName](); + }) + + + } + + parse() { + + try { + this.fs.statSync(this.cheFile); + // we have a file + } catch (e) { + Log.getLogger().debug('No chefile defined, use default settings'); + return; + } + + // load the chefile script if defined + var script_code = this.fs.readFileSync(this.cheFile).toString(); + + // strip the lines that are beginning with # as it may be comments + script_code = script_code.replace(/#[^\n]*/g, ''); + + // create sandboxed object + var sandbox = { "che": this.chefileStruct, "workspace": this.chefileStructWorkspace, "console": console}; + + let options = { + filename : this.cheFile, + displayErrors : true + }; + + try { + this.vm.runInNewContext(script_code, sandbox, options); + } catch (error) { + if (error.stack) { + // search correct line + let splitLines = error.stack.split('\n'); + var found : boolean = false; + var i : number = 0; + while (!found && i < splitLines.length) { + let currentStackLine = splitLines[i]; + if (currentStackLine.indexOf(this.cheFile) != -1) { + // found matching line + found = true; + let splitColumns = currentStackLine.split(':'); + // check line number only or both line+column number + if (splitColumns.length == 3) { + // line and column number + let lineNumber = splitColumns[1]; + let colNumber = splitColumns[2]; + throw new Error('Error while parsing the file \'' + this.cheFile + '\' at line ' + lineNumber + ' and column ' + colNumber + '. The error is :' + error.message); + } else if (splitColumns.length == 2) { + // only line number + let lineNumber = splitColumns[1]; + throw new Error('Error while parsing the file \'' + this.cheFile + '\' at line ' + lineNumber + '. The error is :' + error.message); + } + } + i++; + } + } + // not able to parse error + throw error; + } + + this.cleanupArrays(); + + Log.getLogger().debug('Che file parsing object is ', JSON.stringify(this.chefileStruct)); + Log.getLogger().debug('Che workspace parsing object is ', JSON.stringify(this.chefileStructWorkspace)); + + this.authData.port = this.chefileStruct.server.port; + + } + + + /** + * Cleanup arrays by removing extra elements + */ + cleanupArrays() { + // now, cleanup invalid commands + for (let i : number = this.chefileStructWorkspace.commands.length - 1; i >= 0 ; i--) { + // no name, drop it + if (!this.chefileStructWorkspace.commands[i].name) { + this.chefileStructWorkspace.commands.splice(i, 1); + } + } + // now, cleanup invalid commands + for (let i : number = this.chefileStructWorkspace.postload.actions.length - 1; i >= 0 ; i--) { + // no name, drop it + if (!this.chefileStructWorkspace.postload.actions[i].command && !this.chefileStructWorkspace.postload.actions[i].script) { + this.chefileStructWorkspace.postload.actions.splice(i, 1); + } + } + + // now, cleanup invalid projects + for (let i : number = this.chefileStructWorkspace.projects.length - 1; i >= 1 ; i--) { + // no name, drop it + if (!this.chefileStructWorkspace.projects[i].name) { + this.chefileStructWorkspace.projects.splice(i, 1); + } + } + + + } + + /** + * Check if directory has been initialized or not + * @return true if initialization has been done + */ + isInitialized() : Promise { + return new Promise((resolve) => { + try { + this.fs.statSync(this.dotCheFolder); + resolve(true); + } catch (e) { + resolve(false); + } + }); + + } + + + /** + * Write a default chefile + */ + writeDefaultChefile() { + + + // + this.chefileStructWorkspace.commands[0].name = "my-first-command"; + this.chefileStructWorkspace.commands[0].commandLine = "echo this is my first command && read"; + this.chefileStructWorkspace.postload.actions[0].command = "my-first-command"; + this.chefileStructWorkspace.postload.actions[1].script = "echo 'this is my custom command' && while true; do echo $(date); sleep 1; done"; + + // remove empty values + this.cleanupArrays(); + + // create content to write + let content = ''; + + // work on a copy + let che : CheFileStruct = JSON.parse(JSON.stringify(this.chefileStruct)); + + // make flat the che object + let flatChe = this.flatJson('che', che); + flatChe.forEach((value, key) => { + Log.getLogger().debug( 'the value is ' + value.toString() + ' for key' + key); + if (key !== 'che.server.ip') { + content += key + '=' + value.toString() + '\n'; + } + }); + + // make flat the workspace object + let flatWorkspace = this.flatJson('workspace', this.chefileStructWorkspace); + flatWorkspace.forEach((value, key) => { + Log.getLogger().debug( 'the flatWorkspace value is ' + value.toString() + ' for key' + key); + content += key + '=' + value.toString() + '\n'; + }); + + // write content of this.che object + this.fs.writeFileSync(this.cheFile, content); + Log.getLogger().info('Generating default', this.cheFile); + + + try { + this.fs.chownSync(this.cheFile, 1000, 1000); + } catch (error) { + Log.getLogger().debug("Unable to chown che file", this.cheFile); + } + + + } + + + init() : Promise { + return this.isInitialized().then((isInitialized) => { + if (isInitialized) { + Log.getLogger().warn('Che already initialized'); + } else { + // needs to create folders + this.initCheFolders(); + + // write a default chefile if there is none + try { + this.fs.statSync(this.cheFile); + Log.getLogger().debug('Chefile is present at ', this.cheFile); + } catch (e) { + // write default + Log.getLogger().debug('Write a default Chefile at ', this.cheFile); + this.writeDefaultChefile(); + } + Log.getLogger().info('Adding', this.dotCheFolder, 'directory'); + return true; + } + + }); + + } + + status() : Promise { + return this.isInitialized().then((isInitialized) => { + if (!isInitialized) { + return Promise.reject('This directory has not been initialized. So, status is not available.'); + } + + return new Promise((resolve, reject) => { + this.parse(); + resolve('parsed'); + }).then(() => { + return this.checkCheIsRunning(); + }).then((isRunning) => { + if (!isRunning) { + return Promise.reject('No Eclipse Che Instance Running.'); + } + + // check workspace exists + this.workspace = new Workspace(this.authData); + return this.workspace.existsWorkspace(':' + this.chefileStructWorkspace.name); + }).then((workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) => { + // found it + if (!workspaceDto) { + return Promise.reject('Eclipse Che is running ' + this.buildLocalCheURL() + ' but workspace (' + this.chefileStructWorkspace.name + ') has not been found'); + } + + // search IDE url link + let ideUrl : string = 'N/A'; + workspaceDto.getLinks().forEach((link) => { + if ('ide url' === link.getRel()) { + ideUrl = link.getHref(); + } + }); + Log.getLogger().info(this.i18n.get('status.workspace.name', this.chefileStructWorkspace.name)); + Log.getLogger().info(this.i18n.get('status.workspace.url', ideUrl)); + Log.getLogger().info(this.i18n.get('status.instance.id', this.instanceId)); + return Promise.resolve(true); + }); + }); + + } + + + /** + * Search a che instance and stop it it it's currently running + */ + down() : Promise { + + // call init if not initialized and then call up + return this.isInitialized().then((isInitialized) => { + if (!isInitialized) { + throw new Error('Unable to stop current instance as this directory has not been initialized.') + } + }).then(() => { + + return new Promise((resolve, reject) => { + this.parse(); + + resolve(); + }).then(() => { + Log.getLogger().info(this.i18n.get('down.search')); + + // Try to connect to Eclipse Che instance + return this.checkCheIsRunning(); + }).then((isRunning) => { + if (!isRunning) { + return Promise.reject(this.i18n.get('down.not-running')); + } + Log.getLogger().info(this.i18n.get('down.found', this.buildLocalCheURL())); + Log.getLogger().info(this.i18n.get('down.stopping')); + + // call docker stop on the docker launcher + return this.cheStop(); + }).then(() => { + Log.getLogger().info(this.i18n.get('down.stopped')); + }); + }); + } + + + + /** + * Search a che instance and destroy workspace and then stop + */ + destroy() : Promise { + + // check if directory has been initialized or not + return this.isInitialized().then((isInitialized) => { + if (!isInitialized) { + throw new Error('Unable to stop current instance as this directory has not been initialized.') + } + }).then(() => { + + return new Promise((resolve, reject) => { + this.parse(); + + resolve(); + }).then(() => { + Log.getLogger().info(this.i18n.get('down.search')); + + // Try to connect to Eclipse Che instance + return this.checkCheIsRunning(); + }).then((isRunning) => { + if (!isRunning) { + return Promise.reject(this.i18n.get('down.not-running')); + } + Log.getLogger().info(this.i18n.get('down.found', this.buildLocalCheURL())); + this.workspace = new Workspace(this.authData); + // now, check if there is a workspace + return this.workspace.existsWorkspace(':' + this.chefileStructWorkspace.name); + }).then((workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) => { + // exists ? + if (!workspaceDto) { + // workspace is not existing + Log.getLogger().warn(this.i18n.get('destroy.workspace-not-existing', this.chefileStructWorkspace.name)); + // call docker stop on the docker launcher + Log.getLogger().info(this.i18n.get('down.stopping')); + return this.cheStop(); + } else { + // first stop and then delete workspace + Log.getLogger().info(this.i18n.get('destroy.destroying-workspace', this.chefileStructWorkspace.name)); + return this.workspace.stopWorkspace(workspaceDto.getId()).then(() => { + return this.workspace.deleteWorkspace(workspaceDto.getId()); + }).then(() => { + Log.getLogger().info(this.i18n.get('destroy.destroyed-workspace', this.chefileStructWorkspace.name)); + // then stop server + Log.getLogger().info(this.i18n.get('down.stopping')); + return this.cheStop(); + }); + } + }).then(() => { + Log.getLogger().info(this.i18n.get('down.stopped')); + }); + }); + } + + + buildWorkspaceConfig() : CreateWorkspaceConfig { + let createWorkspaceConfig:CreateWorkspaceConfig = new CreateWorkspaceConfig(); + + let recipe: string = new RecipeBuilder(this.currentFolder).getRecipe(this.chefileStructWorkspace); + createWorkspaceConfig.machineConfigSource = recipe; + createWorkspaceConfig.commands = this.chefileStructWorkspace.commands; + createWorkspaceConfig.name = this.chefileStructWorkspace.name; + createWorkspaceConfig.ram = this.chefileStructWorkspace.ram; + + return createWorkspaceConfig; + } + + + up() : Promise { + let start : number = Date.now(); + // call init if not initialized and then call up + return this.isInitialized().then((isInitialized) => { + if (!isInitialized) { + return this.init(); + } + }).then(() => { + + + var ideUrl : string; + + var needToSetupProject: boolean = true; + var userWorkspaceDto: org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; + var workspaceHasBeenCreated : boolean = false; + return new Promise((resolve, reject) => { + this.parse(); + resolve('parsed'); + }).then(() => { + return this.checkCheIsNotRunning(); + }).then((isNotRunning) => { + return new Promise((resolve, reject) => { + if (isNotRunning) { + resolve(true); + } else { + reject(this.i18n.get('up.existinginstance')); + } + }); + }).then((checkOk) => { + Log.getLogger().info(this.i18n.get('up.starting')); + // needs to invoke docker run + return this.cheBoot(); + }).then((data) => { + // loop to check startup (during 30seconds) + return this.loopWaitChePing(); + }).then((value) => { + Log.getLogger().info(this.i18n.get('up.running', this.buildLocalCheURL())); + // check workspace exists + this.workspace = new Workspace(this.authData); + return this.workspace.existsWorkspace(':' + this.chefileStructWorkspace.name); + }).then((workspaceDto) => { + // found it + if (!workspaceDto) { + // workspace is not existing + // now create the workspace + let createWorkspaceConfig:CreateWorkspaceConfig = this.buildWorkspaceConfig(); + Log.getLogger().info(this.i18n.get('up.workspace-created')); + workspaceHasBeenCreated = true; + return this.workspace.createWorkspace(createWorkspaceConfig) + } else { + // do not create it, just return current one + Log.getLogger().info(this.i18n.get('up.workspace-previous-start')); + needToSetupProject = false; + return workspaceDto; + } + }).then((workspaceDto) => { + Log.getLogger().info(this.i18n.get('up.workspace-booting')); + return this.workspace.startWorkspace(workspaceDto.getId(), this.isVerbose); + }).then((workspaceDto) => { + return this.workspace.getWorkspace(workspaceDto.getId()) + }).then((workspaceDto) => { + userWorkspaceDto = workspaceDto; + }).then(() => { + return this.setupSSHKeys(userWorkspaceDto); + }).then(() => { + if (needToSetupProject) { + return this.setupProjects(userWorkspaceDto); + } else { + return Promise.resolve('existing project'); + } + }).then(() => { + return this.executeCommandsFromCurrentWorkspace(userWorkspaceDto); + }).then(() => { + Log.getLogger().info(this.i18n.get('up.workspace-booted')); + }).then(() => { + let end : number = Date.now(); + Log.getLogger().debug("time =", end - start); + Log.getLogger().info(this.i18n.get('up.workspace-connect-to', this.buildLocalIDEUrl())); + return ideUrl; + }); + + }); + } + + + setupProjects(workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) : any { + let promises : Array> = new Array>(); + Log.getLogger().info(this.i18n.get('up.updating-project')); + + var projectAPI:Project = new Project(workspaceDto); + + this.chefileStructWorkspace.projects.forEach(project => { + // no location, use inner project + if (!project.source.location) { + promises.push(this.estimateAndUpdateProject(projectAPI, this.folderName, project.type)); + } else { + // need to import project + let promise = new Promise((resolve, reject) => { + + let sourceStorageDto : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto = this.getSourceStorageDto(project); + + return projectAPI.importProject(project.name, sourceStorageDto).then(() => { + this.estimateAndUpdateProject(projectAPI, project.name, project.type, sourceStorageDto).then(() => { + resolve(true); + }); + }, (error) => { + reject('Unable to import project ' + project.name + '. Error is : ' + error); + }); + }); + promises.push(promise); + } + }); + + + // update created project to given project type + return Promise.all(promises); + + } + + /** + * get source storage DTO + */ + getSourceStorageDto(project : CheFileStructWorkspaceProject) : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto { + + let sourceStorageDto : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto = new org.eclipse.che.api.workspace.shared.dto.SourceStorageDtoImpl(); + sourceStorageDto.withLocation(project.source.location).withType(project.source.type); + return sourceStorageDto; + } + + + rsyncProject(workspaceDto: org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) : Promise { + var spawn = require('child_process').spawn; + let port: string = workspaceDto.getRuntime().getDevMachine().getRuntime().getServers()["22/tcp"].getAddress().split(":")[1]; + let username : string = "user@" + this.chefileStruct.server.ip; + + + var execSync = require('child_process').execSync; + let containerVersion : string = new ContainerVersion().getVersion(); + let output:string = execSync('docker run -v ' + this.currentFolder + ':' + this.currentFolder + ' -v ' + this.dotCheSshPrivateKeyFile + ':/tmp/ssh.key' + ' -t florentdemo:rsync rsync -ar -e "ssh -p ' + port + ' -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /tmp/ssh.key" --exclude "node_modules" --exclude "target" ' + this.currentFolder + ' ' + username + ':/projects/'); + + return Promise.resolve("ok"); + } + +setupSSHKeys(workspaceDto: org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) : Promise { + + let privateKey : string; + let publicKey : string; + // check if we have keys locally or not ? + try { + this.fs.statSync(this.dotCheSshPrivateKeyFile); + // we have the file + privateKey = this.fs.readFileSync(this.dotCheSshPrivateKeyFile).toString(); + publicKey = this.fs.readFileSync(this.dotCheSshPublicKeyFile).toString(); + Log.getLogger().info('Using existing ssh key'); + } catch (e) { + // no file, need to generate key + Log.getLogger().info('Generating ssh key'); + let map : Map = new SSHGenerator().generateKey(); + + // store locally the private and public keys + privateKey = map.get('private'); + publicKey = map.get('public'); + this.fs.writeFileSync(this.dotCheSshPrivateKeyFile, privateKey, { mode: 0o600 }); + this.fs.writeFileSync(this.dotCheSshPublicKeyFile, publicKey); + + try { + this.fs.chownSync(this.dotCheSshPrivateKeyFile, 1000, 1000); + } catch (error) { + Log.getLogger().debug("Unable to chown ssh key private file", this.dotCheSshPrivateKeyFile); + } + + } + + // ok we have the public key, now storing it + // get dev machine + let machineId : string = workspaceDto.getRuntime().getDevMachine().getId(); + + let machineServiceClient:MachineServiceClientImpl = new MachineServiceClientImpl(this.workspace, this.authData); + + let uuid:string = UUID.build(); + let channel:string = 'process:output:' + uuid; + + let customCommand:CheFileStructWorkspaceCommand = new CheFileStructWorkspaceCommandImpl(); + customCommand.commandLine = '(mkdir $HOME/.ssh || true) && echo "' + publicKey + '">> $HOME/.ssh/authorized_keys'; + customCommand.name = 'setup ssh'; + customCommand.type = 'custom'; + + // store in workspace the public key + return machineServiceClient.executeCommand(workspaceDto, machineId, customCommand, channel, false); + +} + + + ssh() : Promise { + return this.isInitialized().then((isInitialized) => { + if (!isInitialized) { + return Promise.reject('This directory has not been initialized. So, ssh is not available.'); + } + + return new Promise((resolve, reject) => { + this.parse(); + resolve('parsed'); + }).then(() => { + return this.checkCheIsRunning(); + }).then((isRunning) => { + if (!isRunning) { + return Promise.reject('No Eclipse Che Instance Running.'); + } + + // check workspace exists + this.workspace = new Workspace(this.authData); + return this.workspace.existsWorkspace(':' + this.chefileStructWorkspace.name); + }).then((workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) => { + // found it + if (!workspaceDto) { + return Promise.reject('Eclipse Che is running ' + this.buildLocalCheURL() + ' but workspace (' + this.chefileStructWorkspace.name + ') has not been found'); + } + + // Check ssh agent is there + let defaultEnv : string = workspaceDto.getConfig().getDefaultEnv(); + let agents : Array = workspaceDto.getConfig().getEnvironments().get(defaultEnv).getMachines().get("dev-machine").getAgents(); + + if (agents.indexOf('org.eclipse.che.ssh') === - 1) { + return Promise.reject("The SSH agent (org.eclipse.che.ssh) has been disabled for this workspace.") + } + + let port: string = workspaceDto.getRuntime().getDevMachine().getRuntime().getServers().get("22/tcp").getAddress().split(":")[1]; + var spawn = require('child_process').spawn; + + let username : string = "user@" + this.chefileStruct.server.ip; + + var p = spawn("docker", ["run", "-v", this.dotCheSshPrivateKeyFile + ":/tmp/ssh.key", "-ti", "codenvy/alpine_jdk8", "ssh", "-o", "UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no", username, "-p", port, "-i", "/tmp/ssh.key"], { + stdio: 'inherit' + }); + + p.on('error', (err) => { + Log.getLogger().error(err); + }); + + p.on('exit', () => { + Log.getLogger().info('Ending ssh connection'); + }); + return Promise.resolve("ok"); + }) + }); + } + + + + + estimateAndUpdateProject(projectAPI: Project, projectName: string, projectType: string, sourceStorageDto? : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto) : Promise { + Log.getLogger().debug('estimateAndUpdateProject with project', projectName, 'and projectType', projectType); + + var projectTypeToUse: string; + // try to estimate + return projectAPI.estimateType(projectName, projectType).then((content) => { + if (!content.isMatched()) { + Log.getLogger().warn('Wanted to configure project as ' + projectType + ' but server replied that this project type is not possible. Keep Blank'); + projectTypeToUse = 'blank'; + } else { + projectTypeToUse = projectType; + } + // matched = true, then continue + return true; + }).then(() => { + // grab project DTO + return projectAPI.getProject(projectName) + }).then((projectDto) => { + // then update the project type + projectDto.setType(projectTypeToUse); + + // source storage + if (sourceStorageDto) { + projectDto.setSource(sourceStorageDto); + } + + return projectDto; + }).then((projectDto) => { + // and perform update of all these attributes + return projectAPI.update(projectName, projectDto); + }); + + + } + + + + + executeCommandsFromCurrentWorkspace(workspaceDto : org.eclipse.che.api.workspace.shared.dto.WorkspaceDto) : Promise { + // get dev machine + let machineId : string = workspaceDto.getRuntime().getDevMachine().getId(); + + + let promises : Array> = new Array>(); + let workspaceCommands : Array = workspaceDto.getConfig().getCommands(); + let machineServiceClient:MachineServiceClientImpl = new MachineServiceClientImpl(this.workspace, this.authData); + + if (this.chefileStructWorkspace.postload.actions && this.chefileStructWorkspace.postload.actions.length > 0) { + Log.getLogger().info(this.i18n.get("executeCommandsFromCurrentWorkspace.executing")); + } + + this.chefileStructWorkspace.postload.actions.forEach((postLoadingCommand: CheFileStructWorkspaceLoadingAction) => { + let uuid:string = UUID.build(); + let channel:string = 'process:output:' + uuid; + + if (postLoadingCommand.command) { + workspaceCommands.forEach((workspaceCommand) => { + if (postLoadingCommand.command === workspaceCommand.name) { + let customCommand:CheFileStructWorkspaceCommand = new CheFileStructWorkspaceCommandImpl(); + customCommand.commandLine = workspaceCommand.commandLine; + customCommand.name = workspaceCommand.name; + customCommand.type = workspaceCommand.type; + customCommand.attributes = workspaceCommand.attributes; + Log.getLogger().debug('Executing post-loading workspace command \'' + postLoadingCommand.command + '\'.'); + promises.push(machineServiceClient.executeCommand(workspaceDto, machineId, customCommand, channel, false)); + } + }); + } else if (postLoadingCommand.script) { + let customCommand:CheFileStructWorkspaceCommand = new CheFileStructWorkspaceCommandImpl(); + customCommand.commandLine = postLoadingCommand.script; + customCommand.name = 'custom postloading command'; + Log.getLogger().debug('Executing post-loading script \'' + postLoadingCommand.script + '\'.'); + promises.push(machineServiceClient.executeCommand(workspaceDto, machineId, customCommand, channel, false)); + } + + + }); + + return Promise.all(promises); + } + + + + + buildLocalCheURL() : string { + + // handle special docerk4 mac, docker for windows ip + let ip : string = this.chefileStruct.server.ip; + if (ip === '192.168.65.2' || ip === '10.0.75.2') { + ip = 'localhost'; + } + + return 'http://' + ip + ':' + this.chefileStruct.server.port; + } + + buildLocalIDEUrl() : string { + return this.buildLocalCheURL() + "/dashboard/#/ide/che/local"; + } + + + initCheFolders() { + + // create .che folder + try { + this.fs.mkdirSync(this.dotCheFolder, 0o744); + } catch (e) { + // already exist + } + + // write instance id + this.writeInstanceId(); + + // create .che/workspaces folder + try { + this.fs.mkdirSync(this.workspacesFolder, 0o744); + } catch (e) { + // already exist + } + + } + + writeInstanceId() { + try { + this.fs.writeFileSync(this.dotCheIdFile, this.instanceId); + } catch (e) { + // already exist + } + } + + getCheServerContainerName() : string { + return 'che-server-' + this.instanceId; + } + + cheBoot() : Promise { + + let promise : Promise = new Promise((resolve, reject) => { + let containerVersion : string = new ContainerVersion().getVersion(); + + // create command line to execute + var commandLine: string = 'docker run --rm'; + + // add extra properties + // need to setup che.properties file with workspaces folder + this.chefileStruct.server.properties["CHE_WORKSPACE_VOLUME"] = this.currentFolder + ':/projects/' + this.folderName + ";/var/run/docker.sock:/var/run/docker.sock"; + this.chefileStruct.server.properties["CHE_WORKSPACE_STORAGE"] = this.workspacesFolder; + + for(var property in this.chefileStruct.server.properties){ + let envProperty : string = ' --env ' + property + '=\"' + this.chefileStruct.server.properties[property] + '\"'; + commandLine += envProperty; + } + + // continue with own properties + commandLine += + ' -v /var/run/docker.sock:/var/run/docker.sock' + + ' -e CHE_PORT=' + this.chefileStruct.server.port + + ' -e CHE_DATA=' + this.workspacesFolder + + ' -e CHE_SERVER_CONTAINER_NAME=' + this.getCheServerContainerName() + + ' ' + this.cheLauncherImageName + ':' + containerVersion + ' start'; + + Log.getLogger().debug('Executing command line', commandLine); + + + var child = this.exec(commandLine , (error, stdout, stderr) => { + if (error) { + Log.getLogger().error('Error when starting che with che-launcher: ' + error.toString() + '. exit code was ' + error.code); + Log.getLogger().error('Startup traces were on stdout:\n', stdout.toString()); + Log.getLogger().error('Startup traces were on stderr:\n', stderr.toString()); + } else { + resolve({ + childProcess: child, + stdout: stdout, + stderr: stderr + }); + } + }); + + child.stdout.on('data', (data) => { + Log.getLogger().debug(data.toString()); + }); + + + child.on('exit', (exitCode) => { + if (exitCode == 0) { + resolve('success'); + } else { + reject('process has exited'); + } + + }); + + }); + + return promise; + + } + + + + cheStop() : Promise { + + let promise : Promise = new Promise((resolve, reject) => { + let containerVersion : string = new ContainerVersion().getVersion(); + + var commandLine: string = 'docker run --rm' + + ' -v /var/run/docker.sock:/var/run/docker.sock' + + ' -e CHE_PORT=' + this.chefileStruct.server.port + + ' -e CHE_DATA=' + this.workspacesFolder + + ' -e CHE_SERVER_CONTAINER_NAME=' + this.getCheServerContainerName() + + ' ' + this.cheLauncherImageName + ':' + containerVersion + ' stop'; + + Log.getLogger().debug('Executing command line', commandLine); + + + var child = this.exec(commandLine , (error, stdout, stderr) => { + if (error) { + Log.getLogger().error('Error when stopping che with che-launcher: ' + error.toString() + '. exit code was ' + error.code); + Log.getLogger().error('Stopping traces were on stdout:\n', stdout.toString()); + Log.getLogger().error('Stopping traces were on stderr:\n', stderr.toString()); + } else { + resolve({ + childProcess: child, + stdout: stdout, + stderr: stderr + }); + } + }); + + child.stdout.on('data', (data) => { + Log.getLogger().debug(data.toString()); + }); + + + child.on('exit', (exitCode) => { + if (exitCode == 0) { + resolve('success'); + } else { + reject('process has exited'); + } + + }); + + }); + + return promise; + + } + + + checkCheIsNotRunning() : Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace', 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return false; + }, (error) => { + // find error when connecting so probaly not running + return true; + }); + } + + + checkCheIsRunning() : Promise { + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/workspace', 200); + return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { + return true; + }, (error) => { + // find error when connecting so probaly not running + return false; + }); + } + + + pingCheAction() : void { + var options = { + hostname: this.chefileStruct.server.ip, + port: this.chefileStruct.server.port, + path: '/api/workspace', + method: 'GET', + headers: { + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': 'application/json;charset=UTF-8' + } + }; + + var req = this.http.request(options, (res) => { + res.on('data', (body) => { + Log.getLogger().debug('got rest status code =', res.statusCode); + if (res.statusCode === 200 && !this.waitDone) { + Log.getLogger().debug('got 200 status, stop waiting'); + this.waitDone = true; + } + }); + }); + req.on('error', (e) => { + Log.getLogger().debug('Got error when waiting che boot: ' + e.message); + }); + req.end(); + + } + + + /** + * Loop to send ping action each second and then try to see if we need to wait or not again + */ + loopWaitChePing() : Promise { + return new Promise((resolve, reject) => { + var loop = () => { + this.pingCheAction(); + if (this.waitDone) { + resolve(true); + } else { + Log.getLogger().debug('pinging che was not ready, continue ', this.times, ' times.'); + this.times--; + if (this.times === 0) { + reject('Timeout for pinging Eclipse Che has been reached. Please check logs.'); + } else { + // loop again + setTimeout(loop, 1000); + } + } + }; + process.nextTick(loop); + }); + } + + + + + + /** + * Flatten a JSON object and return a map of string with key and value + * @param prefix the prefix to use in order to flatten given object instance + * @param data the JSON object + * @returns {Map} the flatten map + */ + flatJson(prefix, data) : Map { + var map = new Map(); + + this.recurseFlatten(map, data, prefix); + return map; + } + + + /** + * Recursive method to iterate on elements of a JSON object. + * @param map the map containing the key being the property name and the value the JSON element value + * @param jsonData the data to parse + * @param prop the nme of the property being analyzed + */ + recurseFlatten(map : Map, jsonData: any, prop: string) : void { + + if (Object(jsonData) !== jsonData) { + if (this.isNumber(jsonData)) { + map.set(prop, jsonData); + } else { + map.set(prop, "\"" + jsonData + "\""); + } + } else if (Array.isArray(jsonData)) { + let arr : Array = jsonData; + let l: number = arr.length; + if (l == 0) { + map.set(prop, '[]'); + } else { + for(var i : number =0 ; i { + return this.isInitialized().then((isInitialized) => { + if (!isInitialized) { + return Promise.reject('This directory has not been initialized. So, factory export is not available.'); + } + + return new Promise((resolve, reject) => { + this.parse(); + resolve('parsed'); + }).then(() => { + + // check workspace exists + this.workspace = new Workspace(this.authData); + + // take current Chefile and export it as a factory + + + let factoryToCreate:org.eclipse.che.api.factory.shared.dto.FactoryDto = new org.eclipse.che.api.factory.shared.dto.FactoryDtoImpl(); + + + // get workspace object + let createWorkspaceConfig:CreateWorkspaceConfig = this.buildWorkspaceConfig(); + let workspaceConfigDto:org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto = this.workspace.getWorkspaceConfigDto(createWorkspaceConfig); + + factoryToCreate.withV("4.0").withName(this.folderName).withWorkspace(workspaceConfigDto); + + + // add project + let sourceStorageDTO : org.eclipse.che.api.workspace.shared.dto.SourceStorageDto = new org.eclipse.che.api.workspace.shared.dto.SourceStorageDtoImpl(); + + // do we have git there ? + let dotGitFolder : string = this.path.resolve(this.currentFolder, '.git'); + try { + this.fs.statSync(dotGitFolder); + // we have a .git folder + sourceStorageDTO.withType("git"); + + // grab the location URL + let configContent = this.fs.readFileSync(this.path.resolve(dotGitFolder, "config")).toString(); + + var regex = /remote "origin".*?\n.*?url = (.*)/g + ///url = (.*)/g; + var matches = regex.exec(configContent); + if (matches === null) { + return Promise.reject("Found a .git/config file but no remote origin found inside."); + } + let gitURL = matches[1]; + sourceStorageDTO.withLocation(gitURL) ; + + } catch (e) { + return Promise.reject("Factories are only working if there is a project inside. No git metadata has been found"); + } + + let projectDTO : org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto = new org.eclipse.che.api.workspace.shared.dto.ProjectConfigDtoImpl(); + projectDTO.setType(this.chefileStructWorkspace.projects[0].type); + projectDTO.withName(this.folderName).withPath("/" + this.folderName).withSource(sourceStorageDTO); + + workspaceConfigDto.getProjects().push(projectDTO); + + Log.getLogger().info('Factory JSON is :\n' + JSON.stringify(factoryToCreate.toJson(), null, 2)); + return Promise.resolve(true); + }) + }); + + } + + isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + + +} diff --git a/dockerfiles/lib-typescript/src/internal/dir/chefile-struct/che-file-struct.ts b/dockerfiles/lib-typescript/src/internal/dir/chefile-struct/che-file-struct.ts new file mode 100644 index 00000000000..5174c45e6cd --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/dir/chefile-struct/che-file-struct.ts @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +export class CheFileStruct { + server: CheFileServerStruct; + + constructor() { + this.server = new CheFileServerStruct(); + } +} + +export type CheFileServerTypeStruct = 'local' | 'remote'; + +export class CheFileServerStruct { + + type : CheFileServerTypeStruct; + ip: string; + port: number; + user: string; + pass: string; + startup: Array; + + properties : Map; + + constructor() { + //this.startup = new Array(); + this.properties = new Map(); + } +} + + + +export class CheFileStructWorkspaceCommandAttributes { + previewUrl: string; +} + +export interface CheFileStructWorkspaceCommand { + name: string; + type: string; + commandLine: string; + attributes? : CheFileStructWorkspaceCommandAttributes; +} + +export class CheFileStructWorkspaceCommandImpl implements CheFileStructWorkspaceCommand{ + name: string; + type: string; + commandLine: string; + attributes : CheFileStructWorkspaceCommandAttributes; + + constructor() { + this.type = 'custom'; + this.attributes = new CheFileStructWorkspaceCommandAttributes(); + } +} + + +export class CheFileStructWorkspaceProjectSourceImpl { + attributes : Map; + location: string; + type: string; + + constructor() { + this.attributes = new Map(); + } +} + +export interface CheFileStructWorkspaceProject { + type: string; + name : string; + source : CheFileStructWorkspaceProjectSourceImpl; +} + +export class CheFileStructWorkspaceProjectImpl implements CheFileStructWorkspaceProject{ + type: string; + name : string; + source : CheFileStructWorkspaceProjectSourceImpl; + constructor() { + this.type = 'blank'; + this.source = new CheFileStructWorkspaceProjectSourceImpl(); + } +} + + +export class CheFileStructWorkspace { + + name: string; + + ram: number; + commands : Array; + + postload : CheFileStructWorkspacePostLoad; + + runtime : CheFileStructWorkspaceRuntime; + + projects: Array; + + constructor() { + this.commands = new Array(); + this.projects = new Array(); + this.postload = new CheFileStructWorkspacePostLoad(); + this.runtime = new CheFileStructWorkspaceRuntime(); + // init some commands + for (let i : number = 0; i < 255; i++) { + this.commands[i] = new CheFileStructWorkspaceCommandImpl(); + } + + // init some commands + for (let i : number = 0; i < 255; i++) { + this.projects[i] = new CheFileStructWorkspaceProjectImpl(); + } + + } +} + + +export class CheFileStructWorkspaceRuntimeDocker { + content : string; + image : string; + location: string; +} + +export class CheFileStructWorkspaceRuntime { + docker : CheFileStructWorkspaceRuntimeDocker; + + constructor() { + this.docker = new CheFileStructWorkspaceRuntimeDocker(); + } +} + +export class CheFileStructWorkspaceLoadingAction { + command: string; + + script : string; +} + +export class CheFileStructWorkspacePostLoad { + actions : Array; + + constructor() { + this.actions = new Array(); + // init some commands + for (let i : number = 0; i < 255; i++) { + this.actions[i] = new CheFileStructWorkspaceLoadingAction(); + } + + } +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/internal/test/che-test.ts b/dockerfiles/lib-typescript/src/internal/test/che-test.ts new file mode 100644 index 00000000000..fd2345cd63d --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/test/che-test.ts @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +// imports + + +import {Argument} from "../../spi/decorator/parameter"; +import {ArgumentProcessor} from "../../spi/decorator/argument-processor"; +import {PostFlightCheckTest} from "./impl/post-flight-check-test"; +import {Log} from "../../spi/log/log"; +import {ProductName} from "../../utils/product-name"; +/** + * Entrypoint for the Tests. + * @author Florent Benoit + */ +export class CheTest { + + /** + * This test name will be injected automatically. + */ + @Argument({description: "Name of the test to execute"}) + testName : string; + + /** + * Parsing of arguments. + */ + args : Array; + + /** + * Map of tests that are available. + */ + mapOfTests : Map = CheTest.init(); + + static init() : Map { + Log.context = ProductName.getDisplayName() + '(test)'; + let testMap : Map = new Map(); + testMap.set('post-flight-check', PostFlightCheckTest); + return testMap; + } + + /** + * Analyze the arguments by injecting parameters/arguments and define the list of test classes. + * @param args + */ + constructor(args:Array) { + this.args = ArgumentProcessor.inject(this, args); + } + + /** + * Run this che-test entry point. + * When a test is found, build an instance of the test and call run() method which returns a promise + */ + run() : Promise { + let classOfTest: any = this.mapOfTests.get(this.testName); + if (classOfTest) { + // update logger + Log.context = ProductName.getDisplayName() + '(test/' + this.testName + ')'; + var instance = new classOfTest(this.args); + return instance.run(); + } else { + // The given test name has not been found, display available actions + Log.getLogger().error("No test exists with provided name '" + this.testName + "'."); + this.help(); + process.exit(1); + } + } + + + + help() : void { + Log.getLogger().info("Available tests are : "); + for (var [key, value] of this.mapOfTests.entries()) { + Log.getLogger().info('\u001b[1m' + key + '\u001b[0m'); + ArgumentProcessor.help(Object.create(value.prototype)); + } + } + +} diff --git a/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.properties b/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.properties new file mode 100644 index 00000000000..ae0296ca5bd --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2016-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Codenvy, S.A. - initial API and implementation +# + +run.generating=Generating {0} workspace +run.starting-workspace=Starting workspace runtime +run.stopping-workspace=Stopping workspace runtime +run.deleting-workspace=Deleting workspace runtime diff --git a/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.ts b/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.ts new file mode 100644 index 00000000000..d4d523ce76e --- /dev/null +++ b/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.ts @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +// imports +import {Parameter} from "../../../spi/decorator/parameter"; +import {AuthData} from "../../../api/wsmaster/auth/auth-data"; +import {Workspace} from "../../../api/wsmaster/workspace/workspace"; +import {ArgumentProcessor} from "../../../spi/decorator/argument-processor"; +import {CreateWorkspaceConfig} from "../../../api/wsmaster/workspace/workspace"; +import {Log} from "../../../spi/log/log"; +import {I18n} from "../../../spi/i18n/i18n"; +import {Message} from "../../../spi/decorator/message"; +import {org} from "../../../api/dto/che-dto"; + +/** + * This class is managing a post-check operation by creating a workspace, starting it and displaying the log data. + * @author Florent Benoit + */ +export class PostFlightCheckTest { + + @Parameter({names: ["-q", "--quiet"], description: "Run in quiet mode for this test."}) + isQuiet : boolean = false; + + @Parameter({names: ["-u", "--user"], description: "Defines the user to be used"}) + username : string; + + @Parameter({names: ["-w", "--password"], description: "Defines the password to be used"}) + password : string; + + @Parameter({names: ["-p", "--port"], description: "Defines the optional port if no url is given"}) + portNumber : number; + + authData: AuthData; + workspace: Workspace; + + @Message('internal/test/impl/post-flight-check-test') + i18n : I18n; + + constructor(args:Array) { + let updatedArgs = ArgumentProcessor.inject(this, args); + + let url: string; + // get options from arguments + if (updatedArgs.length > 0) { + url = updatedArgs[0]; + } + this.authData = AuthData.parse(url, this.username, this.password); + if (this.portNumber) { + this.authData.port = this.portNumber; + } + this.workspace = new Workspace(this.authData); + } + + run() : Promise { + // first, login + return this.authData.login().then(() => { + // then create the workspace + let createWorkspaceConfig: CreateWorkspaceConfig = new CreateWorkspaceConfig(); + createWorkspaceConfig.name = 'your-first-workspace'; + Log.getLogger().info(this.i18n.get('run.generating',createWorkspaceConfig.name)); + + return this.workspace.createWorkspace(createWorkspaceConfig) + .then(workspaceDto => { + // then start it + Log.getLogger().info(this.i18n.get('run.starting-workspace')); + return this.workspace.startWorkspace(workspaceDto.getId(), !this.isQuiet); + }).then((workspaceDto) => { + // then stop it + Log.getLogger().info(this.i18n.get('run.stopping-workspace')); + return this.workspace.stopWorkspace(workspaceDto.getId()); + }).then((workspaceDto) => { + // then delete it + Log.getLogger().info(this.i18n.get('run.deleting-workspace')); + return this.workspace.deleteWorkspace(workspaceDto.getId()); + }); + + }); + } + +} diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-array-info.ts b/dockerfiles/lib-typescript/src/spi/ascii/ascii-array-info.ts new file mode 100644 index 00000000000..da0b50eeb49 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/ascii-array-info.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +/** + * Provides data about ascii array. + * @author Florent Benoit + */ +export interface AsciiArrayInfo { + + /** + * Provides size of each column. + */ + getColumnsSize() : Array; +} diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-array.ts b/dockerfiles/lib-typescript/src/spi/ascii/ascii-array.ts new file mode 100644 index 00000000000..95febf05a50 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/ascii-array.ts @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {FormatterMode} from "./formatter-mode"; + +/** + * AsciiArray allow to build output arrays and format them in a simple way. + * No need for each command to build its own logic. + * There are CSV, Modern formatters, etc. + * @author Florent Benoit + */ +export interface AsciiArray { + + /** + * Specify the titles for this array + * + * @param columnsTitle + * the given titles + * @return the current array + */ + withTitles(...columnsTitle:Array) : AsciiArray; + + /** + * Specify the columns (containing data) for this array + * + * @param columns + * the given data column + * @return the current array + */ + withColumns(...columns:Array>) : AsciiArray; + + /** + * Specify the rows (containing data) for this array + * + * @param rows + * the given data column + * @return the current array + */ + withListRows(...rows:Array>) : AsciiArray; + + /** + * Specify the rows (containing data) for this array + * + * @param rows + * the given data column + * @return the current array + */ + withRows(rows:Array>) : AsciiArray; + + /** + * Transform the given data into an ascii array + * + * @return stringified table of the array + */ + toAscii() : string; + + /** + * Apply a formatter to this array + * @param formatterMode the name of the formatter + */ + withFormatter(formatterMode:FormatterMode) : AsciiArray; + + /** + * Show or not the title when getting result + * @param showTitles if true, display it + * @returns {DefaultAsciiArray} + */ + withShowTitles(showTitles:boolean) : AsciiArray; + + + /** + * Specify the order and columns that need to be displayed. + * @param columnTitles an array of name of columns + */ + withFormatColumnTitles(...columnTitles:Array) : AsciiArray; + + + /** + * Specify the order and columns that need to be displayed. + * @param columnNames a comma separated list of columns + */ + withFormatColumns(columnNames:string) : AsciiArray; + +} diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-entry.ts b/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-entry.ts new file mode 100644 index 00000000000..7e4836458b3 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-entry.ts @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +/** + * AsciiFormEntry is an entry to {@link AsciiForm} + * @author Florent Benoit + */ +export class AsciiFormEntry { + + /** + * Name of the entry (left display) + */ + private name:string; + + /** + * Value of the entry (right display) + */ + private value:string; + + /** + * Allow to build a new entry by specifying the name and value + * @param name the key + * @param value the value + */ + public constructor(name:string, value:string) { + this.name = name; + this.value = value; + } + + /** + * Provides the value + * @returns {string} + */ + public getValue():string { + return this.value; + } + + + /** + * Provides the name + * @returns {string} + */ + public getName():string { + + return this.name; + } + + + /** + * Allow to compare one ascii form entry to another one + */ + public compareTo(o:AsciiFormEntry):number { + return this.name.localeCompare(o.getName()); + } + +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-info.ts b/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-info.ts new file mode 100644 index 00000000000..c8a3fca3fff --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-info.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +/** + * Provides data about ascii forms. + * @author Florent Benoit + */ +export interface AsciiFormInfo { + + /** + * Size of the column for the title (key) + */ + getTitleColumnSize() : number; + + /** + * Provides size of the column for the values + */ + getValueColumnSize() : number; + + /** + * If true, name of the properties need to be uppercase. + */ + isUppercasePropertyName() : boolean; + +} diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-form.ts b/dockerfiles/lib-typescript/src/spi/ascii/ascii-form.ts new file mode 100644 index 00000000000..a14a15326a8 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/ascii-form.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {FormatterMode} from "./formatter-mode"; + +/** + * AsciiForm allow to build forms (key, value) with all values being left aligned in a simple way. + * No need for each command to build its own logic. + * There are CSV, Modern formatters, etc. + * @author Florent Benoit + */ + +export interface AsciiForm { + + /** + * Adds a new entry in the form + * @param propertyName the name of the property + * @param propertyValue the value of the property + * @return {@link AsciiForm} + */ + withEntry(propertyName:string, propertyValue:string) : AsciiForm; + + /** + * Order all properties by using alphabetical order. + * @return {@link AsciiForm} + */ + alphabeticalSort() : AsciiForm; + + /** + * Use uppercase for the property name + * @return {@link AsciiForm} + */ + withUppercasePropertyName() : AsciiForm; + + /** + * Allow to pickup formatter + * @param formatterMode + */ + withFormatter(formatterMode:FormatterMode) : AsciiForm; + + /** + * Transform the given form into an ascii form + * + * @return stringified table of the form + */ + toAscii() : string; + +} diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-format.ts b/dockerfiles/lib-typescript/src/spi/ascii/ascii-format.ts new file mode 100644 index 00000000000..fd69a4b74d9 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/ascii-format.ts @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +/** + * Provides helper method to format content + * @author Florent Benoit + */ +export class AsciiFormat { + + + /** + * Allow to format values provided as array of string with the formatter + * @param formatter it can include %s, %S (uppercase), %d number, %n carriage return, -%s or -%S for left aligned values + * @param values the values to include in formatted string + * @returns {string} the formatted string + */ + public static format(formatter:string, values:Array):string { + let stringToEval:string = formatter; + let index:number = 0; + return stringToEval.replace(/%((%)|s|S|d|n|-[0-9]*(s|S))/g, (match) => { + var val = null; + + if (index > values.length) { + return "N/A : invalid formatting"; + } + + switch (match[1]) { + case '-': + // number of spaces are all digits after - and before last character + let numberChar:number = 2; + let spaceValue:string = ""; + while (numberChar < match.length - 1) { + spaceValue += match[numberChar]; + numberChar++; + } + + let numberOfSpaces = parseInt(spaceValue); + + val = values[index]; + while (val.length < numberOfSpaces) { + val = val + " "; + } + // uppercase + if (match[match.length - 1] && 'S' === match[match.length - 1]) { + val = val.toUpperCase(); + } + index++; + break; + case 'd': + val = parseFloat(values[index]); + if (isNaN(val)) { + val = 0; + } + index++; + break; + case 'S': + val = values[index].toUpperCase(); + index++; + break; + case 'n': + val = "\n"; + break; + case 's': + val = values[index]; + index++; + break; + } + + return val; + }); + } + +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-formatter.ts b/dockerfiles/lib-typescript/src/spi/ascii/ascii-formatter.ts new file mode 100644 index 00000000000..481d5dd8571 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/ascii-formatter.ts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {AsciiFormInfo} from "./ascii-form-info"; +import {AsciiArrayInfo} from "./ascii-array-info"; + +/** + * Allow to format Ascii Arrays of Ascii Forms + * @author Florent Benoit + */ +export interface AsciiFormatter { + + /** + * If array has a borderline, allow to format it. + * @param asciiArrayInfo the data on the array + */ + getBorderLine(asciiArrayInfo:AsciiArrayInfo) : string; + + /** + * Gets formatter for the given array info + * @param asciiArrayInfo the data on the array + */ + getFormatter(asciiArrayInfo:AsciiArrayInfo) : string; + + /** + * Gets formatter but for the title (which can be different) + * @param asciiArrayInfo the data on the array + */ + getTitleFormatter(asciiArrayInfo:AsciiArrayInfo) : string; + + /** + * Format the title of a ascii form + * @param name the name to format + * @param asciiFormInfo data about the form + */ + formatFormTitle(name:string, asciiFormInfo:AsciiFormInfo) : string; + + /** + * Format the value of a ascii form + * @param value the name to format + * @param asciiFormInfo data about the form + */ + formatFormValue(value:string, asciiFormInfo:AsciiFormInfo) : string; + +} + + diff --git a/dockerfiles/lib-typescript/src/spi/ascii/csv-formatter.ts b/dockerfiles/lib-typescript/src/spi/ascii/csv-formatter.ts new file mode 100644 index 00000000000..306e94727a4 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/csv-formatter.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {AsciiFormatter} from "./ascii-formatter"; +import {AsciiArrayInfo} from "./ascii-array-info"; +import {AsciiFormInfo} from "./ascii-form-info"; + +/** + * CSV formatter + * @author Florent Benoit + */ +export class CSVFormatter implements AsciiFormatter { + + + /** + * No border for CSV formatter + * @param asciiArrayInfo + * @return empty + */ + getBorderLine(asciiArrayInfo:AsciiArrayInfo):string { + return null; + } + + /** + * Provides comma separated list of values + * @returns {string} + */ + getFormatter(asciiArrayInfo:AsciiArrayInfo):string { + + let value = ""; + let size:number = asciiArrayInfo.getColumnsSize().length; + for (let c:number = 1; c <= size; c++) { + value += "%s"; + if (c < size) { + value += ","; + } + } + value += "%n"; + return value; + } + + /** + * Provides comma separated list of values for title as well (with uppercase) + * @returns {string} + */ + getTitleFormatter(asciiArrayInfo:AsciiArrayInfo):string { + let value = ""; + let size:number = asciiArrayInfo.getColumnsSize().length; + for (let c:number = 1; c <= size; c++) { + // uppercase + value += "%S"; + if (c < size) { + value += ","; + } + } + value += "%n"; + return value; + } + + /** + * Do not format forms + */ + formatFormTitle(name:string, asciiFormInfo:AsciiFormInfo):string { + return null; + } + + /** + * Do not format forms + */ + formatFormValue(value:string, asciiFormInfo:AsciiFormInfo):string { + return null; + } + +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.spec.ts b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.spec.ts new file mode 100644 index 00000000000..f0a383231f7 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.spec.ts @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {DefaultAsciiArray} from "./default-ascii-array"; +import {AsciiArray} from "./ascii-array"; +let expect = require('chai').expect; + +/** + * Provides Unit Tests for AsciiArray + * @author Florent Benoit + */ +describe("AsciiArray tests", () => { + + it("testEmptyArray", () => { + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + let result:string = asciiArray.toAscii(); + expect(result.length).to.equal(0); + expect(result).to.equal(""); + }); + + it("testColumnsSize", () => { + + let column1:Array = ["a", "ab", "abc", "a"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withColumns(column1); + let columnsSize:Array = asciiArray.getColumnsSize(); + + expect(columnsSize).to.exist; + expect(columnsSize.length).to.equal(1); + expect(columnsSize[0]).to.equal(3); + }); + + + it("testColumnsSizeTwoColumns", () => { + + let column1:Array = ["a", "ab", "abcdef", " abcdef "]; + let column2:Array = ["defgh", "d", "e", "f"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withColumns(column1, column2); + let columnsSize:Array = asciiArray.getColumnsSize(); + + expect(columnsSize).to.exist; + expect(columnsSize.length).to.equal(2); + expect(columnsSize[0]).to.equal(8); + expect(columnsSize[1]).to.equal(5); + }); + + + it("testColumnsSizeWihTitle", () => { + + let column1:Array = ["a", "ab", "abcdef", " abcdef "]; + let column2:Array = ["defgh", "d", "e", "f"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withColumns(column1, column2).withTitles("Col1", " My Column 2"); + let columnsSize:Array = asciiArray.getColumnsSize(); + + expect(columnsSize).to.exist; + expect(columnsSize.length).to.equal(2); + expect(columnsSize[0]).to.equal(8); + expect(columnsSize[1]).to.equal(12); + }); + + + it("testTwoColumnsWithTitleCsvFormatter", () => { + + let column1:Array = ["row1", "row2", "row3"]; + let column2:Array = ["1", "2", "3"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withColumns(column1, column2).withTitles("name", "id").withFormatter("CSV"); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("NAME,ID\nrow1,1\nrow2,2\nrow3,3"); + }); + + it("testTwoRowsWithTitleCsvFormatter", () => { + + let row1:Array = ["hello1", "hello2", "hello3"]; + let row2:Array = ["another1", "another2", "another3"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withListRows(row1, row2).withTitles("name1", "name2", "name3").withFormatter("CSV"); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("NAME1,NAME2,NAME3\nhello1,hello2,hello3\nanother1,another2,another3"); + }); + + + it("testTwoColumnsWithTitleModernFormatter", () => { + + let column1:Array = ["row1", "row2", "row3"]; + let column2:Array = ["1", "2", "3"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withColumns(column1, column2).withTitles("name", "id").withFormatter("MODERN"); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("NAME ID \nrow1 1 \nrow2 2 \nrow3 3 "); + }); + + + it("testTwoRowsWithTitleModernFormatter", () => { + + let row1:Array = ["hello1", "hello2", "hello3"]; + let row2:Array = ["another1", "another2", "another3"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withListRows(row1, row2).withTitles("name1", "name2", "name3").withFormatter("MODERN"); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("NAME1 NAME2 NAME3 \nhello1 hello2 hello3 \nanother1 another2 another3 "); + }); + + + it("testTwoRowsWithTitleLongDataColumnModernFormatter", () => { + + let row1:Array = ["local", "workspace1x42j3pjczrnnqdr", "RUNNING"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withListRows(row1).withTitles("name", "id", "status").withFormatter("MODERN"); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("NAME ID STATUS \nlocal workspace1x42j3pjczrnnqdr RUNNING "); + }); + + + it("testSkipTitleCsvFormatter", () => { + + let row1:Array = ["id1", "name1", "status1"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withListRows(row1).withTitles("id", "name", "status very long").withShowTitles(false).withFormatter('CSV'); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("id1,name1,status1"); + }); + + + it("testCustomOrderingCsvFormatter", () => { + + let row1:Array = ["id1", "name1", "status1"]; + let row2:Array = ["id2", "name2", "status2"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withListRows(row1, row2).withTitles("id", "name", "status").withFormatter("CSV").withFormatColumnTitles("status", "id"); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("STATUS,ID\nstatus1,id1\nstatus2,id2"); + }); + + + it("testCustomOrderingCommaSeparatedCsvFormatter", () => { + + let row1:Array = ["id1", "name1", "status1"]; + let row2:Array = ["id2", "name2", "status2"]; + + let asciiArray:DefaultAsciiArray = new DefaultAsciiArray(); + asciiArray.withListRows(row1, row2).withTitles("id", "name", "status").withFormatter("CSV").withFormatColumns("status,NAME"); + + let result:string = asciiArray.toAscii(); + + expect(result).to.equal("STATUS,NAME\nstatus1,name1\nstatus2,name2"); + }); + + +}); diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.ts b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.ts new file mode 100644 index 00000000000..31869f210e0 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.ts @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {AsciiFormatter} from "./ascii-formatter"; +import {FormatterMode} from "./formatter-mode"; +import {CSVFormatter} from "./csv-formatter"; +import {AsciiArray} from "./ascii-array"; +import {AsciiArrayInfo} from "./ascii-array-info"; +import {AsciiFormat} from "./ascii-format"; +import {ModernFormatter} from "./modern-formatter"; + + +/** + * Implementation of {@link AsciiArray} + * @author Florent Benoit + */ +export class DefaultAsciiArray implements AsciiArray { + + /** + * Columns of this array + */ + private columns:Array>; + + /** + * Columns of this array + */ + private rows:Array>; + + /** + * Titles of each column (if any) + */ + private titles:Array; + + /** + * Formatters. + */ + private formatters:Map; + + /** + * Formatter + */ + private formatterMode:FormatterMode; + + + /** + * Show the titles. + */ + private showTitles:boolean = true; + + + /** + * Order and name of column titles + */ + private formatColumnTitles:Array; + + + /** + * Used when rendering. number of columns to render. + */ + private numberOfColumns:number; + + /** + * Used when rendering. + */ + private columnMapping:Array; + + + /** + * Default constructor + */ + public constructor() { + this.columns = new Array>(); + this.rows = new Array>(); + this.titles = new Array(); + this.formatters = new Map(); + this.formatColumnTitles = new Array(); + //this.formatters.se(EIGHTIES, new EightiesFormatter()); + this.formatters.set('MODERN', new ModernFormatter()); + this.formatters.set('CSV', new CSVFormatter()); + this.columnMapping = new Array(); + this.formatterMode = 'MODERN'; + } + + /** + * Specify the titles for this array + * + * @param columnsTitle + * the given titles + * @return the current array + */ + + public withTitles(...columnsTitle:Array):AsciiArray { + this.titles = columnsTitle; + return this; + } + + + /** + * Specify the columns (containing data) for this array + * + * @param columns + * the given data column + * @return the current array + */ + + public withColumns(...columns:Array>):AsciiArray { + if (this.rows.length > 0) { + throw new Error("Array is already built with columns, cannot mix both inputs"); + } + + columns.forEach((column) => { + this.addColumn(column); + }); + return this; + } + + /** + * Specify the rows (containing data) for this array + * + * @param rows + * the given data column + * @return the current array + */ + + public withRows(rows:Array>):AsciiArray { + if (this.columns.length > 0) { + throw new Error("Array is already built with columns, cannot mix both inputs"); + } + rows.forEach((row) => { + this.addRow(row); + }); + return this; + } + + /** + * Specify the rows (containing data) for this array + * + * @param rows + * the given data column + * @return the current array + */ + + public withListRows(...rows:Array>):AsciiArray { + if (this.columns.length > 0) { + throw new Error("Array is already built with columns, cannot mix both inputs"); + } + rows.forEach((row) => { + this.addRow(row); + }); + return this; + } + + /** + * Add the given column + * + * @param column + * the column + */ + protected addColumn(column:Array):void { + this.columns.push(column); + } + + + /** + * Add the given row + * + * @param row + * the row + */ + protected addRow(row:Array):void { + this.rows.push(row); + } + + + /** + * Checks that the array is valid before trying to get its stringified version + */ + protected checkIntegrity():void { + // check that columns have the same row length + if (this.columns.length > 0) { + let size:number = this.columns[0].length; + + this.columns.forEach((column) => { + if (column.length != size) { + throw new Error("The columns have not the same sized. : " + column.length + " vs " + size); + } + }); + + // if there are titles check that we've the same number of columns + if (this.titles) { + if (this.columns.length > 0) { + if (this.titles.length != this.columns.length) { + throw new Error( + "Invalid expected titles. There are " + this.columns.length + " while there are " + this.titles.length + " titles."); + } + } + } + + } + } + + + /** + * Transform the given data into an ascii array + * + * @return stringified table of the array + */ + + public toAscii():string { + + // check + this.checkIntegrity(); + + // handle empty + if (this.columns.length === 0 && this.rows.length === 0) { + return ""; + } + + // compute mapping + this.computeMapping(); + + // first line is the border + let computeBorder:string = this.getBorderLine(); + let beginBorderLine:string; + let endBorderLine:string; + if (computeBorder != null) { + beginBorderLine = computeBorder + "%n"; + endBorderLine = computeBorder; + } else { + beginBorderLine = ""; + endBorderLine = ""; + } + + let buffer:string = beginBorderLine; + let formatter:string = this.getFormatter(); + let titleFormatter:string = this.getTitleFormatter(); + + // now add titles if any + if (this.titles.length > 0 && this.showTitles) { + let value:Array = this.titles; + if (this.formatColumnTitles.length > 0) { + value = this.getMappingRow(value); + } + + + buffer += AsciiFormat.format(titleFormatter, value); + + + buffer += beginBorderLine; + } + + // data ? + if (this.rows.length > 0) { + this.rows.forEach((row) => { + if (this.formatColumnTitles.length > 0) { + row = this.getMappingRow(row); + } + + buffer += AsciiFormat.format(formatter, row); + }); + buffer += endBorderLine; + + } + + + if (this.columns.length > 0) { + let nbRows:number = this.columns[0].length; + + + for (let row:number = 0; row < nbRows; row++) { + let rowElements = this.getRow(row); + if (this.formatColumnTitles.length > 0) { + rowElements = this.getMappingRow(rowElements); + } + buffer += AsciiFormat.format(formatter, rowElements); + } + buffer += endBorderLine; + } + + + if (buffer.length > 0 && buffer.slice(-1) === '\n') { + // remove it + buffer = buffer.slice(0, -1); + } + + return buffer; + + } + + /** + * Extract columns from the existing row + * @param row the row to analyze and extract and sort column + * @returns {Array} + */ + protected getMappingRow(row:Array):Array { + let mapped:Array = new Array(); + for (let i = 0; i < this.numberOfColumns; i++) { + mapped.push(row[this.columnMapping[i]]); + } + return mapped; + } + + /** + * Get content of a selected row for the given array + * + * @param index + * the index in the columns + * @return the content + */ + protected getRow(index:number):Array { + let row:Array = new Array(); + let i:number = 0; + this.columns.forEach((column) => { + row[i++] = column[index]; + }); + return row; + } + + /** + * @return formatter + */ + protected getFormatterMode():AsciiFormatter { + return this.formatters.get(this.formatterMode); + } + + protected getArrayInfo():AsciiArrayInfo { + return new MyAsciiArrayInfo(this); + } + + /** + * @return formatter used to format row content + */ + protected getFormatter():string { + return this.getFormatterMode().getFormatter(this.getArrayInfo()); + } + + /** + * @return formatter used to format title content + */ + protected getTitleFormatter():string { + return this.getFormatterMode().getTitleFormatter(this.getArrayInfo()); + } + + + /** + * @return value used as border of the array + */ + protected getBorderLine():string { + return this.getFormatterMode().getBorderLine(this.getArrayInfo()); + } + + + /** + * Compute a mapping between existing columns and the columns that need to be displayed. + */ + protected computeMapping():void { + if (this.formatColumnTitles.length > 0) { + this.numberOfColumns = this.formatColumnTitles.length; + + // compute column ordering. + for (let column:number = 0; column < this.numberOfColumns; column++) { + // indexOf + + var foundIndex = -1; + this.titles.some((element, i) => { + if (this.formatColumnTitles[column].toLowerCase() === element.toLowerCase()) { + foundIndex = i; + return true; + } + }); + if (foundIndex === -1) { + throw new Error("There is no column with name '" + this.formatColumnTitles[column] + "'. Existing names are " + this.titles); + } + this.columnMapping[column] = foundIndex; + } + + } else { + if (this.rows.length > 0) { + this.numberOfColumns = this.rows[0].length; + } else { + this.numberOfColumns = this.columns.length; + } + for (let column:number = 0; column < this.numberOfColumns; column++) { + // no mapping + this.columnMapping[column] = column; + } + + } + } + + /** + * @return the size of the column (by searching max size of each column, including title) + */ + public getColumnsSize():Array { + let lengths:Array = new Array(); + + // Array with rows input + if (this.rows.length > 0) { + + + // column number is first row length + for (let column:number = 0; column < this.numberOfColumns; column++) { + // for each column, set the max length + let maxLength:number = 0; + + // for title + if (this.titles && this.titles.length > 0 && this.showTitles) { + let currentLength:number = this.titles[this.columnMapping[column]].length; + if (currentLength > maxLength) { + maxLength = currentLength; + } + } + + this.rows.forEach((row) => { + let currentLength = row[this.columnMapping[column]].length; + if (currentLength > maxLength) { + maxLength = currentLength; + } + + }); + + lengths.push(maxLength); + + + } + } + + // Array with columns input + if (this.columns.length > 0) { + for (let column:number = 0; column < this.columns.length; column++) { + // for each column, set the max length + let maxLength:number = 0; + + // for title + if (this.titles && this.titles.length > 0 && this.showTitles) { + let currentLength:number = this.titles[column].length; + if (currentLength > maxLength) { + maxLength = currentLength; + } + } + + // for content + let columnData:Array = this.columns[column]; + columnData.forEach((row) => { + let currentLength:number = row.length; + if (currentLength > maxLength) { + maxLength = currentLength; + } + }); + lengths.push(maxLength); + } + } + + return lengths; + + } + + public withFormatter(formatterMode:FormatterMode):AsciiArray { + if (!formatterMode) { + return this; + } + + if (formatterMode !== 'CSV' && formatterMode !== 'MODERN') { + throw new Error("The formatter mode " + formatterMode + " is not supported. Current support is CSV or MODERN.") + } + + this.formatterMode = formatterMode; + return this; + } + + /** + * Show or not the title when getting result + * @param showTitles if true, display it + * @returns {DefaultAsciiArray} + */ + withShowTitles(showTitles:boolean):AsciiArray { + if (!showTitles) { + this.showTitles = false; + } + return this; + } + + /** + * Specify the order and columns that need to be displayed. + * @param columnTitles an array of name of columns + */ + withFormatColumnTitles(...columnTitles:Array):AsciiArray { + this.formatColumnTitles = columnTitles; + return this; + } + + + /** + * Specify the order and columns that need to be displayed. + * @param columnNames a comma separated list of columns + */ + withFormatColumns(columnNames:string):AsciiArray { + if (columnNames) { + this.formatColumnTitles = columnNames.split(","); + } + return this; + } + + +} + +/** + * Inner class with column size data. + */ +export class MyAsciiArrayInfo implements AsciiArrayInfo { + private array:DefaultAsciiArray; + + constructor(array:DefaultAsciiArray) { + this.array = array; + } + + public getColumnsSize():Array { + return this.array.getColumnsSize(); + } +} diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.spec.ts b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.spec.ts new file mode 100644 index 00000000000..ea374a317fd --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.spec.ts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {DefaultAsciiForm} from "./default-ascii-form"; +import {AsciiForm} from "./ascii-form"; +let expect = require('chai').expect; + +/** + * Provides Unit Tests for AsciiForm + * @author Florent Benoit + */ + +describe("AsciiForm tests", () => { + + it("testEmptyForm", () => { + + let asciiForm:DefaultAsciiForm = new DefaultAsciiForm(); + let result:string = asciiForm.toAscii(); + expect(result.length).to.equal(0); + expect(result).to.equal(""); + }); + + + it("testOneLineForm", () => { + + let asciiForm:AsciiForm = new DefaultAsciiForm().withEntry("id", "value1"); + let result:string = asciiForm.toAscii(); + expect(result.length).to.above(0); + expect(result).to.equal("id value1"); + }); + + + + it("testThreeLinesFormUppercase", () => { + + let asciiForm:AsciiForm = new DefaultAsciiForm().withEntry("id", "value1").withEntry("a very long Id", "123456789").withEntry("short id", "abc").withUppercasePropertyName(); + let result:string = asciiForm.toAscii(); + expect(result.length).to.above(0); + expect(result).to.equal("ID value1\n" + "A VERY LONG ID 123456789\n" + + "SHORT ID abc"); + }); + + +}); diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.ts b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.ts new file mode 100644 index 00000000000..4abab8e2100 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.ts @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {AsciiForm} from "./ascii-form"; +import {FormatterMode} from "./formatter-mode"; +import {AsciiFormatter} from "./ascii-formatter"; +import {CSVFormatter} from "./csv-formatter"; +import {AsciiFormInfo} from "./ascii-form-info"; +import {AsciiFormEntry} from "./ascii-form-entry"; +import {ModernFormatter} from "./modern-formatter"; + +/** + * Default implementation of {@link AsciiForm} + * @author Florent Benoit + */ +export class DefaultAsciiForm implements AsciiForm { + + private entries:Array; + + private alphabeticalSortValue:boolean = false; + + private uppercasePropertyName:boolean = false; + + /** + * Formatters. + */ + private formatters:Map; + + /** + * Formatter + */ + private formatterMode:FormatterMode; + + /** + * Default constructor + */ + public constructor() { + this.entries = new Array(); + this.formatters = new Map(); + this.formatters.set('MODERN', new ModernFormatter()); + this.formatters.set('CSV', new CSVFormatter()); + + this.formatterMode = 'MODERN'; + } + + + /** + * Adds a new entry in the form + * + * @param propertyName + * the name of the property + * @param propertyValue + * the value of the property + * @return {@link com.codenvy.cli.command.builtin.util.ascii.AsciiForm} + */ + + public withEntry(propertyName:string, propertyValue:string):AsciiForm { + this.entries.push(new AsciiFormEntry(propertyName, propertyValue)); + return this; + } + + /** + * Order all properties by using alphabetical order. + * + * @return {@link com.codenvy.cli.command.builtin.util.ascii.AsciiForm} + */ + public alphabeticalSort():AsciiForm { + this.alphabeticalSortValue = true; + return this; + } + + /** + * Use uppercase for the property name + * + * @return {@link com.codenvy.cli.command.builtin.util.ascii.AsciiForm} + */ + + public withUppercasePropertyName():AsciiForm { + this.uppercasePropertyName = true; + return this; + } + + + public withFormatter(formatterMode:FormatterMode):AsciiForm { + this.formatterMode = formatterMode; + return this; + } + + /** + * Transform the given form into an ascii form + * + * @return stringified table of the form + */ + + public toAscii():string { + // compute each line + + // sort entries if alphabetical sort + if (this.alphabeticalSort) { + //Collections.sort(entries); + } + + let output:string = ""; + + this.entries.forEach((entry) => { + // first get title + let title:string = this.getFormatterMode().formatFormTitle(entry.getName(), new MyAsciiFormInfo(this)); + let value:string = this.getFormatterMode().formatFormValue(entry.getValue(), new MyAsciiFormInfo(this)); + output += title + value + "\n"; + }); + + if (output.length > 0 && output.slice(-1) === '\n') { + // remove it + output = output.slice(0, -1); + } + + return output; + + } + + /** + * @return formatter + */ + protected getFormatterMode():AsciiFormatter { + return this.formatters.get(this.formatterMode); + } + + + public getTitleColumnSize():number { + let length:number = 0; + this.entries.forEach((entry) => { + // length is without ansi + length = Math.max(length, entry.getName().length); + }); + return length; + } + + public getValueColumnSize():number { + let length:number = 0; + this.entries.forEach((entry) => { + // length is without ansi + length = Math.max(length, entry.getValue().length); + }); + + return length; + } + + public isUppercasePropertyName():boolean { + return this.uppercasePropertyName; + } + +} +export class MyAsciiFormInfo implements AsciiFormInfo { + private form:DefaultAsciiForm; + + public constructor(form:DefaultAsciiForm) { + this.form = form; + } + + + public getTitleColumnSize():number { + return this.form.getTitleColumnSize(); + } + + public getValueColumnSize():number { + return this.form.getValueColumnSize(); + } + + public isUppercasePropertyName():boolean { + return this.form.isUppercasePropertyName(); + } +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/ascii/formatter-mode.ts b/dockerfiles/lib-typescript/src/spi/ascii/formatter-mode.ts new file mode 100644 index 00000000000..0ded6259df1 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/formatter-mode.ts @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +/** + * Possible modes of formatters + * @author Florent Benoit + */ +export type FormatterMode = 'MODERN' | 'CSV' diff --git a/dockerfiles/lib-typescript/src/spi/ascii/modern-formatter.ts b/dockerfiles/lib-typescript/src/spi/ascii/modern-formatter.ts new file mode 100644 index 00000000000..885ccf6ccfa --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/ascii/modern-formatter.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {AsciiFormatter} from "./ascii-formatter"; +import {AsciiArrayInfo} from "./ascii-array-info"; +import {AsciiFormInfo} from "./ascii-form-info"; +import {AsciiFormat} from "./ascii-format"; + +/** + * Modern formatter with spaces (2 spaces) between columns and left-aligned values. + */ +export class ModernFormatter implements AsciiFormatter { + + + /** + * No border for modern formatter + * @param asciiArrayInfo + * @return empty + */ + + public getBorderLine(asciiArrayInfo:AsciiArrayInfo):string { + return null; + } + + + public getFormatter(asciiArrayInfo:AsciiArrayInfo):string { + let buffer:string = ""; + + asciiArrayInfo.getColumnsSize().forEach((columnSize) => { + buffer += "%-" + columnSize + "s"; + buffer += " "; + }); + buffer += "%n"; + + return buffer; + + } + + public getTitleFormatter(asciiArrayInfo:AsciiArrayInfo):string { + let buffer:string = ""; + + asciiArrayInfo.getColumnsSize().forEach((columnSize) => { + // uppercase + buffer += "%-" + columnSize + "S"; + buffer += " "; + }); + buffer += "%n"; + + return buffer; + + } + + + public formatFormTitle(name:string, asciiFormInfo:AsciiFormInfo):string { + let entryName:string = name; + + // format it + let flag:string = "s"; + if (asciiFormInfo.isUppercasePropertyName()) { + flag = "S"; + } + return AsciiFormat.format("%-" + (asciiFormInfo.getTitleColumnSize()) + flag, [name]); + } + + + public formatFormValue(value:string, asciiFormInfo:AsciiFormInfo):string { + if (!value) { + return " "; + } + + // just adding text after adding a space + return " " + value; + } + +} diff --git a/dockerfiles/lib-typescript/src/spi/decorator/argument-processor.ts b/dockerfiles/lib-typescript/src/spi/decorator/argument-processor.ts new file mode 100644 index 00000000000..42e9a994791 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/decorator/argument-processor.ts @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {ArgumentTypeDesc} from "./parameter"; +import {ParameterTypeDesc} from "./parameter"; +import {Log} from "../log/log"; +import {DefaultAsciiForm} from "../ascii/default-ascii-form"; +import {AsciiForm} from "../ascii/ascii-form"; + +/** + * Manage the injection of annotations @Parameter or @Argument + * @author Florent Benoit + */ +export class ArgumentProcessor { + + + static displayHelp(metadataArguments:Array , metadataParameters:Array) : void { + // display help menu + let asciiFormParameters : AsciiForm = new DefaultAsciiForm(); + if (metadataParameters && metadataParameters.length > 0) { + asciiFormParameters.withEntry(" Parameters:", ""); + metadataParameters.forEach((metadataParameter) => { + let val = ""; + if (metadataParameter.type !== 'Boolean') { + val = "=" + } + asciiFormParameters.withEntry(" [" + metadataParameter.names + "]" + val, metadataParameter.description); + }); + } + + if (metadataArguments && metadataArguments.length > 0) { + + asciiFormParameters.withEntry(" Arguments:", ""); + metadataArguments.forEach((metadataArgument) => { + asciiFormParameters.withEntry(" <" + metadataArgument.fieldName + ">", metadataArgument.description); + }); + } + Log.getLogger().log("multiline:info", asciiFormParameters.toAscii()); + } + + static help(object : any) : void { + var metadataArguments:Array = object.__arguments; + var metadataParameters:Array = object.__parameters; + ArgumentProcessor.displayHelp(metadataArguments, metadataParameters); + } + + + static inject(object : any, args: Array) : Array { + var metadataArguments:Array = object.__arguments; + var metadataParameters:Array = object.__parameters; + + var updatedArgs:Array = args; + if (!updatedArgs) { + updatedArgs = new Array(); + } + + // handle special help feature + if (updatedArgs.length == 1 && ('--help' === updatedArgs[0] || 'help' === updatedArgs[0])) { + ArgumentProcessor.displayHelp(metadataArguments, metadataParameters); + process.exit(0); + } + + + var optionsEnabled : Array = new Array(); + + // loop on each argument + if (metadataParameters) { + var i : number = 0; + while (i < updatedArgs.length) { + + var currentArg : string = updatedArgs[i]; + Log.getLogger().debug('checking currentArg', currentArg); + + + metadataParameters.forEach((metadataParameter) => { + metadataParameter.names.forEach((name) => { + + Log.getLogger().debug('checking metadataParameter', name + '=', 'against', currentArg); + + // toggle like '--p=value' + if (ArgumentProcessor.startsWith(currentArg, name + '=')) { + Log.getLogger().debug('it is equals to name='); + // need to split key from value as it's --key=value + let splitter:string[] = currentArg.split("="); + let value = splitter[1]; + object[metadataParameter.fieldName] = value; + optionsEnabled.push(name + '(' + metadataParameter.description + ') =>' + value); + Log.getLogger().debug('= removedOptionsArgs before', updatedArgs, 'with index=', i); + updatedArgs.splice(i, 1); + i--; + Log.getLogger().debug('= match removedOptionsArgs after', updatedArgs, 'with index=', i); + Log.getLogger().debug('= match is object[metadataParameter.fieldName] ', object[metadataParameter.fieldName] ); + } else if (name === currentArg && ArgumentProcessor.startsWith(currentArg, '-')) { + // like -a + if (metadataParameter.type === 'Boolean') { + object[metadataParameter.fieldName] = true; + updatedArgs.splice(i, 1); + i--; + } else { + object[metadataParameter.fieldName] = updatedArgs[i +1]; + updatedArgs.splice(i, 2); + i = i-2; + } + optionsEnabled.push(name + '(' + metadataParameter.description + ') =>' + object[metadataParameter.fieldName]); + + } else if (currentArg === name) { + // flag is matching exact argument without value + Log.getLogger().debug('exact match is', name, 'for currentArg', currentArg); + if (metadataParameter.type === 'Boolean') { + object[metadataParameter.fieldName] = true; + } + Log.getLogger().debug('exact match is object[metadataParameter.fieldName] ', metadataParameter.fieldName); + optionsEnabled.push(name + '(' + metadataParameter.description + ') =>' + object[metadataParameter.fieldName]); + Log.getLogger().debug('exact match removedOptionsArgs before', updatedArgs, 'with index=', i); + updatedArgs.splice(i, 1); + i--; + Log.getLogger().debug('exact match removedOptionsArgs and after we have', updatedArgs); + } + + }); + + }); + i++; + } + + } + + // display sum up of what has been processed + if (optionsEnabled.length > 0) { + optionsEnabled.forEach((option) => { + Log.getLogger().debug(option); + }); + } + + Log.getLogger().debug('start metadata arguments with args', updatedArgs); + + // we have arguments, needs to fill them + if (metadataArguments) { + metadataArguments.forEach((argument) => { + // we're requiring an argument but it's not there + if (updatedArgs.length == 0) { + Log.getLogger().error('Expecting mandatory argument : ' + argument.description); + ArgumentProcessor.displayHelp(metadataArguments, metadataParameters); + if (object.help) { + object.help(); + } + process.exit(1); + } + + object[argument.fieldName] = updatedArgs[0]; + // shift args + updatedArgs = updatedArgs.slice(1); + }) + } + + Log.getLogger().debug('end metadata arguments with args', updatedArgs); + + return updatedArgs; + } + + + static startsWith(value:string, searchString: string) : boolean { + if (!value) { + return false; + } + if (!searchString) { + return false; + } + return value.substr(0, searchString.length) === searchString; + } + + static contains(a : Array, obj : any) : boolean{ + for (var i = 0; i < a.length; i++) { + if (a[i] === obj) { + return true; + } + } + return false; +} + +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/decorator/message.ts b/dockerfiles/lib-typescript/src/spi/decorator/message.ts new file mode 100644 index 00000000000..9ed6a14cd35 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/decorator/message.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import 'reflect-metadata'; +import {I18n} from "../i18n/i18n"; +import {Log} from "../log/log"; + + + +/** + * Handle annotation/decorator for the Message + * @param propertyKey + * @returns {function(any, string, PropertyDescriptor): undefined} + */ +export function Message(key: string) : any { + return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { + + var t = Reflect.getMetadata("design:type", target, propertyKey); + + let path: any = require('path'); + + // get file + let rootFolder : string = path.resolve(path.resolve(__dirname, '..' + path.sep), '..' + path.sep); + let filename : string = path.resolve(rootFolder, key + '.properties'); + + let i18n:I18n = new I18n(); + try { + // load file content of message properties file, or display warn if file is not found + var propertiesContent = require('fs').readFileSync(filename).toString(); + + require('fs').readFileSync(filename).toString().split('\n').forEach((line) => { + let split:Array = line.split('='); + i18n.add(split[0], split[1]); + }); + } catch (error) { + Log.getLogger().warn('Unable to locate file', filename); + } + + target.i18n = i18n; + + }; + + +} + +function walk(dir, results) { + var list = require('fs').readdirSync(dir) + list.forEach((file) => { + file = dir + '/' + file + var stat = require('fs').statSync(file) + if (stat && stat.isDirectory()) results = results.concat(walk(file, results)) + else results.push(file) + }) +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/decorator/parameter.ts b/dockerfiles/lib-typescript/src/spi/decorator/parameter.ts new file mode 100644 index 00000000000..8ad525056f9 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/decorator/parameter.ts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import 'reflect-metadata'; + +export interface ParameterType { + + names: Array; + + description? : string; +} + +export interface ParameterTypeDesc extends ParameterType { + fieldName: string; + type : string; +} + + +export interface ArgumentType { + + description? : string; +} + +export interface ArgumentTypeDesc extends ArgumentType { + fieldName: string; + type : boolean; +} + +/** + * Handle annotation/decorator for the given parameter + * @param propertyKey + * @returns {function(any, string, PropertyDescriptor): undefined} + * @constructor + */ +export function Parameter(parameterType: ParameterType) : any { + return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { + + var t = Reflect.getMetadata("design:type", target, propertyKey); + let option : ParameterTypeDesc = {names: parameterType.names, description: parameterType.description, fieldName : propertyKey, type : t.name}; + + if (target.__parameters) { + target.__parameters.push(option); + } else { + let options : Array = [option]; + target.__parameters = options; + } + + }; + +} + + + +/** + * Handle annotation/decorator for the given parameter + * @param propertyKey + * @returns {function(any, string, PropertyDescriptor): undefined} + * @constructor + */ +export function Argument(argumentType: ArgumentType) : any { + return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { + + var t = Reflect.getMetadata("design:type", target, propertyKey); + let option : ArgumentTypeDesc = {description: argumentType.description, fieldName : propertyKey, type : t.name}; + if (target.__arguments) { + target.__arguments.push(option); + } else { + let options : Array = [option]; + target.__arguments = options; + } + + + }; + + +} diff --git a/dockerfiles/lib-typescript/src/spi/docker/container-version.ts b/dockerfiles/lib-typescript/src/spi/docker/container-version.ts new file mode 100644 index 00000000000..7ead83ca12d --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/docker/container-version.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +/** + * Run in the container the command to get image being launched so we can detect the version of the image + * @author Florent Benoit + */ +export class ContainerVersion { + + static version: string; + + constructor() { + if (!ContainerVersion.version) { + let execSync = require('child_process').execSync; + ContainerVersion.version = execSync("docker inspect --format='{{.Config.Image}}' `hostname` | cut -d : -f2 -s").toString().replace(/[\n\r]/g, ''); + } + } + + + getVersion() : string { + return ContainerVersion.version; + } + +} diff --git a/dockerfiles/lib-typescript/src/spi/docker/recipebuilder.ts b/dockerfiles/lib-typescript/src/spi/docker/recipebuilder.ts new file mode 100644 index 00000000000..04ce0239221 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/docker/recipebuilder.ts @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {Log} from "../log/log"; +import {CheFileStructWorkspace} from "../../internal/dir/chefile-struct/che-file-struct"; +/** + * Build a default recipe. + * @author Florent Benoit + */ +export class RecipeBuilder { + + static DEFAULT_DOCKERFILE_CONTENT: string = 'FROM codenvy/ubuntu_jdk8'; + path: any; + fs: any; + currentFolder : any; + + constructor(currentFolder) { + this.path = require('path'); + this.fs = require('fs'); + this.currentFolder = currentFolder; + } + + + getRecipe(cheStructWorkspace : CheFileStructWorkspace) : any { + + // do we have a custom property in Chefile + if (cheStructWorkspace) { + if (cheStructWorkspace.runtime) { + if (cheStructWorkspace.runtime.docker) { + if (cheStructWorkspace.runtime.docker.image) { + return {"contentType": "text/x-dockerfile", "type": "dockerimage", "location": cheStructWorkspace.runtime.docker.image}; + } else if (cheStructWorkspace.runtime.docker.content) { + return { + "contentType": "text/x-dockerfile", + "type": "dockerfile", + "content": cheStructWorkspace.runtime.docker.content + }; + } else if (cheStructWorkspace.runtime.docker.location) { + return { + "contentType": "text/x-dockerfile", + "type": "recipe", + "location": cheStructWorkspace.runtime.docker.location + }; + } + } + } + } + + // build path to the Dockerfile in current directory + var dockerFilePath = this.path.resolve(this.currentFolder, 'Dockerfile'); + + // use synchronous API + try { + var stats = this.fs.statSync(dockerFilePath); + Log.getLogger().info('Using a custom project Dockerfile \'' + dockerFilePath + '\' for the setup of the workspace.'); + var content = this.fs.readFileSync(dockerFilePath, 'utf8'); + return {"contentType": "text/x-dockerfile", "type": "dockerfile", "content": content}; + } catch (e) { + // file does not exist, return default + return {"contentType": "text/x-dockerfile", "type": "dockerfile", "content": RecipeBuilder.DEFAULT_DOCKERFILE_CONTENT} ; + } + + } + + + +} diff --git a/dockerfiles/lib-typescript/src/spi/docker/remoteip.ts b/dockerfiles/lib-typescript/src/spi/docker/remoteip.ts new file mode 100644 index 00000000000..73378676475 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/docker/remoteip.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {ContainerVersion} from "./container-version"; + +/** + * Defines a way to grab remote ip + * @author Florent Benoit + */ +export class RemoteIp { + + static ip: string; + + constructor() { + if (!RemoteIp.ip) { + var execSync = require('child_process').execSync; + let containerVersion : string = new ContainerVersion().getVersion(); + RemoteIp.ip = execSync('docker run --net host --rm eclipse/che-ip:' + containerVersion).toString().replace(/[\n\r]/g, ''); + } + } + + + getIp() : string { + return RemoteIp.ip; + } + +} diff --git a/dockerfiles/lib-typescript/src/spi/docker/ssh-generator.ts b/dockerfiles/lib-typescript/src/spi/docker/ssh-generator.ts new file mode 100644 index 00000000000..984905adbd1 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/docker/ssh-generator.ts @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {ContainerVersion} from "./container-version"; + + +/** + * Defines a way to get ssh key (private key and public key) + * @author Florent Benoit + */ +export class SSHGenerator { + + + generateKey() : any { + let map : Map = new Map(); + var execSync = require('child_process').execSync; + let output:string = execSync('docker run --rm --entrypoint /bin/sh codenvy/alpine_jdk8 -c "sudo /usr/bin/ssh-keygen -t rsa -A && echo PRIVATE_KEY_START && sudo cat /etc/ssh/ssh_host_rsa_key && echo PRIVATE_KEY_END && echo PUBLIC_KEY_START && sudo cat /etc/ssh/ssh_host_rsa_key.pub &&echo PUBLIC_KEY_END"').toString(); + + // now grab private key + let isPrivateKey : boolean = false; + let isPublicKey : boolean = false; + let publicKey: string = ''; + let privateKey : string = ''; + let lines : Array = output.split("\n"); + let i : number = 0; + + // TODO : use regexp there + while (i < lines.length) { + let line = lines[i]; + if (line === 'PRIVATE_KEY_START') { + isPrivateKey = true; + i++; + continue; + } else if (line === 'PRIVATE_KEY_END') { + isPrivateKey = false; + i++; + continue; + } else if (line === 'PUBLIC_KEY_START') { + isPrivateKey = false; + isPublicKey = true; + i++; + continue; + } else if (line === 'PUBLIC_KEY_END') { + isPublicKey = false; + i++; + continue; + } + // line could have been moved + line = lines[i]; + + + if (isPrivateKey) { + if (privateKey.length > 0) { + privateKey = privateKey + '\n' + line; + } else { + privateKey = line; + } + } + + if (isPublicKey) { + if (publicKey.length > 0) { + publicKey = publicKey + '\n' + line; + } else { + publicKey = line; + } + } + i++; + } + + map.set('private', privateKey); + map.set('public', publicKey); + + return map; + } + +} + diff --git a/dockerfiles/lib-typescript/src/spi/http/default-http-json-request.ts b/dockerfiles/lib-typescript/src/spi/http/default-http-json-request.ts new file mode 100644 index 00000000000..9b05eaf2b41 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/http/default-http-json-request.ts @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {AuthData} from "../../api/wsmaster/auth/auth-data"; +import {Log} from "../log/log"; +import {org} from "../../api/dto/che-dto"; +/** + * Implementation of a Request on the remote server + * @author Florent Benoit + */ +export class DefaultHttpJsonRequest implements HttpJsonRequest { + + authData : AuthData; + body : any = {}; + http: any; + options: any; + expectedStatusCode : number; + + + constructor(authData : AuthData, url : string, expectedStatusCode: number) { + this.authData = authData; + if (authData.isSecured()) { + this.http = require('https'); + } else { + this.http = require('http'); + } + this.expectedStatusCode = expectedStatusCode; + + this.options = { + hostname: this.authData.getHostname(), + port: this.authData.getPort(), + path: url, + method: 'GET', + headers: { + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': 'application/json;charset=UTF-8', + 'Cookie': 'session-access-key=' + this.authData.getToken() + } + }; + + } + + + setMethod(methodName: string) : DefaultHttpJsonRequest { + this.options.method = methodName; + return this; + } + + + setBody(value : any) : DefaultHttpJsonRequest { + if (value.toJson) { + this.body = value.toJson(); + } else { + this.body = value; + } + return this; + } + + + request() : Promise { + + return new Promise( (resolve, reject) => { + var req = this.http.request(this.options, (res) => { + + var data: string = ''; + + res.on('error', (body)=> { + Log.getLogger().error('got the following error', body.toString()); + reject(body); + }); + + res.on('data', (body) => { + data += body; + }); + + res.on('end', () => { + Log.getLogger().debug('Reply for call', this.options.path, 'with method', this.options.method, 'statusCode:', res.statusCode, 'and got body:', data); + + if (res.statusCode == this.expectedStatusCode) { + // workspace created, continue + resolve(new DefaultHttpJsonResponse(res.statusCode, data)); + } else { + try { + var parsed = JSON.parse(data); + if (parsed.message) { + reject('Call on rest url ' + this.options.path + ' returned invalid response code (' + res.statusCode + ') with error:' + parsed.message); + } else { + reject('Call on rest url ' + this.options.path + ' returned invalid response code (' + res.statusCode + ') with error:' + data); + } + } catch (error) { + reject('Call on rest url ' + this.options.path + ' returned invalid response code (' + res.statusCode + ') with error:' + data.toString()); + } + + } + }); + + }); + + req.on('error', (err) => { + Log.getLogger().debug('http error using the following options', this.options, JSON.stringify(err)); + if (err.code && (err.code === 'ECONNREFUSED' || err.code === 'EHOSTUNREACH')) { + reject('Unable to connect to the remote host ' + this.options.hostname + ' on port ' + this.options.port + + '. Please check the server is listening and that there is no network issue to reach this host. Full error: ' + err); + } else { + reject('HTTP error: ' + err); + } + }); + + let stringified : string = JSON.stringify(this.body); + Log.getLogger().debug('Send request', this.options.path, 'with method', this.options.method, "using ip/port", this.authData.hostname + ":" + this.authData.port, ' body:', stringified); + req.write(stringified); + req.end(); + + }); + } + + +} + + +export class DefaultHttpJsonResponse implements HttpJsonResponse { + + responseCode : number; + data : any; + + constructor (responseCode : number, data : any) { + this.responseCode = responseCode; + this.data = data; + } + + getData() : any { + return this.data; + } + + + asDto(dtoImplementation : any) : any { + //let interfaceName: string = dtoClass.name; + return new dtoImplementation(JSON.parse(this.data)); + } + + asArrayDto(dtoImplementation : any) : Array { + let parsed : any = JSON.parse(this.data); + let arrayDto:Array = new Array(); + parsed.forEach((entry) => { + let implementationInstance = new dtoImplementation(entry); + arrayDto.push(implementationInstance); + }); + return arrayDto; + } + +} + +export interface HttpJsonResponse { + + getData() : any; + + asDto(dtoImplementation : any) : any; + + asArrayDto(dtoImplementation : any) : Array; + +} + +export interface HttpJsonRequest { + + setMethod(methodName: string) : DefaultHttpJsonRequest; + + setBody(body : any) : DefaultHttpJsonRequest; + + request() : Promise; +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/i18n/i18n.ts b/dockerfiles/lib-typescript/src/spi/i18n/i18n.ts new file mode 100644 index 00000000000..8634a66907f --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/i18n/i18n.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + + +export class I18n { + + mapOfConstants : Map; + + constructor() { + this.mapOfConstants = new Map(); + } + + get(key: string, ...optional: Array) : string { + + let constant : string = this.mapOfConstants.get(key); + // not found, return the key + if (!constant) { + return key; + } + + // replace values + return constant.replace(/{(\d+)}/g, (match, number) => { + return typeof optional[number] != 'undefined' + ? optional[number] + : match + }); + } + + + add(key : string, value : string) { + this.mapOfConstants.set(key, value); + } + +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/spi/index.ts b/dockerfiles/lib-typescript/src/spi/index.ts new file mode 100644 index 00000000000..dd6d92b5434 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +export * from './decorator/argument-processor'; +export * from './decorator/message'; +export * from './decorator/parameter'; +export * from './docker/container-version'; +export * from './docker/recipebuilder'; +export * from './docker/remoteip'; +export * from './http/default-http-json-request'; +export * from './i18n/i18n'; +export * from './log/log'; +export * from './websocket/messagebuilder'; +export * from './websocket/messagebus'; +export * from './websocket/messagebus-subscriber'; +export * from './websocket/websocket'; diff --git a/dockerfiles/lib-typescript/src/spi/log/log.ts b/dockerfiles/lib-typescript/src/spi/log/log.ts new file mode 100644 index 00000000000..136659a772b --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/log/log.ts @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {ProductName} from "../../utils/product-name"; +/** + * Logging class allowing to log message + * @author Florent Benoit + */ +export class Log { + + static debugEnabled : boolean = false; + static context : string = ProductName.getDisplayName(); + static logger : Log; + static disabledPrefix : boolean = false; + + static BLUE: string = '\u001b[34m'; + static GREEN : string = '\u001b[32m'; + static RED : string = '\u001b[31m'; + static ORANGE: string = '\u001b[33m'; + static NC : string = '\u001b[39m'; + + static INFO_PREFIX: string = Log.GREEN + 'INFO:' + Log.NC; + static DEBUG_PREFIX: string = Log.BLUE + 'DEBUG:' + Log.NC; + static WARN_PREFIX: string = Log.ORANGE + 'WARN:' + Log.NC; + static ERROR_PREFIX: string = Log.RED + 'ERROR:' + Log.NC; + + static getLogger() : Log { + if (!Log.logger) { + Log.logger = new Log(); + } + return Log.logger; + } + + info(message : string, ...optional: Array) { + this.log('info', message, optional); + } + + warn(message : string, ...optional: Array) { + this.log('warn', message, optional); + } + + error(message : string, ...optional: Array) { + this.log('error', message, optional); + } + + debug(message : string, ...optional: Array) { + if (Log.debugEnabled) { + this.log('debug', message, optional); + } + } + + /** + * Direct option is that it doesn't show any logger trace + */ + direct(message : string, ...optional: Array) { + this.log('direct', message, optional); + } + + + log(type: LogType, message: string, optional?: Array) { + let useContext : boolean = true; + var prefix: String; + var displayEachLine : boolean = false; + if ('info' === type) { + prefix = Log.INFO_PREFIX; + } else if ('debug' === type) { + prefix = Log.DEBUG_PREFIX; + } else if ('warn' === type) { + prefix = Log.WARN_PREFIX; + } else if ('error' === type) { + prefix = Log.ERROR_PREFIX; + } else if ('direct' === type) { + prefix = ''; + useContext = false; + } else if ('multiline:info' === type) { + prefix = Log.INFO_PREFIX; + displayEachLine = true; + } + + if (useContext && Log.context) { + prefix += ' ' + Log.context + ': '; + } + if (Log.disabledPrefix) { + prefix = ''; + } + + var consoleMethod : any; + if ('error' === type) { + consoleMethod = console.error; + } else { + consoleMethod = console.log; + } + + if (displayEachLine) { + message.split("\n").forEach((line) => { + consoleMethod(prefix + line); + }) + } else { + if (optional && optional.length > 0) { + consoleMethod(prefix + message, optional.join(' ')); + } else { + consoleMethod(prefix + message); + } + } + + } + + + static enableDebug() : void { + Log.debugEnabled = true; + } + + static disablePrefix() : void { + Log.disabledPrefix = true; + } + +} + + +export type LogType = 'info' | 'debug' | 'warn' | 'error' | 'direct' | 'multiline:info'; diff --git a/dockerfiles/lib-typescript/src/spi/websocket/messagebuilder.ts b/dockerfiles/lib-typescript/src/spi/websocket/messagebuilder.ts new file mode 100644 index 00000000000..bce88e6b8bd --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/websocket/messagebuilder.ts @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {UUID} from "../../utils/index"; + +/** + * Generator of the messages to send with the {@link MessageBus} object. + * @author Florent Benoit + */ +export class MessageBuilder { + + method: string; + path: string; + TYPE: string; + message : any; + + constructor(method? : string, path? : string) { + this.TYPE = 'x-everrest-websocket-message-type'; + if (method) { + this.method = method; + } else { + this.method = 'POST'; + } + if (path) { + this.path = path; + } else { + this.path = null; + } + + + this.message = {}; + // add uuid + this.message.uuid = UUID.build(); + + this.message.method = this.method; + this.message.path = this.path; + this.message.headers = []; + this.message.body; + } + + subscribe(channel) { + var header = {name: this.TYPE, value: 'subscribe-channel'}; + this.message.headers.push(header); + this.message.body = JSON.stringify({channel: channel}); + return this; + } + + unsubscribe(channel) { + var header = {name:this.TYPE, value: 'unsubscribe-channel'}; + this.message.headers.push(header); + this.message.body = JSON.stringify({channel: channel}); + return this; + } + + /** + * Prepares ping frame for server. + * + * @returns {MessageBuilder} + */ + ping() { + var header = {name:this.TYPE, value: 'ping'}; + this.message.headers.push(header); + return this; + } + + build() { + return this.message; + } + +} diff --git a/dockerfiles/lib-typescript/src/spi/websocket/messagebus-subscriber.ts b/dockerfiles/lib-typescript/src/spi/websocket/messagebus-subscriber.ts new file mode 100644 index 00000000000..f9264f7f8dd --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/websocket/messagebus-subscriber.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +/** + * Interface required to be implemented to subscribe to message bus messages. + * @author Florent Benoit + */ +export interface MessageBusSubscriber { + + handleMessage(message: string); + + +} diff --git a/dockerfiles/lib-typescript/src/spi/websocket/messagebus.ts b/dockerfiles/lib-typescript/src/spi/websocket/messagebus.ts new file mode 100644 index 00000000000..1a9f1683df7 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/websocket/messagebus.ts @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {MessageBuilder} from './messagebuilder'; +import {MessageBusSubscriber} from './messagebus-subscriber'; +import {Log} from "../log/log"; +import {Websocket} from "./websocket"; + + +/** + * Allow to handle calls to the MessageBus running inside Eclipse Che by sending and receiving the messages. + * It handles the UUID messages and subscribers that can subscribe/unsubscribe + * @author Florent Benoit + */ +export class MessageBus { + + websocketConnection : any; + heartbeatPeriod : number; + subscribersByChannel : Map>; + keepAlive : any; + delaySend: Array; + websocketClient : any; + closed : boolean; + websocket : Websocket; + + constructor(websocketClient : any, url: string, websocket: Websocket, resolve : any, reject : any) { + + this.websocketClient = websocketClient; + this.websocket = websocket; + + this.closed = false; + this.delaySend = []; + + var client = websocketClient.on('connectFailed', (error) => { + Log.getLogger().error('Connect Error: ' + error.toString()); + reject(error); + }); + + + client.on('error', error => { + Log.getLogger().error('websocketclient error', error.toString()); + reject(error); + }); + + client.on('connect', (connection) => { + // resolve the promise of connecting to the bus + resolve(true); + this.websocketConnection = connection; + // push all previous messages + this.delaySend.forEach((subscribeOrder) => this.send(subscribeOrder)); + + // remove them + this.delaySend.length = 0; + + // init keep alive + this.setKeepAlive(); + + connection.on('error', (error) => { + if (!this.closed) { + Log.getLogger().error("Connection Error: " + error.toString()); + } + }); + connection.on('close', () => { + if (!this.closed) { + Log.getLogger().error('Websocket connection closed'); + } + }); + connection.on('message', (message) => { + if (message.type === 'utf8') { + this.handleMessage(message.utf8Data); + } + }); + + }); + + // now connect + websocketClient.connect(url); + + + + this.heartbeatPeriod = 3000;//1000 * 50; //ping each 50 seconds + + this.subscribersByChannel = new Map>(); + + } + + close() { + this.closed = true; + this.websocketConnection.close(); + } + + + /** + * Sets the keep alive interval, which sends + * ping frame to server to keep connection alive. + * */ + setKeepAlive() { + this.keepAlive = setTimeout(this.ping, this.heartbeatPeriod, this); + } + + /** + * Sends ping frame to server. + */ + ping(instance) { + instance.send(new MessageBuilder().ping().build()); + } + + /** + * Restart ping timer (cancel previous and start again). + */ + restartPing () { + if (this.keepAlive) { + clearTimeout(this.keepAlive); + } + + this.setKeepAlive(); + } + + /** + * Subscribes a new callback which will listener for messages sent to the specified channel. + * Upon the first subscribe to a channel, a message is sent to the server to + * subscribe the client for that channel. Subsequent subscribes for a channel + * already previously subscribed to do not trigger a send of another message + * to the server because the client has already a subscription, and merely registers + * (client side) the additional handler to be fired for events received on the respective channel. + */ + subscribe(channel, callback) { + // already subscribed ? + var existingSubscribers = this.subscribersByChannel.get(channel); + if (!existingSubscribers) { + // register callback + + var subscribers = []; + subscribers.push(callback); + this.subscribersByChannel.set(channel, subscribers); + + var subscribeOrder = new MessageBuilder().subscribe(channel).build(); + // send subscribe order + if (!this.websocketConnection) { + this.delaySend.push(subscribeOrder); + } else { + this.send(subscribeOrder); + } + + } else { + // existing there, add only callback + existingSubscribers.push(callback); + } + } + + + + /** + * Unsubscribes a previously subscribed handler listening on the specified channel. + * If it's the last unsubscribe to a channel, a message is sent to the server to + * unsubscribe the client for that channel. + */ + unsubscribe(channel) { + // already subscribed ? + var existingSubscribers = this.subscribersByChannel.get(channel); + // unable to cancel if not existing channel + if (!existingSubscribers) { + return; + } + + if (existingSubscribers.length > 1) { + // only remove callback + for(let i = 0; i < existingSubscribers.length; i++) { + delete existingSubscribers[i]; + } + } else { + // only one element, remove and send server message + this.subscribersByChannel.delete(channel); + + // send unsubscribe order + this.send(new MessageBuilder().unsubscribe(channel).build()); + } + } + + + + send(message) { + var stringified = JSON.stringify(message); + this.websocketConnection.sendUTF(stringified); + } + + + handleMessage(message) { + + // handling the receive of a message + // needs to parse it + var jsonMessage = JSON.parse(message); + + // get headers + var headers = jsonMessage.headers; + + var channelHeader; + // found channel headers + for(let i = 0; i < headers.length; i++) { + let header = headers[i]; + if ('x-everrest-websocket-channel' === header.name) { + channelHeader = header; + continue; + } + } + + + if (channelHeader) { + // message for a channel, look at current subscribers + var subscribers : Array = this.subscribersByChannel.get(channelHeader.value); + if (subscribers) { + subscribers.forEach((subscriber : MessageBusSubscriber) => { + + // Convert to JSON object if it's a JSON body + var data; + try { + data = JSON.parse(jsonMessage.body); + } catch (error) { + // keep raw data + data = jsonMessage.body; + } + subscriber.handleMessage(data); + }); + } + } + + // restart ping after received message + this.restartPing(); + } + +} diff --git a/dockerfiles/lib-typescript/src/spi/websocket/websocket.ts b/dockerfiles/lib-typescript/src/spi/websocket/websocket.ts new file mode 100644 index 00000000000..11f2af86a29 --- /dev/null +++ b/dockerfiles/lib-typescript/src/spi/websocket/websocket.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +import {MessageBus} from './messagebus'; + +/** + * This class is handling the websocket handling by providing a {@link MessageBus} object + * @author Florent Benoit + */ +export class Websocket { + + /** + * Websocket client object. + */ + wsClient: any; + + /** + * Map of bus per workspace ID. + */ + messageBus : MessageBus; + + /** + * Default constructor initializing websocket. + */ + constructor() { + this.wsClient = require('websocket').client; + } + + /** + * Gets a MessageBus object for a remote workspace, by providing the remote URL to this websocket + * @param websocketURL the remote host base WS url + * @param workspaceId the workspaceID used as suffix for the URL + */ + getMessageBus(websocketURL) : Promise { + if (this.messageBus) { + return Promise.resolve(this.messageBus); + } + var webSocketClient: any = new this.wsClient(); + var remoteWebsocketUrl: string = websocketURL; + let promise : Promise = new Promise((resolve, reject) => { + this.messageBus = new MessageBus(webSocketClient, remoteWebsocketUrl, this, resolve, reject); + }); + + return promise.then(() => { + return this.messageBus; + }); + + } + +} diff --git a/dockerfiles/lib-typescript/src/utils/index.ts b/dockerfiles/lib-typescript/src/utils/index.ts new file mode 100644 index 00000000000..e251bb4836a --- /dev/null +++ b/dockerfiles/lib-typescript/src/utils/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +export * from './string-utils'; +export * from './uuid'; diff --git a/dockerfiles/lib-typescript/src/utils/product-name.ts b/dockerfiles/lib-typescript/src/utils/product-name.ts new file mode 100644 index 00000000000..58b5cdd8236 --- /dev/null +++ b/dockerfiles/lib-typescript/src/utils/product-name.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +/** + * Creates an helper class for getting product name + * @author Florent Benoit + */ +export class ProductName { + static getDisplayName() : string { + let productName: string = process.env.CHE_PRODUCT_NAME; + if (!productName) { + return 'Eclipse Che'; + } + return productName; + } + +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/utils/string-utils.spec.ts b/dockerfiles/lib-typescript/src/utils/string-utils.spec.ts new file mode 100644 index 00000000000..a543317581e --- /dev/null +++ b/dockerfiles/lib-typescript/src/utils/string-utils.spec.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {StringUtils} from './string-utils'; + +let expect = require('chai').expect; + + +describe("String Utils tests", () => { + it("not included", () => { + expect(StringUtils.startsWith("toto", 'n')).to.be.false; + }); + + it("starts with", () => { + expect(StringUtils.startsWith("toto", "t")).to.be.true; + }); +}); diff --git a/dockerfiles/lib-typescript/src/utils/string-utils.ts b/dockerfiles/lib-typescript/src/utils/string-utils.ts new file mode 100644 index 00000000000..4add3868396 --- /dev/null +++ b/dockerfiles/lib-typescript/src/utils/string-utils.ts @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +export class StringUtils { + static startsWith(value:string, searchString:string):boolean { + return value.substr(0, searchString.length) === searchString; + } +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/src/utils/uuid.ts b/dockerfiles/lib-typescript/src/utils/uuid.ts new file mode 100644 index 00000000000..754fb40fae1 --- /dev/null +++ b/dockerfiles/lib-typescript/src/utils/uuid.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ + +/** + * Creates an helper class for building UUID (like for message bus channels, etc) + * @author Florent Benoit + */ +export class UUID { + static build() : string { + var time = new Date().getTime(); + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (match) => { + var rem = (time + 16 * Math.random()) % 16 | 0; + time = Math.floor(time / 16); + return (match === 'x' ? rem : rem & 7 | 8).toString(16); + }); + } + +} \ No newline at end of file diff --git a/dockerfiles/lib-typescript/tsconfig.json b/dockerfiles/lib-typescript/tsconfig.json new file mode 100644 index 00000000000..c10f91e39e2 --- /dev/null +++ b/dockerfiles/lib-typescript/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es6", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "outDir": "lib", + "module": "commonjs", + "moduleResolution": "node", + "types": [ + "node", + "mocha" + ] + }, + "include": [ + "src/**/*" + ],"exclude": [ + "node_modules", + "jspm_packages", + "dependencies" +] +} diff --git a/dockerfiles/mount/Dockerfile b/dockerfiles/mount/Dockerfile new file mode 100644 index 00000000000..5b8987b1436 --- /dev/null +++ b/dockerfiles/mount/Dockerfile @@ -0,0 +1,69 @@ +# Copyright (c) 2012-2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial implementation +# +# build: +# docker build -t eclipse/che-mount . +# +# use: +# On linux: +# docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse +# --name che-mount +# -v ${HOME}/.ssh:${HOME}/.ssh +# -v ${HOME}/.unison:${HOME}/.unison +# -v /etc/group:/etc/group:ro +# -v /etc/passwd:/etc/passwd:ro +# -u $(id -u ${USER}) +# -v :/mnthost codenvy/che-mount +# +# On Mac or Windows: +# docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse +# --name che-mount +# -v ~/.ssh:/root/.ssh +# -v :/mnthost codenvy/che-mount +# +# RUN IN CONTAINER: +# echo "secret" | $(echo "yes" | sshfs user@10.0.75.2:/projects /mntssh -p 32774) +# +# TO UNMOUNT IN CONTAINER +# fusermount -u /mntssh +# +# INTERNAL SYNC SCRIPT +# /bin/synch.sh +FROM alpine:3.4 + +ENV UNISON_VERSION=2.48.4 + +RUN apk add --update build-base curl bash sshfs && \ + apk add ocaml --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted && \ + curl -L https://www.seas.upenn.edu/~bcpierce/unison/download/releases/unison-$UNISON_VERSION/unison-$UNISON_VERSION.tar.gz | tar xzv -C /tmp && \ + cd /tmp/src && \ + sed -i -e 's/GLIBC_SUPPORT_INOTIFY 0/GLIBC_SUPPORT_INOTIFY 1/' fsmonitor/linux/inotify_stubs.c && \ + make && \ + cp /tmp/src/unison /usr/local/bin && \ + cp /tmp/src/unison-fsmonitor /usr/local/bin && \ + apk del ocaml curl build-base bash && \ + rm -rf /tmp /var/cache/apk/* && \ + mkdir /mntssh && chmod -R 777 /mntssh && \ + mkdir /mnthost && chmod -R 777 /mnthost + +ENV DOCKER_BUCKET get.docker.com +ENV DOCKER_VERSION 1.6.0 + +RUN set -x \ + && apk add --no-cache \ + ca-certificates \ + curl \ + openssl \ + && curl -sL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" \ + > /usr/bin/docker; chmod +x /usr/bin/docker \ + && apk del curl ca-certificates openssl + +COPY /entrypoint.sh /bin/entrypoint.sh + +ENTRYPOINT ["/bin/entrypoint.sh"] diff --git a/dockerfiles/mount/build.sh b/dockerfiles/mount/build.sh new file mode 100755 index 00000000000..5c2673bfbe2 --- /dev/null +++ b/dockerfiles/mount/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-mount" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build diff --git a/dockerfiles/mount/entrypoint.sh b/dockerfiles/mount/entrypoint.sh new file mode 100755 index 00000000000..86d3544d5a3 --- /dev/null +++ b/dockerfiles/mount/entrypoint.sh @@ -0,0 +1,137 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Tyler Jewell - Initial implementation +# +init_logging() { + BLUE='\033[1;34m' + GREEN='\033[0;32m' + RED='\033[0;31m' + NC='\033[0m' +} + +init_global_variables() { + + USAGE=" +Usage on Linux + docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse + --name che-mount + -v \${HOME}/.ssh:\${HOME}/.ssh + -v /etc/group:/etc/group:ro + -v /etc/passwd:/etc/passwd:ro + -v :/profile + -u \$(id -u \${USER}) + -v /:/mnthost eclipse/che-mount + + ID or Name of the workspace or namespace:workspace-name + +Usage on Mac or Windows: + docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse + --name che-mount + -v :/profile + -v /:/mnthost eclipse/che-mount + + ID or Name of the workspace or namespace:workspace-name +" + UNISON_REPEAT_DELAY_IN_SEC=2 + WORKSPACE_NAME= + COMMAND_EXTRA_ARGS= +} + +parse_command_line () { + if [ $# -eq 0 ]; then + usage + return 1 + fi + + # See if profile document was provided + mkdir -p $HOME/.unison + cp -rf /profile/default.prf $HOME/.unison/default.prf + + WORKSPACE_NAME=$1 + shift + COMMAND_EXTRA_ARGS="$*" +} + +usage () { + printf "%s" "${USAGE}" +} + +info() { + printf "${GREEN}INFO:${NC} %s\n" "${1}" +} + +debug() { + printf "${BLUE}DEBUG:${NC} %s\n" "${1}" +} + +error() { + echo "---------------------------------------" + echo "!!!" + echo "!!! ${1}" + echo "!!!" + echo "---------------------------------------" + return 1 +} + +stop_sync() { + echo "Received interrupt signal. Exiting." + exit 1 +} + +# See: https://sipb.mit.edu/doc/safe-shell/ +set -u + +# on callback, kill the last background process, which is `tail -f /dev/null` and execute the specified handler +trap 'stop_sync' SIGHUP SIGTERM SIGINT + +init_logging +init_global_variables +parse_command_line "$@" +status=$? +if [ $status -ne 0 ]; then + exit 1 +fi + +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action:${CHE_VERSION} get-ssh-data ${WORKSPACE_NAME} ${COMMAND_EXTRA_ARGS} > $HOME/env +if [ $? -ne 0 ]; then + error "ERROR: Error when trying to get workspace data for workspace named ${WORKSPACE_NAME}" + echo "List of workspaces are:" + docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action:${CHE_VERSION} list-workspaces + return 1 +fi + +source $HOME/env + +# store private key +mkdir $HOME/.ssh +echo "${SSH_PRIVATE_KEY}" > $HOME/.ssh/id_rsa +chmod 600 $HOME/.ssh/id_rsa + +info "INFO: (che mount): Mounting ${SSH_USER}@${SSH_IP}:/projects with SSHFS" +sshfs ${SSH_USER}@${SSH_IP}:/projects /mntssh -p ${SSH_PORT} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no + +status=$? +if [ $status -ne 0 ]; then + error "ERROR: Fatal error occurred ($status)" + exit 1 +fi +info "INFO: (che mount): Successfully mounted ${SSH_USER}@${SSH_IP}:/projects (${SSH_PORT})" +info "INFO: (che mount): Initial sync...Please wait." +unison /mntssh /mnthost -batch -fat -silent -auto -prefer=newer -log=false > /dev/null 2>&1 +status=$? +if [ $status -ne 0 ]; then + error "ERROR: Fatal error occurred ($status)" + exit 1 +fi +info "INFO: (che mount): Background sync continues every ${UNISON_REPEAT_DELAY_IN_SEC} seconds." +info "INFO: (che mount): This terminal will block while the synchronization continues." +info "INFO: (che mount): To stop, issue a SIGTERM or SIGINT, usually CTRL-C." + +# run application +unison /mntssh /mnthost -batch -retry 10 -fat -silent -copyonconflict -auto -prefer=newer -repeat=${UNISON_REPEAT_DELAY_IN_SEC} -log=false > /dev/null 2>&1 diff --git a/dockerfiles/test/Dockerfile b/dockerfiles/test/Dockerfile new file mode 100644 index 00000000000..69a1f1e5fba --- /dev/null +++ b/dockerfiles/test/Dockerfile @@ -0,0 +1,15 @@ +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# build: +# docker build -t eclipse/che-test . +# +# use: +# docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-test [command] + +FROM eclipse/che-lib-typescript:nightly + +ENTRYPOINT ["node", "/che-lib/index.js", "che-test"] diff --git a/dockerfiles/test/README.md b/dockerfiles/test/README.md new file mode 100644 index 00000000000..bd5f7d63853 --- /dev/null +++ b/dockerfiles/test/README.md @@ -0,0 +1,22 @@ +### Testing local or remote Eclipse Che instance with a Docker container + +## Build container +``` +$ build.sh (on Unix) +``` + +## Run a test +``` +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-test +``` + +## Get available tests +``` +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-test +``` + +## Get help on a test +``` +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-test --help +``` + diff --git a/dockerfiles/test/build.sh b/dockerfiles/test/build.sh new file mode 100755 index 00000000000..f2db599d0b1 --- /dev/null +++ b/dockerfiles/test/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2016 Codenvy, S.A. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +IMAGE_NAME="eclipse/che-test" +. $(cd "$(dirname "$0")"; pwd)/../build.include + +init +build From 9f5c994156a9f3ec5c4d7ae2e9c44793489a5bc4 Mon Sep 17 00:00:00 2001 From: Florent BENOIT Date: Thu, 1 Dec 2016 08:25:12 -0700 Subject: [PATCH 35/74] Fix ssh client calls for UD and CLI (#3238) * Fix ssh client calls It's due to the breaking change introduced by https://github.com/eclipse/che/pull/3000 where name is now a parameter, not a path attribute Change-Id: I88e0e5fb215351c59ce4a73494feb3670455c954 Signed-off-by: Florent BENOIT Change-Id: I745efd45dbb1459e40f659caa63f559701c4e9aa Signed-off-by: Florent BENOIT --- dashboard/src/components/api/che-ssh.factory.ts | 4 ++-- dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dashboard/src/components/api/che-ssh.factory.ts b/dashboard/src/components/api/che-ssh.factory.ts index ef237d1fe42..399a93efd55 100644 --- a/dashboard/src/components/api/che-ssh.factory.ts +++ b/dashboard/src/components/api/che-ssh.factory.ts @@ -49,8 +49,8 @@ export class CheSsh { // remote call this.remoteSshAPI = this.$resource('/api/ssh', {}, { - getKeyPair: { method: 'GET', url: '/api/ssh/:serviceId/:nameId'}, - removeKey: { method: 'DELETE', url: '/api/ssh/:serviceId/:nameId'}, + getKeyPair: { method: 'GET', url: '/api/ssh/:serviceId/find?name=:nameId'}, + removeKey: { method: 'DELETE', url: '/api/ssh/:serviceId/?name=:nameId'}, generateKey: { method: 'POST', url: '/api/ssh/generate'}, }); } diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts b/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts index adc77fb3ed2..c84664d7f87 100644 --- a/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts +++ b/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts @@ -45,7 +45,7 @@ export class Ssh { * when any other error occurs during ssh pair fetching */ getPair(service: string, name: string):Promise { - var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/ssh/' + service + '/' + name, 200); + var jsonRequest:HttpJsonRequest = new DefaultHttpJsonRequest(this.authData, '/api/ssh/' + service + '/find?name=' + name, 200); return jsonRequest.request().then((jsonResponse:HttpJsonResponse) => { return jsonResponse.asDto(org.eclipse.che.api.ssh.shared.dto.SshPairDtoImpl); }); From 4f83334a107f8251d1b78ec0d50ca5461ef5fe9e Mon Sep 17 00:00:00 2001 From: Florent BENOIT Date: Thu, 1 Dec 2016 10:56:21 -0700 Subject: [PATCH 36/74] add all CHE_ properties to che.env file at first (#3246) Change-Id: Ia7a48355d81dc1ba7b4b86726038637ef3e44e68 Signed-off-by: Florent BENOIT --- dockerfiles/init/modules/che/templates/che.env.erb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dockerfiles/init/modules/che/templates/che.env.erb b/dockerfiles/init/modules/che/templates/che.env.erb index c434a00e1eb..e42644c5509 100644 --- a/dockerfiles/init/modules/che/templates/che.env.erb +++ b/dockerfiles/init/modules/che/templates/che.env.erb @@ -1,3 +1,11 @@ +# Include all custom CHE_* properties that user may has defined in its che.env file +<% ENV.each do |k,v| -%> +<% if k.include? "CHE_" then -%> +<%= k + '=' + v %> +<% end -%> +<% end -%> + + CHE_IP=<%= scope.lookupvar('che::che_ip') %> CHE_PORT=<%= scope.lookupvar('che::che_port') %> CHE_LOGS_DIR=/logs From 51cb17368cb9670d29460c554b23ebc63ffc6ef0 Mon Sep 17 00:00:00 2001 From: Roman Nikitenko Date: Thu, 1 Dec 2016 00:17:52 +0200 Subject: [PATCH 37/74] CHE-2391. File content synchronization after rename resource Signed-off-by: Roman Nikitenko --- .../che/ide/editor/EditorApiModule.java | 6 +- .../EditorContentSynchronizerImpl.java | 67 ++++++++++- .../EditorGroupSychronizationFactory.java | 26 ----- .../EditorContentSynchronizerImplTest.java | 107 +++++++++++++----- .../orion/client/OrionEditorPresenter.java | 21 ++-- 5 files changed, 148 insertions(+), 79 deletions(-) delete mode 100644 ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSychronizationFactory.java diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorApiModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorApiModule.java index 61509b6022d..de7393f2ec3 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorApiModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorApiModule.java @@ -37,7 +37,6 @@ import org.eclipse.che.ide.editor.quickfix.QuickAssistWidgetFactory; import org.eclipse.che.ide.editor.synchronization.EditorContentSynchronizer; import org.eclipse.che.ide.editor.synchronization.EditorContentSynchronizerImpl; -import org.eclipse.che.ide.editor.synchronization.EditorGroupSychronizationFactory; import org.eclipse.che.ide.editor.synchronization.EditorGroupSynchronization; import org.eclipse.che.ide.editor.synchronization.EditorGroupSynchronizationImpl; import org.eclipse.che.ide.editor.texteditor.TextEditorPartViewImpl; @@ -67,10 +66,7 @@ protected void configure() { bind(EditorPartStackView.class); bind(EditorContentSynchronizer.class).to(EditorContentSynchronizerImpl.class).in(Singleton.class); - - install(new GinFactoryModuleBuilder() - .implement(EditorGroupSynchronization.class, EditorGroupSynchronizationImpl.class) - .build(EditorGroupSychronizationFactory.class)); + bind(EditorGroupSynchronization.class).to(EditorGroupSynchronizationImpl.class); // the text editor view bind(TextEditorPartView.class).to(TextEditorPartViewImpl.class); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImpl.java index 85a697f7771..f4ee1050b1d 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImpl.java @@ -11,6 +11,7 @@ package org.eclipse.che.ide.editor.synchronization; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -20,11 +21,19 @@ import org.eclipse.che.ide.api.event.ActivePartChangedHandler; import org.eclipse.che.ide.api.parts.EditorPartStack; import org.eclipse.che.ide.api.parts.PartPresenter; +import org.eclipse.che.ide.api.resources.ResourceChangedEvent; +import org.eclipse.che.ide.api.resources.ResourceChangedEvent.ResourceChangedHandler; +import org.eclipse.che.ide.api.resources.ResourceDelta; import org.eclipse.che.ide.resource.Path; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import static org.eclipse.che.ide.api.resources.ResourceDelta.ADDED; +import static org.eclipse.che.ide.api.resources.ResourceDelta.MOVED_FROM; +import static org.eclipse.che.ide.api.resources.ResourceDelta.MOVED_TO; + /** * The default implementation of {@link EditorContentSynchronizer}. @@ -36,17 +45,19 @@ * @author Roman Nikitenko */ @Singleton -public class EditorContentSynchronizerImpl implements EditorContentSynchronizer, ActivePartChangedHandler { - private final Map editorGroups; - private final EditorGroupSychronizationFactory editorGroupSychronizationFactory; +public class EditorContentSynchronizerImpl implements EditorContentSynchronizer, ActivePartChangedHandler, + ResourceChangedHandler { + final Map editorGroups; + final Provider editorGroupSyncProvider; @Inject public EditorContentSynchronizerImpl(EventBus eventBus, - EditorGroupSychronizationFactory editorGroupSychronizationFactory) { - this.editorGroupSychronizationFactory = editorGroupSychronizationFactory; + Provider editorGroupSyncProvider) { + this.editorGroupSyncProvider = editorGroupSyncProvider; this.editorGroups = new HashMap<>(); eventBus.addHandler(ActivePartChangedEvent.TYPE, this); + eventBus.addHandler(ResourceChangedEvent.getType(), this); } /** @@ -61,7 +72,7 @@ public void trackEditor(EditorPartPresenter editor) { if (editorGroups.containsKey(path)) { editorGroups.get(path).addEditor(editor); } else { - EditorGroupSynchronization group = editorGroupSychronizationFactory.create(); + EditorGroupSynchronization group = editorGroupSyncProvider.get(); editorGroups.put(path, group); group.addEditor(editor); } @@ -101,4 +112,48 @@ public void onActivePartChanged(ActivePartChangedEvent event) { editorGroups.get(path).onActiveEditorChanged(activeEditor); } } + + @Override + public void onResourceChanged(ResourceChangedEvent event) { + final ResourceDelta delta = event.getDelta(); + if (delta.getKind() != ADDED || (delta.getFlags() & (MOVED_FROM | MOVED_TO)) == 0) { + return; + } + + final Path fromPath = delta.getFromPath(); + final Path toPath = delta.getToPath(); + + if (delta.getResource().isFile()) { + onFileChanged(fromPath, toPath); + } else { + onFolderChanged(fromPath, toPath); + } + } + + private void onFileChanged(Path fromPath, Path toPath) { + final EditorGroupSynchronization group = editorGroups.remove(fromPath); + if (group != null) { + editorGroups.put(toPath, group); + } + } + + private void onFolderChanged(Path fromPath, Path toPath) { + final Map newGroups = new HashMap<>(editorGroups.size()); + final Iterator> iterator = editorGroups.entrySet().iterator(); + while (iterator.hasNext()) { + final Map.Entry entry = iterator.next(); + final Path groupPath = entry.getKey(); + final EditorGroupSynchronization group = entry.getValue(); + + if (fromPath.isPrefixOf(groupPath)) { + final Path relPath = groupPath.removeFirstSegments(fromPath.segmentCount()); + final Path newPath = toPath.append(relPath); + + newGroups.put(newPath, group); + iterator.remove(); + } + } + + editorGroups.putAll(newGroups); + } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSychronizationFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSychronizationFactory.java deleted file mode 100644 index 53fa4709e2e..00000000000 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/synchronization/EditorGroupSychronizationFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.ide.editor.synchronization; - -/** - * The factory creates instances of {@link EditorGroupSynchronization} to provide the synchronization of - * the content for them. - * - * @author Roman Nikitenko - */ -public interface EditorGroupSychronizationFactory { - /** - * Creates implementation of {@link EditorGroupSynchronization}. - * - * @return an instance of {@link EditorGroupSynchronization} - */ - EditorGroupSynchronization create(); -} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImplTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImplTest.java index 3cf49896260..98c28fd0dab 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImplTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/editor/synchronization/EditorContentSynchronizerImplTest.java @@ -10,13 +10,17 @@ *******************************************************************************/ package org.eclipse.che.ide.editor.synchronization; +import com.google.inject.Provider; +import com.google.web.bindery.event.shared.Event; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorInput; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.editor.EditorWithAutoSave; import org.eclipse.che.ide.api.event.ActivePartChangedEvent; +import org.eclipse.che.ide.api.resources.Resource; +import org.eclipse.che.ide.api.resources.ResourceChangedEvent; +import org.eclipse.che.ide.api.resources.ResourceDelta; import org.eclipse.che.ide.api.resources.VirtualFile; import org.eclipse.che.ide.resource.Path; import org.junit.Before; @@ -27,13 +31,14 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.util.ArrayList; -import java.util.List; -import static org.mockito.Matchers.eq; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; @@ -41,14 +46,15 @@ /** @author Roman Nikitenko */ @RunWith(MockitoJUnitRunner.class) public class EditorContentSynchronizerImplTest { + private static final String FOLDER_PATH = "testProject/src/main/java/org/eclipse/che/examples/"; + private static final String FILE_NAME = "someFile"; + private static final String FILE_PATH = FOLDER_PATH + FILE_NAME; //constructor mocks @Mock - private EventBus eventBus; + private EventBus eventBus; @Mock - private EditorAgent editorAgent; - @Mock - private EditorGroupSychronizationFactory editorGroupSychronizationFactory; + private Provider editorGroupSyncProvider; //additional mocks @Mock @@ -69,27 +75,23 @@ public void init() { activeEditor = mock(EditorPartPresenter.class, withSettings().extraInterfaces(EditorWithAutoSave.class)); when(activeEditor.getEditorInput()).thenReturn(editorInput); when(editorInput.getFile()).thenReturn(virtualFile); - when(virtualFile.getLocation()).thenReturn(new Path("somePath")); - when(editorAgent.getActiveEditor()).thenReturn(activeEditor); - when(editorGroupSychronizationFactory.create()).thenReturn(editorGroupSynchronization); + when(virtualFile.getLocation()).thenReturn(new Path(FILE_PATH)); + when(editorGroupSyncProvider.get()).thenReturn(editorGroupSynchronization); } @Test public void constructorShouldBeVerified() { - verify(eventBus).addHandler(Matchers.anyObject(), eq(editorContentSynchronizer)); + verify(eventBus, times(2)).addHandler(Matchers.>anyObject(), anyObject()); } @Test public void shouldCreateNewEditorGroup() { EditorPartPresenter openedEditor = mock(EditorPartPresenter.class); when(openedEditor.getEditorInput()).thenReturn(editorInput); - List openedFiles = new ArrayList<>(1); - openedFiles.add(openedEditor); - when(editorAgent.getOpenedEditors()).thenReturn(openedFiles); editorContentSynchronizer.trackEditor(activeEditor); - verify(editorGroupSychronizationFactory).create(); + verify(editorGroupSyncProvider).get(); } @Test @@ -98,18 +100,14 @@ public void shouldAddEditorIntoExistGroup() { EditorPartPresenter openedEditor2 = mock(EditorPartPresenter.class); when(openedEditor1.getEditorInput()).thenReturn(editorInput); when(openedEditor2.getEditorInput()).thenReturn(editorInput); - List openedFiles = new ArrayList<>(1); - openedFiles.add(openedEditor1); - openedFiles.add(openedEditor2); - when(editorAgent.getOpenedEditors()).thenReturn(openedFiles); editorContentSynchronizer.trackEditor(openedEditor1); editorContentSynchronizer.trackEditor(openedEditor2); - reset(editorGroupSychronizationFactory); + reset(editorGroupSyncProvider); editorContentSynchronizer.trackEditor(activeEditor); - verify(editorGroupSychronizationFactory, never()).create(); + verify(editorGroupSyncProvider, never()).get(); verify(editorGroupSynchronization).addEditor(activeEditor); } @@ -119,15 +117,10 @@ public void shouldRemoveEditorFromGroup() { EditorPartPresenter openedEditor2 = mock(EditorPartPresenter.class); when(openedEditor1.getEditorInput()).thenReturn(editorInput); when(openedEditor2.getEditorInput()).thenReturn(editorInput); - List openedFiles = new ArrayList<>(1); - openedFiles.add(openedEditor1); - openedFiles.add(openedEditor2); - when(editorAgent.getOpenedEditors()).thenReturn(openedFiles); editorContentSynchronizer.trackEditor(openedEditor1); editorContentSynchronizer.trackEditor(openedEditor2); editorContentSynchronizer.trackEditor(activeEditor); - reset(editorGroupSychronizationFactory); editorContentSynchronizer.unTrackEditor(activeEditor); @@ -138,9 +131,6 @@ public void shouldRemoveEditorFromGroup() { public void shouldRemoveGroup() { EditorPartPresenter openedEditor1 = mock(EditorPartPresenter.class); when(openedEditor1.getEditorInput()).thenReturn(editorInput); - List openedFiles = new ArrayList<>(1); - openedFiles.add(openedEditor1); - when(editorAgent.getOpenedEditors()).thenReturn(openedFiles); editorContentSynchronizer.trackEditor(openedEditor1); editorContentSynchronizer.trackEditor(activeEditor); @@ -149,4 +139,61 @@ public void shouldRemoveGroup() { verify(editorGroupSynchronization).removeEditor(activeEditor); verify(editorGroupSynchronization).unInstall(); } + + @Test + public void shouldUpdatePathForGroupWhenFileLocationIsChanged() { + Resource resource = mock(Resource.class); + ResourceDelta delta = mock(ResourceDelta.class); + ResourceChangedEvent resourceChangedEvent = new ResourceChangedEvent(delta); + Path fromPath = new Path(FILE_PATH); + Path toPath = new Path("testProject/src/main/java/org/eclipse/che/examples/changedFile"); + EditorPartPresenter openedEditor1 = mock(EditorPartPresenter.class); + + when(openedEditor1.getEditorInput()).thenReturn(editorInput); + when(delta.getKind()).thenReturn(ResourceDelta.ADDED); + when(delta.getFlags()).thenReturn(5632); + when(delta.getFromPath()).thenReturn(fromPath); + when(delta.getToPath()).thenReturn(toPath); + when(delta.getResource()).thenReturn(resource); + when(resource.isFile()).thenReturn(true); + + editorContentSynchronizer.trackEditor(openedEditor1); + editorContentSynchronizer.onResourceChanged(resourceChangedEvent); + + final EditorGroupSynchronization oldGroup = editorContentSynchronizer.editorGroups.get(fromPath); + final EditorGroupSynchronization newGroup = editorContentSynchronizer.editorGroups.get(toPath); + + assertNull(oldGroup); + assertNotNull(newGroup); + } + + @Test + public void shouldUpdatePathForGroupWhenFolderLocationIsChanged() { + Resource resource = mock(Resource.class); + ResourceDelta delta = mock(ResourceDelta.class); + ResourceChangedEvent resourceChangedEvent = new ResourceChangedEvent(delta); + Path fromPath = new Path(FOLDER_PATH); + Path toPath = new Path("testProject/src/main/java/org/eclipse/che/samples/"); + + Path oldFilePath = new Path(FILE_PATH); + Path newFilePath = new Path("testProject/src/main/java/org/eclipse/che/samples/" + FILE_NAME); + EditorPartPresenter openedEditor1 = mock(EditorPartPresenter.class); + + when(openedEditor1.getEditorInput()).thenReturn(editorInput); + when(delta.getKind()).thenReturn(ResourceDelta.ADDED); + when(delta.getFlags()).thenReturn(5632); + when(delta.getFromPath()).thenReturn(fromPath); + when(delta.getToPath()).thenReturn(toPath); + when(delta.getResource()).thenReturn(resource); + when(resource.isFile()).thenReturn(false); + + editorContentSynchronizer.trackEditor(openedEditor1); + editorContentSynchronizer.onResourceChanged(resourceChangedEvent); + + final EditorGroupSynchronization oldGroup = editorContentSynchronizer.editorGroups.get(oldFilePath); + final EditorGroupSynchronization newGroup = editorContentSynchronizer.editorGroups.get(newFilePath); + + assertNull(oldGroup); + assertNotNull(newGroup); + } } diff --git a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java index 8b5d1397fa5..67f1fd0382d 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java +++ b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorPresenter.java @@ -348,20 +348,18 @@ private void onResourceCreated(ResourceDelta delta) { return; } + final Resource resource = delta.getResource(); + final Path movedFrom = delta.getFromPath(); + //file moved directly - if (delta.getFromPath().equals(document.getFile().getLocation())) { - final Resource resource = delta.getResource(); - final Path movedFrom = delta.getFromPath(); - - if (document.getFile().getLocation().equals(movedFrom)) { - deletedFilesController.add(movedFrom.toString()); - document.setFile((File)resource); - input.setFile((File)resource); - } + if (document.getFile().getLocation().equals(movedFrom)) { + deletedFilesController.add(movedFrom.toString()); + document.setFile((File)resource); + input.setFile((File)resource); updateContent(); - } else if (delta.getFromPath().isPrefixOf(document.getFile().getLocation())) { //directory where file moved - final Path relPath = document.getFile().getLocation().removeFirstSegments(delta.getFromPath().segmentCount()); + } else if (movedFrom.isPrefixOf(document.getFile().getLocation())) { //directory where file moved + final Path relPath = document.getFile().getLocation().removeFirstSegments(movedFrom.segmentCount()); final Path newPath = delta.getToPath().append(relPath); appContext.getWorkspaceRoot().getFile(newPath).then(new Operation>() { @@ -381,7 +379,6 @@ public void apply(Optional file) throws OperationException { } }); } - } private void updateTabReference(File file, Path oldPath) { From 65adb7f3b21b543c5b614e1f8b5d09b8d12bb659 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskyi Date: Fri, 2 Dec 2016 10:18:41 +0200 Subject: [PATCH 38/74] Save state of expanded containers when refactoring operations are performed (#3231) * Save state of expanded containers when refactoring operations are performed * Remove unnecessary return statement --- .../project/ProjectExplorerPresenter.java | 144 ++++++++++-------- 1 file changed, 82 insertions(+), 62 deletions(-) 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 15e70d284ab..696072011cf 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 @@ -10,8 +10,7 @@ *******************************************************************************/ package org.eclipse.che.ide.part.explorer.project; -import com.google.common.base.Optional; -import com.google.gwt.core.client.Scheduler; +import com.google.common.collect.Sets; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -19,6 +18,7 @@ import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.CoreLocalizationConstant; +import org.eclipse.che.ide.DelayedTask; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.data.tree.Node; @@ -33,7 +33,6 @@ import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.parts.base.BasePresenter; import org.eclipse.che.ide.api.resources.Container; -import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.api.resources.ResourceChangedEvent; import org.eclipse.che.ide.api.resources.ResourceChangedEvent.ResourceChangedHandler; @@ -50,14 +49,16 @@ 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.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; import javax.validation.constraints.NotNull; +import java.util.HashSet; +import java.util.Set; -import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Preconditions.checkNotNull; import static org.eclipse.che.ide.api.resources.ResourceDelta.ADDED; import static org.eclipse.che.ide.api.resources.ResourceDelta.MOVED_FROM; @@ -84,6 +85,9 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel private final Resources resources; private final TreeExpander treeExpander; + private UpdateTask updateTask = new UpdateTask(); + private Set expandQueue = new HashSet<>(); + private static final int PART_SIZE = 500; private boolean hiddenFilesAreShown; @@ -132,6 +136,19 @@ public void onBeforeExpand(BeforeExpandNodeEvent event) { } }); + 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); + } + + } + } + }); + treeExpander = new ProjectExplorerTreeExpander(view.getTree(), appContext); registerNative(); @@ -156,11 +173,11 @@ private native void registerNative() /*-{ var ProjectExplorer = {}; - ProjectExplorer.expandAll = $entry(function() { + ProjectExplorer.expandAll = $entry(function () { that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doExpand()(); }) - ProjectExplorer.collapseAll = $entry(function() { + ProjectExplorer.collapseAll = $entry(function () { that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doCollapse()(); }) @@ -185,24 +202,6 @@ public void onResourceChanged(ResourceChangedEvent event) { final Tree tree = view.getTree(); final ResourceDelta delta = event.getDelta(); final Resource resource = delta.getResource(); - - if (delta.getKind() == UPDATED) { - for (Node node : tree.getNodeStorage().getAll()) { - if (node instanceof ResourceNode && ((ResourceNode)node).getData().getLocation().equals(delta.getResource().getLocation())) { - final String oldId = tree.getNodeStorage().getKeyProvider().getKey(node); - ((ResourceNode)node).setData(delta.getResource()); - tree.getNodeStorage().reIndexNode(oldId, node); - tree.refresh(node); - - if (tree.isExpanded(node)) { - reloadNode(node); - } - - return; - } - } - } - final NodeSettings nodeSettings = settingsProvider.getSettings(); // process root projects, they have only one segment in path @@ -215,40 +214,36 @@ public void onResourceChanged(ResourceChangedEvent event) { if (node != null) { tree.getNodeStorage().remove(node); } + } else if (delta.getKind() == UPDATED) { + for (Node node : tree.getNodeStorage().getAll()) { + if (node instanceof ResourceNode && + ((ResourceNode)node).getData().getLocation().equals(delta.getResource().getLocation())) { + final String oldId = tree.getNodeStorage().getKeyProvider().getKey(node); + ((ResourceNode)node).setData(delta.getResource()); + tree.getNodeStorage().reIndexNode(oldId, node); + tree.refresh(node); + updateTask.submit(delta.getResource().getLocation()); + } + } } } else { - final Optional parent = resource.getParent(); - final Optional relatedProject = resource.getRelatedProject(); - if (parent.isPresent() && relatedProject.isPresent()) { - final Container container = parent.get(); - final Node parentNode = firstNonNull(getNode(container.getLocation()), getParentNode(container.getLocation())); + if ((delta.getFlags() & (MOVED_FROM | MOVED_TO)) != 0) { + final Node node = getNode(delta.getFromPath()); - if (parentNode != null && tree.isExpanded(parentNode)) { - reloadNode(parentNode); + if (node != null && tree.isExpanded(node)) { + expandQueue.add(delta.getToPath()); } } - // process movement - if ((delta.getFlags() & (MOVED_FROM | MOVED_TO)) != 0) { - final Node parentNode = getParentNode(delta.getFromPath()); + updateTask.submit(resource.getLocation()); - if (parentNode != null && tree.isExpanded(parentNode)) { - reloadNode(parentNode); - } + if (delta.getFromPath() != null) { + updateTask.submit(delta.getFromPath()); } } } - private void reloadNode(final Node node) { - Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { - @Override - public void execute() { - view.getTree().getNodeLoader().loadChildren(node, true); - } - }); - } - private Node getNode(Path path) { final Tree tree = view.getTree(); @@ -261,28 +256,19 @@ private Node getNode(Path path) { return null; } - private Node getParentNode(Path path) { - Node node = null; - - while (node == null) { - if (path.segmentCount() == 0) { - return null; - } - - path = path.parent(); - node = getNode(path); - } - - return node; - } - private boolean isNodeServesLocation(Node node, Path location) { return node instanceof ResourceNode && ((ResourceNode)node).getData().getLocation().equals(location); } @Override public void onMarkerChanged(MarkerChangedEvent event) { - + final Tree tree = view.getTree(); + for (Node node : tree.getNodeStorage().getAll()) { + if (node instanceof ResourceNode && + ((ResourceNode)node).getData().getLocation().equals(event.getResource().getLocation())) { + tree.refresh(node); + } + } } @Override @@ -399,4 +385,38 @@ public boolean isShowHiddenFiles() { return hiddenFilesAreShown; } + private class UpdateTask extends DelayedTask { + + private Set toRefresh = new HashSet<>(); + + public void submit(Path path) { + toRefresh.add(path.uptoSegment(1)); + + delay(500); + } + + @Override + public void onExecute() { + if (view.getTree().getNodeLoader().isBusy()) { + delay(500); + + return; + } + + final Set updateQueue = Sets.newHashSet(toRefresh); + toRefresh.clear(); + + for (Path path : updateQueue) { + final Node node = getNode(path); + + if (node == null) { + continue; + } + + if (getTree().isExpanded(node)) { + view.getTree().getNodeLoader().loadChildren(node, true); + } + } + } + } } From 34279b1813662714f77a67bac7fc22a6a27e6da5 Mon Sep 17 00:00:00 2001 From: Evgen Vidolob Date: Fri, 2 Dec 2016 10:33:45 +0200 Subject: [PATCH 39/74] #2676 use theme color for editor meta tag style (#3254) Signed-off-by: Evgen Vidolob --- .../eclipse/che/ide/editor/orion/client/orion-codenvy-theme.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugin-orion/che-plugin-orion-editor/src/main/resources/org/eclipse/che/ide/editor/orion/client/orion-codenvy-theme.css b/plugins/plugin-orion/che-plugin-orion-editor/src/main/resources/org/eclipse/che/ide/editor/orion/client/orion-codenvy-theme.css index 32e8c8d2faa..fe6fc867353 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/src/main/resources/org/eclipse/che/ide/editor/orion/client/orion-codenvy-theme.css +++ b/plugins/plugin-orion/che-plugin-orion-editor/src/main/resources/org/eclipse/che/ide/editor/orion/client/orion-codenvy-theme.css @@ -326,7 +326,7 @@ } .orionCodenvy .meta.tag { - color: #e8bf55; + color: tag; } .orionCodenvy .meta.preprocessor { From a5d0a5e242b29c17ae12c4bafe1b2a29b4ce552b Mon Sep 17 00:00:00 2001 From: Florent BENOIT Date: Fri, 2 Dec 2016 01:41:50 -0700 Subject: [PATCH 40/74] - Rename base-cli folder to base (#3255) - Rename lib-typescript folder to lib - Update docker image eclipse/che-lib-typescript to be eclipse/che-lib Change-Id: I878b52853a424f14cdec74074055d52dc8e198fd Signed-off-by: Florent BENOIT --- dockerfiles/action/Dockerfile | 2 +- dockerfiles/{base-cli => base}/Dockerfile | 0 dockerfiles/{base-cli => base}/build.sh | 0 .../{base-cli => base}/scripts/base/cli/cli-functions.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_action.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_backup.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_config.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_debug.sh | 0 .../scripts/base/commands/cmd_destroy.sh | 0 .../scripts/base/commands/cmd_download.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_help.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_info.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_init.sh | 0 .../scripts/base/commands/cmd_network.sh | 0 .../scripts/base/commands/cmd_offline.sh | 0 .../scripts/base/commands/cmd_restore.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_rmi.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_ssh.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_start.sh | 0 .../{base-cli => base}/scripts/base/commands/cmd_sync.sh | 0 .../scripts/base/commands/cmd_upgrade.sh | 0 .../scripts/base/commands/cmd_version.sh | 0 dockerfiles/{base-cli => base}/scripts/base/curl.sh | 0 dockerfiles/{base-cli => base}/scripts/base/docker.sh | 0 dockerfiles/{base-cli => base}/scripts/base/paths.sh | 0 dockerfiles/{base-cli => base}/scripts/base/startup.sh | 0 dockerfiles/build-all.sh | 2 +- dockerfiles/dir/Dockerfile | 2 +- dockerfiles/{lib-typescript => lib}/.babelrc | 0 dockerfiles/{lib-typescript => lib}/.dockerignore | 0 dockerfiles/{lib-typescript => lib}/.gitignore | 0 dockerfiles/{lib-typescript => lib}/Dockerfile | 7 ++++--- dockerfiles/{lib-typescript => lib}/Dockerfile.dev | 0 dockerfiles/{lib-typescript => lib}/README.md | 0 dockerfiles/{lib-typescript => lib}/build.sh | 2 +- dockerfiles/{lib-typescript => lib}/dto-pom.xml | 0 dockerfiles/{lib-typescript => lib}/package.json | 4 ++-- .../runtime-dependencies/package.json | 0 dockerfiles/{lib-typescript => lib}/src/api/dto/che-dto.ts | 0 .../src/api/wsmaster/auth/auth-data.ts | 0 .../src/api/wsmaster/machine/machine-service-client.ts | 0 .../api/wsmaster/machine/process-log-output-subscriber.ts | 0 .../machine/process-terminated-event-promise-subscriber.ts | 0 .../src/api/wsmaster/permissions/dto/domaindto.ts | 0 .../src/api/wsmaster/permissions/dto/permissiondto.ts | 0 .../src/api/wsmaster/permissions/permissions.ts | 0 .../src/api/wsmaster/project/project.ts | 0 .../{lib-typescript => lib}/src/api/wsmaster/ssh/ssh.ts | 0 .../{lib-typescript => lib}/src/api/wsmaster/user/user.ts | 0 .../wsmaster/workspace/workspace-log-output-subscriber.ts | 0 .../workspace/workspace-start-event-promise-subscriber.ts | 0 .../workspace/workspace-stop-event-promise-subscriber.ts | 0 .../src/api/wsmaster/workspace/workspace.ts | 0 dockerfiles/{lib-typescript => lib}/src/index.ts | 0 .../src/internal/action/che-action.ts | 0 .../src/internal/action/impl/add-user-action.ts | 0 .../internal/action/impl/create-start-workspace-action.ts | 0 .../src/internal/action/impl/execute-command-action.ts | 0 .../src/internal/action/impl/get-ssh-action.ts | 0 .../src/internal/action/impl/list-workspaces-action.ts | 0 .../src/internal/action/impl/remove-user-action.ts | 0 .../src/internal/action/impl/workspace-ssh-action.ts | 0 .../src/internal/dir/che-dir-constant.properties | 0 .../{lib-typescript => lib}/src/internal/dir/che-dir.ts | 0 .../src/internal/dir/chefile-struct/che-file-struct.ts | 0 .../{lib-typescript => lib}/src/internal/test/che-test.ts | 0 .../internal/test/impl/post-flight-check-test.properties | 0 .../src/internal/test/impl/post-flight-check-test.ts | 0 .../src/spi/ascii/ascii-array-info.ts | 0 .../{lib-typescript => lib}/src/spi/ascii/ascii-array.ts | 0 .../src/spi/ascii/ascii-form-entry.ts | 0 .../src/spi/ascii/ascii-form-info.ts | 0 .../{lib-typescript => lib}/src/spi/ascii/ascii-form.ts | 0 .../{lib-typescript => lib}/src/spi/ascii/ascii-format.ts | 0 .../src/spi/ascii/ascii-formatter.ts | 0 .../{lib-typescript => lib}/src/spi/ascii/csv-formatter.ts | 0 .../src/spi/ascii/default-ascii-array.spec.ts | 0 .../src/spi/ascii/default-ascii-array.ts | 0 .../src/spi/ascii/default-ascii-form.spec.ts | 0 .../src/spi/ascii/default-ascii-form.ts | 0 .../src/spi/ascii/formatter-mode.ts | 0 .../src/spi/ascii/modern-formatter.ts | 0 .../src/spi/decorator/argument-processor.ts | 0 .../{lib-typescript => lib}/src/spi/decorator/message.ts | 0 .../{lib-typescript => lib}/src/spi/decorator/parameter.ts | 0 .../src/spi/docker/container-version.ts | 0 .../src/spi/docker/recipebuilder.ts | 0 .../{lib-typescript => lib}/src/spi/docker/remoteip.ts | 0 .../src/spi/docker/ssh-generator.ts | 0 .../src/spi/http/default-http-json-request.ts | 0 dockerfiles/{lib-typescript => lib}/src/spi/i18n/i18n.ts | 0 dockerfiles/{lib-typescript => lib}/src/spi/index.ts | 0 dockerfiles/{lib-typescript => lib}/src/spi/log/log.ts | 0 .../src/spi/websocket/messagebuilder.ts | 0 .../src/spi/websocket/messagebus-subscriber.ts | 0 .../src/spi/websocket/messagebus.ts | 0 .../{lib-typescript => lib}/src/spi/websocket/websocket.ts | 0 dockerfiles/{lib-typescript => lib}/src/utils/index.ts | 0 .../{lib-typescript => lib}/src/utils/product-name.ts | 0 .../{lib-typescript => lib}/src/utils/string-utils.spec.ts | 0 .../{lib-typescript => lib}/src/utils/string-utils.ts | 0 dockerfiles/{lib-typescript => lib}/src/utils/uuid.ts | 0 dockerfiles/{lib-typescript => lib}/tsconfig.json | 0 dockerfiles/test/Dockerfile | 2 +- 104 files changed, 11 insertions(+), 10 deletions(-) rename dockerfiles/{base-cli => base}/Dockerfile (100%) rename dockerfiles/{base-cli => base}/build.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/cli/cli-functions.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_action.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_backup.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_config.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_debug.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_destroy.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_download.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_help.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_info.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_init.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_network.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_offline.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_restore.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_rmi.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_ssh.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_start.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_sync.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_upgrade.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/commands/cmd_version.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/curl.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/docker.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/paths.sh (100%) rename dockerfiles/{base-cli => base}/scripts/base/startup.sh (100%) rename dockerfiles/{lib-typescript => lib}/.babelrc (100%) rename dockerfiles/{lib-typescript => lib}/.dockerignore (100%) rename dockerfiles/{lib-typescript => lib}/.gitignore (100%) rename dockerfiles/{lib-typescript => lib}/Dockerfile (88%) rename dockerfiles/{lib-typescript => lib}/Dockerfile.dev (100%) rename dockerfiles/{lib-typescript => lib}/README.md (100%) rename dockerfiles/{lib-typescript => lib}/build.sh (98%) rename dockerfiles/{lib-typescript => lib}/dto-pom.xml (100%) rename dockerfiles/{lib-typescript => lib}/package.json (92%) rename dockerfiles/{lib-typescript => lib}/runtime-dependencies/package.json (100%) rename dockerfiles/{lib-typescript => lib}/src/api/dto/che-dto.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/auth/auth-data.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/machine/machine-service-client.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/machine/process-log-output-subscriber.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/permissions/dto/domaindto.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/permissions/dto/permissiondto.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/permissions/permissions.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/project/project.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/ssh/ssh.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/user/user.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/api/wsmaster/workspace/workspace.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/index.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/che-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/impl/add-user-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/impl/create-start-workspace-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/impl/execute-command-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/impl/get-ssh-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/impl/list-workspaces-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/impl/remove-user-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/action/impl/workspace-ssh-action.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/dir/che-dir-constant.properties (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/dir/che-dir.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/dir/chefile-struct/che-file-struct.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/test/che-test.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/test/impl/post-flight-check-test.properties (100%) rename dockerfiles/{lib-typescript => lib}/src/internal/test/impl/post-flight-check-test.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/ascii-array-info.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/ascii-array.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/ascii-form-entry.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/ascii-form-info.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/ascii-form.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/ascii-format.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/ascii-formatter.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/csv-formatter.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/default-ascii-array.spec.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/default-ascii-array.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/default-ascii-form.spec.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/default-ascii-form.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/formatter-mode.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/ascii/modern-formatter.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/decorator/argument-processor.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/decorator/message.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/decorator/parameter.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/docker/container-version.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/docker/recipebuilder.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/docker/remoteip.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/docker/ssh-generator.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/http/default-http-json-request.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/i18n/i18n.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/index.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/log/log.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/websocket/messagebuilder.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/websocket/messagebus-subscriber.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/websocket/messagebus.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/spi/websocket/websocket.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/utils/index.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/utils/product-name.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/utils/string-utils.spec.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/utils/string-utils.ts (100%) rename dockerfiles/{lib-typescript => lib}/src/utils/uuid.ts (100%) rename dockerfiles/{lib-typescript => lib}/tsconfig.json (100%) diff --git a/dockerfiles/action/Dockerfile b/dockerfiles/action/Dockerfile index 712b9f1d548..fb41f7e3290 100644 --- a/dockerfiles/action/Dockerfile +++ b/dockerfiles/action/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action [command] -FROM eclipse/che-lib-typescript:nightly +FROM eclipse/che-lib:nightly ENTRYPOINT ["node", "/che-lib/index.js", "che-action"] diff --git a/dockerfiles/base-cli/Dockerfile b/dockerfiles/base/Dockerfile similarity index 100% rename from dockerfiles/base-cli/Dockerfile rename to dockerfiles/base/Dockerfile diff --git a/dockerfiles/base-cli/build.sh b/dockerfiles/base/build.sh similarity index 100% rename from dockerfiles/base-cli/build.sh rename to dockerfiles/base/build.sh diff --git a/dockerfiles/base-cli/scripts/base/cli/cli-functions.sh b/dockerfiles/base/scripts/base/cli/cli-functions.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/cli/cli-functions.sh rename to dockerfiles/base/scripts/base/cli/cli-functions.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_action.sh b/dockerfiles/base/scripts/base/commands/cmd_action.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_action.sh rename to dockerfiles/base/scripts/base/commands/cmd_action.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_backup.sh b/dockerfiles/base/scripts/base/commands/cmd_backup.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_backup.sh rename to dockerfiles/base/scripts/base/commands/cmd_backup.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_config.sh b/dockerfiles/base/scripts/base/commands/cmd_config.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_config.sh rename to dockerfiles/base/scripts/base/commands/cmd_config.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_debug.sh b/dockerfiles/base/scripts/base/commands/cmd_debug.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_debug.sh rename to dockerfiles/base/scripts/base/commands/cmd_debug.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_destroy.sh b/dockerfiles/base/scripts/base/commands/cmd_destroy.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_destroy.sh rename to dockerfiles/base/scripts/base/commands/cmd_destroy.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_download.sh b/dockerfiles/base/scripts/base/commands/cmd_download.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_download.sh rename to dockerfiles/base/scripts/base/commands/cmd_download.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_help.sh b/dockerfiles/base/scripts/base/commands/cmd_help.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_help.sh rename to dockerfiles/base/scripts/base/commands/cmd_help.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_info.sh b/dockerfiles/base/scripts/base/commands/cmd_info.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_info.sh rename to dockerfiles/base/scripts/base/commands/cmd_info.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_init.sh b/dockerfiles/base/scripts/base/commands/cmd_init.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_init.sh rename to dockerfiles/base/scripts/base/commands/cmd_init.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_network.sh b/dockerfiles/base/scripts/base/commands/cmd_network.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_network.sh rename to dockerfiles/base/scripts/base/commands/cmd_network.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_offline.sh b/dockerfiles/base/scripts/base/commands/cmd_offline.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_offline.sh rename to dockerfiles/base/scripts/base/commands/cmd_offline.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_restore.sh b/dockerfiles/base/scripts/base/commands/cmd_restore.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_restore.sh rename to dockerfiles/base/scripts/base/commands/cmd_restore.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_rmi.sh b/dockerfiles/base/scripts/base/commands/cmd_rmi.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_rmi.sh rename to dockerfiles/base/scripts/base/commands/cmd_rmi.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_ssh.sh b/dockerfiles/base/scripts/base/commands/cmd_ssh.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_ssh.sh rename to dockerfiles/base/scripts/base/commands/cmd_ssh.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_start.sh b/dockerfiles/base/scripts/base/commands/cmd_start.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_start.sh rename to dockerfiles/base/scripts/base/commands/cmd_start.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_sync.sh b/dockerfiles/base/scripts/base/commands/cmd_sync.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_sync.sh rename to dockerfiles/base/scripts/base/commands/cmd_sync.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_upgrade.sh b/dockerfiles/base/scripts/base/commands/cmd_upgrade.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_upgrade.sh rename to dockerfiles/base/scripts/base/commands/cmd_upgrade.sh diff --git a/dockerfiles/base-cli/scripts/base/commands/cmd_version.sh b/dockerfiles/base/scripts/base/commands/cmd_version.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/commands/cmd_version.sh rename to dockerfiles/base/scripts/base/commands/cmd_version.sh diff --git a/dockerfiles/base-cli/scripts/base/curl.sh b/dockerfiles/base/scripts/base/curl.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/curl.sh rename to dockerfiles/base/scripts/base/curl.sh diff --git a/dockerfiles/base-cli/scripts/base/docker.sh b/dockerfiles/base/scripts/base/docker.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/docker.sh rename to dockerfiles/base/scripts/base/docker.sh diff --git a/dockerfiles/base-cli/scripts/base/paths.sh b/dockerfiles/base/scripts/base/paths.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/paths.sh rename to dockerfiles/base/scripts/base/paths.sh diff --git a/dockerfiles/base-cli/scripts/base/startup.sh b/dockerfiles/base/scripts/base/startup.sh similarity index 100% rename from dockerfiles/base-cli/scripts/base/startup.sh rename to dockerfiles/base/scripts/base/startup.sh diff --git a/dockerfiles/build-all.sh b/dockerfiles/build-all.sh index 5dc2bea4f0a..6ae302564d0 100755 --- a/dockerfiles/build-all.sh +++ b/dockerfiles/build-all.sh @@ -13,7 +13,7 @@ set -u init # loop on all libraries first -for directory in lib-*/ ; do +for directory in lib*/ ; do if [[ -e ${directory}/build.sh ]] ; then echo "Call buid.sh from ${directory}" ${directory}build.sh "$@" diff --git a/dockerfiles/dir/Dockerfile b/dockerfiles/dir/Dockerfile index 7a1802e008e..26c1d378df4 100644 --- a/dockerfiles/dir/Dockerfile +++ b/dockerfiles/dir/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-dir [command] -FROM eclipse/che-lib-typescript:nightly +FROM eclipse/che-lib:nightly ENTRYPOINT ["node", "/che-lib/index.js", "che-dir"] diff --git a/dockerfiles/lib-typescript/.babelrc b/dockerfiles/lib/.babelrc similarity index 100% rename from dockerfiles/lib-typescript/.babelrc rename to dockerfiles/lib/.babelrc diff --git a/dockerfiles/lib-typescript/.dockerignore b/dockerfiles/lib/.dockerignore similarity index 100% rename from dockerfiles/lib-typescript/.dockerignore rename to dockerfiles/lib/.dockerignore diff --git a/dockerfiles/lib-typescript/.gitignore b/dockerfiles/lib/.gitignore similarity index 100% rename from dockerfiles/lib-typescript/.gitignore rename to dockerfiles/lib/.gitignore diff --git a/dockerfiles/lib-typescript/Dockerfile b/dockerfiles/lib/Dockerfile similarity index 88% rename from dockerfiles/lib-typescript/Dockerfile rename to dockerfiles/lib/Dockerfile index 778d7a4c7cb..dfdc03b9edb 100644 --- a/dockerfiles/lib-typescript/Dockerfile +++ b/dockerfiles/lib/Dockerfile @@ -4,9 +4,11 @@ # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html # -# Contributors: -# Codenvy, S.A. - Initial implementation +# build: +# docker build -t eclipse/che-lib . # +# use: +# docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-lib [command] FROM mhart/alpine-node:6 @@ -29,4 +31,3 @@ RUN cd /lib-typescript/ && npm install \ && cd /runtime && npm install && /lib-typescript/node_modules/.bin/tsc --project /lib-typescript/ \ && mv /lib-typescript/lib /che-lib && cd /lib-typescript/src && find . -name "*.properties" -exec install -D {} /che-lib/{} \;\ && rm -rf /lib-typescript && mv /runtime/node_modules /che-lib && rm -rf /runtime - diff --git a/dockerfiles/lib-typescript/Dockerfile.dev b/dockerfiles/lib/Dockerfile.dev similarity index 100% rename from dockerfiles/lib-typescript/Dockerfile.dev rename to dockerfiles/lib/Dockerfile.dev diff --git a/dockerfiles/lib-typescript/README.md b/dockerfiles/lib/README.md similarity index 100% rename from dockerfiles/lib-typescript/README.md rename to dockerfiles/lib/README.md diff --git a/dockerfiles/lib-typescript/build.sh b/dockerfiles/lib/build.sh similarity index 98% rename from dockerfiles/lib-typescript/build.sh rename to dockerfiles/lib/build.sh index 0a163bb5219..40720258b9f 100755 --- a/dockerfiles/lib-typescript/build.sh +++ b/dockerfiles/lib/build.sh @@ -5,7 +5,7 @@ # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html -IMAGE_NAME="eclipse/che-lib-typescript" +IMAGE_NAME="eclipse/che-lib" . $(cd "$(dirname "$0")"; pwd)/../build.include DIR=$(cd "$(dirname "$0")"; pwd) diff --git a/dockerfiles/lib-typescript/dto-pom.xml b/dockerfiles/lib/dto-pom.xml similarity index 100% rename from dockerfiles/lib-typescript/dto-pom.xml rename to dockerfiles/lib/dto-pom.xml diff --git a/dockerfiles/lib-typescript/package.json b/dockerfiles/lib/package.json similarity index 92% rename from dockerfiles/lib-typescript/package.json rename to dockerfiles/lib/package.json index 5a4bae84844..fd99805faed 100644 --- a/dockerfiles/lib-typescript/package.json +++ b/dockerfiles/lib/package.json @@ -1,7 +1,7 @@ { - "name": "che-typescript", + "name": "che-cli-library", "version": "1.0.0", - "description": "TypeScript library used in dockerfiles", + "description": "CLI library used in dockerfiles", "main": "lib/index.js", "author": "Florent Benoit", "license": "EPL-1.0", diff --git a/dockerfiles/lib-typescript/runtime-dependencies/package.json b/dockerfiles/lib/runtime-dependencies/package.json similarity index 100% rename from dockerfiles/lib-typescript/runtime-dependencies/package.json rename to dockerfiles/lib/runtime-dependencies/package.json diff --git a/dockerfiles/lib-typescript/src/api/dto/che-dto.ts b/dockerfiles/lib/src/api/dto/che-dto.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/dto/che-dto.ts rename to dockerfiles/lib/src/api/dto/che-dto.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/auth/auth-data.ts b/dockerfiles/lib/src/api/wsmaster/auth/auth-data.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/auth/auth-data.ts rename to dockerfiles/lib/src/api/wsmaster/auth/auth-data.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/machine/machine-service-client.ts b/dockerfiles/lib/src/api/wsmaster/machine/machine-service-client.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/machine/machine-service-client.ts rename to dockerfiles/lib/src/api/wsmaster/machine/machine-service-client.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-log-output-subscriber.ts b/dockerfiles/lib/src/api/wsmaster/machine/process-log-output-subscriber.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/machine/process-log-output-subscriber.ts rename to dockerfiles/lib/src/api/wsmaster/machine/process-log-output-subscriber.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts b/dockerfiles/lib/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts rename to dockerfiles/lib/src/api/wsmaster/machine/process-terminated-event-promise-subscriber.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/domaindto.ts b/dockerfiles/lib/src/api/wsmaster/permissions/dto/domaindto.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/domaindto.ts rename to dockerfiles/lib/src/api/wsmaster/permissions/dto/domaindto.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/permissiondto.ts b/dockerfiles/lib/src/api/wsmaster/permissions/dto/permissiondto.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/permissions/dto/permissiondto.ts rename to dockerfiles/lib/src/api/wsmaster/permissions/dto/permissiondto.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/permissions/permissions.ts b/dockerfiles/lib/src/api/wsmaster/permissions/permissions.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/permissions/permissions.ts rename to dockerfiles/lib/src/api/wsmaster/permissions/permissions.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/project/project.ts b/dockerfiles/lib/src/api/wsmaster/project/project.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/project/project.ts rename to dockerfiles/lib/src/api/wsmaster/project/project.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts b/dockerfiles/lib/src/api/wsmaster/ssh/ssh.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/ssh/ssh.ts rename to dockerfiles/lib/src/api/wsmaster/ssh/ssh.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/user/user.ts b/dockerfiles/lib/src/api/wsmaster/user/user.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/user/user.ts rename to dockerfiles/lib/src/api/wsmaster/user/user.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts b/dockerfiles/lib/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts rename to dockerfiles/lib/src/api/wsmaster/workspace/workspace-log-output-subscriber.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts b/dockerfiles/lib/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts rename to dockerfiles/lib/src/api/wsmaster/workspace/workspace-start-event-promise-subscriber.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts b/dockerfiles/lib/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts rename to dockerfiles/lib/src/api/wsmaster/workspace/workspace-stop-event-promise-subscriber.ts diff --git a/dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace.ts b/dockerfiles/lib/src/api/wsmaster/workspace/workspace.ts similarity index 100% rename from dockerfiles/lib-typescript/src/api/wsmaster/workspace/workspace.ts rename to dockerfiles/lib/src/api/wsmaster/workspace/workspace.ts diff --git a/dockerfiles/lib-typescript/src/index.ts b/dockerfiles/lib/src/index.ts similarity index 100% rename from dockerfiles/lib-typescript/src/index.ts rename to dockerfiles/lib/src/index.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/che-action.ts b/dockerfiles/lib/src/internal/action/che-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/che-action.ts rename to dockerfiles/lib/src/internal/action/che-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/add-user-action.ts b/dockerfiles/lib/src/internal/action/impl/add-user-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/impl/add-user-action.ts rename to dockerfiles/lib/src/internal/action/impl/add-user-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/create-start-workspace-action.ts b/dockerfiles/lib/src/internal/action/impl/create-start-workspace-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/impl/create-start-workspace-action.ts rename to dockerfiles/lib/src/internal/action/impl/create-start-workspace-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/execute-command-action.ts b/dockerfiles/lib/src/internal/action/impl/execute-command-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/impl/execute-command-action.ts rename to dockerfiles/lib/src/internal/action/impl/execute-command-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/get-ssh-action.ts b/dockerfiles/lib/src/internal/action/impl/get-ssh-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/impl/get-ssh-action.ts rename to dockerfiles/lib/src/internal/action/impl/get-ssh-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/list-workspaces-action.ts b/dockerfiles/lib/src/internal/action/impl/list-workspaces-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/impl/list-workspaces-action.ts rename to dockerfiles/lib/src/internal/action/impl/list-workspaces-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/remove-user-action.ts b/dockerfiles/lib/src/internal/action/impl/remove-user-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/impl/remove-user-action.ts rename to dockerfiles/lib/src/internal/action/impl/remove-user-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/action/impl/workspace-ssh-action.ts b/dockerfiles/lib/src/internal/action/impl/workspace-ssh-action.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/action/impl/workspace-ssh-action.ts rename to dockerfiles/lib/src/internal/action/impl/workspace-ssh-action.ts diff --git a/dockerfiles/lib-typescript/src/internal/dir/che-dir-constant.properties b/dockerfiles/lib/src/internal/dir/che-dir-constant.properties similarity index 100% rename from dockerfiles/lib-typescript/src/internal/dir/che-dir-constant.properties rename to dockerfiles/lib/src/internal/dir/che-dir-constant.properties diff --git a/dockerfiles/lib-typescript/src/internal/dir/che-dir.ts b/dockerfiles/lib/src/internal/dir/che-dir.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/dir/che-dir.ts rename to dockerfiles/lib/src/internal/dir/che-dir.ts diff --git a/dockerfiles/lib-typescript/src/internal/dir/chefile-struct/che-file-struct.ts b/dockerfiles/lib/src/internal/dir/chefile-struct/che-file-struct.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/dir/chefile-struct/che-file-struct.ts rename to dockerfiles/lib/src/internal/dir/chefile-struct/che-file-struct.ts diff --git a/dockerfiles/lib-typescript/src/internal/test/che-test.ts b/dockerfiles/lib/src/internal/test/che-test.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/test/che-test.ts rename to dockerfiles/lib/src/internal/test/che-test.ts diff --git a/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.properties b/dockerfiles/lib/src/internal/test/impl/post-flight-check-test.properties similarity index 100% rename from dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.properties rename to dockerfiles/lib/src/internal/test/impl/post-flight-check-test.properties diff --git a/dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.ts b/dockerfiles/lib/src/internal/test/impl/post-flight-check-test.ts similarity index 100% rename from dockerfiles/lib-typescript/src/internal/test/impl/post-flight-check-test.ts rename to dockerfiles/lib/src/internal/test/impl/post-flight-check-test.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-array-info.ts b/dockerfiles/lib/src/spi/ascii/ascii-array-info.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/ascii-array-info.ts rename to dockerfiles/lib/src/spi/ascii/ascii-array-info.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-array.ts b/dockerfiles/lib/src/spi/ascii/ascii-array.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/ascii-array.ts rename to dockerfiles/lib/src/spi/ascii/ascii-array.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-entry.ts b/dockerfiles/lib/src/spi/ascii/ascii-form-entry.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/ascii-form-entry.ts rename to dockerfiles/lib/src/spi/ascii/ascii-form-entry.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-form-info.ts b/dockerfiles/lib/src/spi/ascii/ascii-form-info.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/ascii-form-info.ts rename to dockerfiles/lib/src/spi/ascii/ascii-form-info.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-form.ts b/dockerfiles/lib/src/spi/ascii/ascii-form.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/ascii-form.ts rename to dockerfiles/lib/src/spi/ascii/ascii-form.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-format.ts b/dockerfiles/lib/src/spi/ascii/ascii-format.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/ascii-format.ts rename to dockerfiles/lib/src/spi/ascii/ascii-format.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/ascii-formatter.ts b/dockerfiles/lib/src/spi/ascii/ascii-formatter.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/ascii-formatter.ts rename to dockerfiles/lib/src/spi/ascii/ascii-formatter.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/csv-formatter.ts b/dockerfiles/lib/src/spi/ascii/csv-formatter.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/csv-formatter.ts rename to dockerfiles/lib/src/spi/ascii/csv-formatter.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.spec.ts b/dockerfiles/lib/src/spi/ascii/default-ascii-array.spec.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.spec.ts rename to dockerfiles/lib/src/spi/ascii/default-ascii-array.spec.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.ts b/dockerfiles/lib/src/spi/ascii/default-ascii-array.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/default-ascii-array.ts rename to dockerfiles/lib/src/spi/ascii/default-ascii-array.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.spec.ts b/dockerfiles/lib/src/spi/ascii/default-ascii-form.spec.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.spec.ts rename to dockerfiles/lib/src/spi/ascii/default-ascii-form.spec.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.ts b/dockerfiles/lib/src/spi/ascii/default-ascii-form.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/default-ascii-form.ts rename to dockerfiles/lib/src/spi/ascii/default-ascii-form.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/formatter-mode.ts b/dockerfiles/lib/src/spi/ascii/formatter-mode.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/formatter-mode.ts rename to dockerfiles/lib/src/spi/ascii/formatter-mode.ts diff --git a/dockerfiles/lib-typescript/src/spi/ascii/modern-formatter.ts b/dockerfiles/lib/src/spi/ascii/modern-formatter.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/ascii/modern-formatter.ts rename to dockerfiles/lib/src/spi/ascii/modern-formatter.ts diff --git a/dockerfiles/lib-typescript/src/spi/decorator/argument-processor.ts b/dockerfiles/lib/src/spi/decorator/argument-processor.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/decorator/argument-processor.ts rename to dockerfiles/lib/src/spi/decorator/argument-processor.ts diff --git a/dockerfiles/lib-typescript/src/spi/decorator/message.ts b/dockerfiles/lib/src/spi/decorator/message.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/decorator/message.ts rename to dockerfiles/lib/src/spi/decorator/message.ts diff --git a/dockerfiles/lib-typescript/src/spi/decorator/parameter.ts b/dockerfiles/lib/src/spi/decorator/parameter.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/decorator/parameter.ts rename to dockerfiles/lib/src/spi/decorator/parameter.ts diff --git a/dockerfiles/lib-typescript/src/spi/docker/container-version.ts b/dockerfiles/lib/src/spi/docker/container-version.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/docker/container-version.ts rename to dockerfiles/lib/src/spi/docker/container-version.ts diff --git a/dockerfiles/lib-typescript/src/spi/docker/recipebuilder.ts b/dockerfiles/lib/src/spi/docker/recipebuilder.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/docker/recipebuilder.ts rename to dockerfiles/lib/src/spi/docker/recipebuilder.ts diff --git a/dockerfiles/lib-typescript/src/spi/docker/remoteip.ts b/dockerfiles/lib/src/spi/docker/remoteip.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/docker/remoteip.ts rename to dockerfiles/lib/src/spi/docker/remoteip.ts diff --git a/dockerfiles/lib-typescript/src/spi/docker/ssh-generator.ts b/dockerfiles/lib/src/spi/docker/ssh-generator.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/docker/ssh-generator.ts rename to dockerfiles/lib/src/spi/docker/ssh-generator.ts diff --git a/dockerfiles/lib-typescript/src/spi/http/default-http-json-request.ts b/dockerfiles/lib/src/spi/http/default-http-json-request.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/http/default-http-json-request.ts rename to dockerfiles/lib/src/spi/http/default-http-json-request.ts diff --git a/dockerfiles/lib-typescript/src/spi/i18n/i18n.ts b/dockerfiles/lib/src/spi/i18n/i18n.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/i18n/i18n.ts rename to dockerfiles/lib/src/spi/i18n/i18n.ts diff --git a/dockerfiles/lib-typescript/src/spi/index.ts b/dockerfiles/lib/src/spi/index.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/index.ts rename to dockerfiles/lib/src/spi/index.ts diff --git a/dockerfiles/lib-typescript/src/spi/log/log.ts b/dockerfiles/lib/src/spi/log/log.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/log/log.ts rename to dockerfiles/lib/src/spi/log/log.ts diff --git a/dockerfiles/lib-typescript/src/spi/websocket/messagebuilder.ts b/dockerfiles/lib/src/spi/websocket/messagebuilder.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/websocket/messagebuilder.ts rename to dockerfiles/lib/src/spi/websocket/messagebuilder.ts diff --git a/dockerfiles/lib-typescript/src/spi/websocket/messagebus-subscriber.ts b/dockerfiles/lib/src/spi/websocket/messagebus-subscriber.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/websocket/messagebus-subscriber.ts rename to dockerfiles/lib/src/spi/websocket/messagebus-subscriber.ts diff --git a/dockerfiles/lib-typescript/src/spi/websocket/messagebus.ts b/dockerfiles/lib/src/spi/websocket/messagebus.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/websocket/messagebus.ts rename to dockerfiles/lib/src/spi/websocket/messagebus.ts diff --git a/dockerfiles/lib-typescript/src/spi/websocket/websocket.ts b/dockerfiles/lib/src/spi/websocket/websocket.ts similarity index 100% rename from dockerfiles/lib-typescript/src/spi/websocket/websocket.ts rename to dockerfiles/lib/src/spi/websocket/websocket.ts diff --git a/dockerfiles/lib-typescript/src/utils/index.ts b/dockerfiles/lib/src/utils/index.ts similarity index 100% rename from dockerfiles/lib-typescript/src/utils/index.ts rename to dockerfiles/lib/src/utils/index.ts diff --git a/dockerfiles/lib-typescript/src/utils/product-name.ts b/dockerfiles/lib/src/utils/product-name.ts similarity index 100% rename from dockerfiles/lib-typescript/src/utils/product-name.ts rename to dockerfiles/lib/src/utils/product-name.ts diff --git a/dockerfiles/lib-typescript/src/utils/string-utils.spec.ts b/dockerfiles/lib/src/utils/string-utils.spec.ts similarity index 100% rename from dockerfiles/lib-typescript/src/utils/string-utils.spec.ts rename to dockerfiles/lib/src/utils/string-utils.spec.ts diff --git a/dockerfiles/lib-typescript/src/utils/string-utils.ts b/dockerfiles/lib/src/utils/string-utils.ts similarity index 100% rename from dockerfiles/lib-typescript/src/utils/string-utils.ts rename to dockerfiles/lib/src/utils/string-utils.ts diff --git a/dockerfiles/lib-typescript/src/utils/uuid.ts b/dockerfiles/lib/src/utils/uuid.ts similarity index 100% rename from dockerfiles/lib-typescript/src/utils/uuid.ts rename to dockerfiles/lib/src/utils/uuid.ts diff --git a/dockerfiles/lib-typescript/tsconfig.json b/dockerfiles/lib/tsconfig.json similarity index 100% rename from dockerfiles/lib-typescript/tsconfig.json rename to dockerfiles/lib/tsconfig.json diff --git a/dockerfiles/test/Dockerfile b/dockerfiles/test/Dockerfile index 69a1f1e5fba..260b89138c8 100644 --- a/dockerfiles/test/Dockerfile +++ b/dockerfiles/test/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-test [command] -FROM eclipse/che-lib-typescript:nightly +FROM eclipse/che-lib:nightly ENTRYPOINT ["node", "/che-lib/index.js", "che-test"] From d484d4be27f8b7c2f84f6992c73cdc683db0e895 Mon Sep 17 00:00:00 2001 From: Tyler Jewell Date: Fri, 2 Dec 2016 05:49:07 -0800 Subject: [PATCH 41/74] Update che.env to reflect latest properties (#3251) * initial * docker alias * docs --- .../WEB-INF/classes/che_aliases.properties | 2 + dockerfiles/init/manifests/che.env | 267 ++++++--- docs/README.md | 525 ++++++++++++++++++ 3 files changed, 710 insertions(+), 84 deletions(-) create mode 100644 docs/README.md diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che_aliases.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che_aliases.properties index 5c4f0f6da0d..055ea34566d 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che_aliases.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che_aliases.properties @@ -58,3 +58,5 @@ che.docker.api=docker.api.version che.docker.tcp_connection_timeout_ms=docker.connection.tcp.connection_timeout_ms che.docker.tcp_connection_read_timeout_ms=docker.connection.tcp.read_timeout_ms che.docker.swap=machine.docker.memory_swap_multiplier +che.docker.daemon_url=docker.client.daemon_url + diff --git a/dockerfiles/init/manifests/che.env b/dockerfiles/init/manifests/che.env index dfcc4d7b845..bf497fa6f55 100644 --- a/dockerfiles/init/manifests/che.env +++ b/dockerfiles/init/manifests/che.env @@ -1,9 +1,9 @@ -############################################################ -##### ##### -##### CHE SYSTEM ##### -##### ##### +######################################################################################## +##### ##### +##### CHE SYSTEM ##### +##### ##### # -# Fundamental parameters that affect the initial system operation. +# Parameters that affect the initial system operation. # # IP address, hostname, or DNS @@ -23,18 +23,18 @@ # configure proxies for Che's internal system services. Third, if you want your users # to access the Internet, then you should also add proxy values for their workspaces. # -# Please be mindful of the proxy URL formatting. Proxies are unforgiving if you do not type -# the URL just right, inclduing the protocol and whether they allow a trailing /. +# Please be mindful of the proxy URL formatting. Proxies are unforgiving if you do not +# type the URL properly, including the protocol and whether they allow a trailing /. #CHE_HTTP_PROXY_FOR_CHE=http://myproxy.com:8001/ #CHE_HTTPS_PROXY_FOR_CHE=http://myproxy.com:8001/ #CHE_NO_PROXY_FOR_CHE= # Proxies for Workspaces -# The proxy values that will be set as environment variables within each user's workspace. -# Set these to allow users Internet access if they are behind a proxy. -#CHE_HTTP_PROXY_FOR_CHE_WORKSPACES=http://myproxy.com:8001/ -#CHE_HTTPS_PROXY_FOR_CHE_WORKSPACES=http://myproxy.com:8001/ -#CHE_NO_PROXY_FOR_CHE_WORKSPACES= +# The proxy values that will be set as environment variables within each user's. +# workspace. Set these to allow users Internet access if they are behind a proxy. +#CHE_WORKSPACE_HTTP__PROXY=http://myproxy.com:8001/ +#CHE_WORKSPACE_HTTPS__PROXY=http://myproxy.com:8001/ +#CHE_WORKSPACE_NO__PROXY= # JPDA # If using Che in development mode, activate this property to enable JPDA @@ -49,58 +49,58 @@ # It should be rare that you would need to change this. #CHE_SERVER_XMX=2048 -############################################################ -##### ##### -##### WORKSPACE CONFIGURATION ##### -##### ##### +######################################################################################## +##### ##### +##### WORKSPACES ##### +##### ##### # -# User workspaces have their own runtimes. Those runtimes can be composed 1..n containers. -# We call each container a 'machine' as it is a dedicated runtime. One of the machines for a -# workspace must be designated as the 'development' machine, which installs Che agents to +# User workspaces have their own runtimes. Those runtimes are composed of 1..n containers. +# We call each container a 'machine' as it is a dedicated runtime. One of the machines for +# a workspace must be designated as the 'development' machine, which installs Che agents to # provide additional services to the user. These parameters configure how Che manages user # machines and the agents that are deployed within them. # -# Since workspaces have their own runtimes, they have separate proxies that do not inherit from -# the system proxies that you have configured for your Docker daemon. +# Since workspaces have their own runtimes, they have separate proxies that do not inherit +# from system proxies that you have configured for your Docker daemon. # -# /etc/hosts for Workspaces -# This will add entries into the user's /etc/hosts file that is running within their workspace. -# You may need to configure this file to give the user access to systems within your network -# or access to the Internet. +# /etc/hosts +# This will add entries into the user's /etc/hosts file that is running within their +# workspace. You may need to configure this to give user's access to systems within +# your network or access to the Internet. #CHE_MACHINE_EXTRA_HOSTS=NULL # Idle Timeout -# The length of time that a user is idel with their workspace when the system will suspend the -# workspace by snapshotting it and then stopping it. Idleness is determined by the length of -# time that the user has not interacted with the workspace, meaning that one of our agents -# has not received instructions. Leaving a browser window open counts as idleness time. +# The system will suspend the workspace and snapshot it if the end user is idle for +# this length of time. Idleness is determined by the length of time that a user has +# not interacted with the workspace, meaning that one of our agents has not received +# instructions. Leaving a browser window open counts as idleness time. #CHE_MACHINE_WS_AGENT_INACTIVE_STOP_TIMEOUT_MS=600000 # Memory -# The recommended RAM size that users will see for their workspace when they create new -# workspaces in the user dashboard. +# The recommended RAM size for new workspaces when created from the dashboard. #CHE_MACHINE_DEFAULT_MEM_SIZE_MB=1024 # Memory Swap -# Adjust machine swap memory by multiplication current machnine memory on provided value. -# default is 0 which means disabled swap, if set multiplier value equal to 0.5 +# Adjust machine swap memory by multiplication current machnine memory on provided +# value. Default is 0 which means disabled swap, if set multiplier value equal to 0.5 # machine swap will be configured with size that equal to half of current machine memory. # It should be rare that you would configure this. See Docker memory swap online # for background. #CHE_MACHINE_DOCKER_MEMORY_SWAP_MULTIPLIER=0 # Host Volume Mounts -# Semicolon separated list of volume mounts. If this is provided, Che will volume mount -# those host folders into each workspace generated by your users. This is a way to allow -# you to provide access to network attached storage that is shared across many workspaces. -#CHE_MACHINE_SERVER_EXTRA_VOLUME=/path/on/host:/path/in/workspace:ro,Z;/path/to/host2:/path/in/workspace2:ro,Z; +# Semicolon separated list of volume mounts. Che will volume mount these host folders +# into each workspace. This is a way to allow you to provide access to NAS shared +# across many workspaces. +#CHE_WORKSPACE_VOLUME=/path/on/host:/path/in/workspace:ro,Z;/path/to/host2:/path/in/workspace2:ro,Z; # Privilged Mode -# Set to `true` if you would like user workspaces to be started with Docker's privileged mode. -# Please be careful when setting this property. This allows user workspaces to gain access to -# the underly host with root privileges. However, privileged mode is needed if users want to -# launch their own Docker containers from within their Docker-powered workspace. -#CHE_MACHINE_DOCKER_PRIVILEGE_MODE=false +# Set to `true` if you would like user workspaces to be started with Docker's +# privileged mode. Please be careful when setting this property. This allows +# user workspaces to gain access to the underly host with root privileges. +# However, privileged mode is needed if users want to launch their own Docker +# containers from within their Docker-powered workspace. +#CHE_DOCKER_PRIVILEGE__MODE=false # Agent Start Timeout # The length of time that a workspace will be allowed to boot before the system terminates the @@ -109,45 +109,137 @@ #CHE_MACHINE_WS_AGENT_MAX_START_TIME_MS=300000 -############################################################ -##### ##### -##### OAUTH CONFIGURATION ##### -##### ##### + +######################################################################################## +##### ##### +##### NETWORKING ##### +##### ##### +# +# Affects how the Che server connects to the Docker Daemon, how the Che server and +# workspaces establish connections to one another, and also how remote browser clients +# should discover and connect to workspaces. +# +# Che goes through a progression algorithm to establish the protocol, IP address and +# port to establish communications with it is booting or starting a workspace. +# +# Browser --> Che Server +# 1. Default is 'http://localhost:${SERVER_PORT}/wsmaster/api'. +# 2. Else use the value of che.api # -# You can configure a 3rd party provider's oAuth, which will be used for your users when they -# create accounts and login. There are certain services within Che, such as GitHub -# integration, where GitHub keys are required. oAuth must be configured for those services to work. +# Che Server --> Docker Daemon Progression: +# 1. Use the value of che.docker.daemon_url +# 2. Else, use the value of DOCKER_HOST system variable +# 3. Else, use Unix socket over unix:///var/run/docker.sock # -# Google -#CHE_GOOGLE_CLIENT_ID=your_google_client_id -#CHE_GOOGLE_SECRET=your_google_secret +# Che Server --> Workspace Connection: +# Browser --> Workspace Connection: +# 1. Use the value of che.docker.ip +# 2. Else, if server connects over Unix socket, then use localhost +# 3. Else, use DOCKER_HOST +# +# Workspace Agent --> Che Server +# 1. Default is http://che-host:${SERVER_PORT}/wsmaster/api, where che-host is IP of server. +# 2. Else, use value of che.workspace.che_server_endpoint +# 3. Else, if 'docker0' interface is unreachable, then che-host replaced with +# 172.17.42.1 or 192.168.99.1 +# 4. Else, print connection exception -# GitHub -#CHE_GITHUB_CLIENT_ID=your_github_client_ide -#CHE_GITHUB_SECRET=your_google_secret -# BitBucket -#CHE_BITBUCKET_CLIENT_ID=your_bitbucket_client_ide -#CHE_BITBUCKET_SECRET=your_bitbucket_secret +######################################################################################## +##### ##### +##### DOCKER ##### +##### ##### +# +# IP Address +# The IP address of the Docker daemon that is running on your host. We do a +# self-discovery to auto-set this. You can combine this with DOCKER_HOST to change +# communications from socket to TCP. This value will be set to DOCKER_MACHINE_HOST +# env variable for the Che Docker container when it boots - it's how we determine +# what containers will boot. +#CHE_DOCKER_IP=172.17.0.1 + +# External Host Name +# The hostname that a browser should use to connect to a workspace container. +# Only set this if your workspace containers are not directly pingable. This is unusual, +# but happens for example in Docker for Mac when containers are in a VM. +#CHE_DOCKER_IP_EXTERNAL=NULL + +# Docker Host +# How Che will connect to the Docker Host. +#DOCKER_HOST=tcp://localhost:2375 + +# Docker Registry +# Docker is the default machine implementation within Che. Workspaces are powered +# by machines that are constructed when the workspace is started. The images used to +# generate containers for the machines can come from DockerHub or a private +# Docker registry. +# +# You can have an internal registry configured for Che to store images: +#CHE_DOCKER_REGISTRY=${CHE_REGISTRY_HOST}:5000 +# +# You can configure 1..n private registries for Che to connect to when searching +# for Docker images to be used for your workspaces. +#CHE_DOCKER_REGISTRY_AUTH__URL=https://index.docker.io/v1/ +#CHE_DOCKER_REGISTRY_AUTH__USERNAME= +#CHE_DOCKER_REGISTRY_AUTH__URL=https://index.docker.io/v1/ + +# Use Registry For Snapshots? +# Use a Docker registry for workspace snapshots. If false, snaps are saved to disk. +# The namespace is how the snapshots will be organized in the registry. +#CHE_DOCKER_REGISTRY__FOR__SNAPSHOTS=false +#CHE_DOCKER_NAMESPACE=NULL -# Microsoft -#CHE_MICROSOFT_CLIENT_ID==your_microsoft_client_ide -#CHE_MICROSOFT_SECRET=your_microsoft_secret +# Force Image Update +# If true, then Che always pulls an image from a registry even if it is cached +# If false, Docker only pulls the image if it does not exist locally. This can +# create situations where images are not current, but a forced pull is slower. +#CHE_DOCKER_ALWAYS__PULL__IMAGE=true -# WSO2 -#CHE_WSO2_CLIENT_ID=your_wso2_client_ide -#CHE_WSO2_SECRET=your_wso2_secret +# Control User Processes +# Limits the number of processes that can be forked inside a cgroup. Set -1 for +# unlimited. Requires Docker running on a 4.3 Linux kernel. +#CHE_DOCKER_PIDS__LIMIT=-1 -# Project Locker -#CHE_PROJECTLOCKER_CLIENT_ID=your_projectlocker_client_ide -#CHE_PROJECTLOCKER_SECRET=your_projectlocker_secret +# SELinux Options +# By default, your source code is mounted into a workspace into /projects folder. +# On SELinux and other OS, you may need to add additional mounting attributes. +#CHE_DOCKER_VOLUMES__PROJECTS__OPTIONS=Z +#CHE_DOCKER_VOLUMES__AGENT__OPTIONS=ro,Z +# Docker Network +# Provides a Docker network for the Che server and workspaces to use together. +# Workspace containers created by Che will be added to this Docker network. +# Communications between the Che server and container occur over this network. +#CHE_DOCKER_NETWORK=NULL +# Docker Cleanup +# Unused containers from Che and workspaces need to be cleaned up periodically. +#CHE_DOCKER_UNUSED__CONTAINERS__CLEANUP__MIN=60 -############################################################ -##### ##### -##### JMX ##### -##### ##### + + + +######################################################################################## +##### ##### +##### OAUTH ##### +##### ##### +# +# You can configure a 3rd party provider's oAuth, which will be used for your users when +# they initiate Git actions from within Che. +# +# GitHub +#CHE_OAUTH_GITHUB_CLIENTID=your_github_client_ide +#CHE_OAUTH_GITHUB_CLIENTSECRET=your_google_secret +#CHE_OAUTH_GITHUB_AUTHURI=https://github.com/login/oauth/authorize +#CHE_OAUTH_GITHUB_TOKENURI=https://github.com/login/oauth/access_token +#CHE_OAUTH_GITHUB_REDIRECTURIS=http://localhost:${SERVER_PORT}/wsmaster/api/oauth/callback + + + +######################################################################################## +##### ##### +##### JMX ##### +##### ##### # # JMX provides a management interface point to within the Che container. JMX is not # use by other containers such as haproxy or nginx. While Che is running, grab the @@ -157,17 +249,24 @@ #CHE_JMX_PASSWORD=Che -############################################################ -##### ##### -##### DOCKER ##### -##### ##### -# IP Address -# The IP address of the Docker daemon that is running on your host. We do a self-discovery -# to set this. You can combine this with values of DOCKER_HOST to change communications -# from socket to TCP. This value will be set to DOCKER_MACHINE_HOST env variable for -# the Che Docker container when it boots - it's how we determine what containers will boot. -#CHE_DOCKER_IP=172.17.0.1 +######################################################################################## +##### ##### +##### CUSTOM ##### +##### ##### +# Custom che.properties Property +# Che's server loads name=value properties in a .properties file. Those values can +# be seen by custom extensions that are packaged within a Che server. There are +# also Che properties that are rarely configured that are shown in documentation +# that can be added with a custom format here. You can add as many as you would like. +# +# Add a new property in the format of CHE_=value. If in your +# you have a single underscore '_', that will be replaced with a +# dot '.'. A double underscore '__' will be replaced with a single underscore '_'. +# +# For example, CHE_WORKSPACE_AUTO__SNAPSHOT=false will be converted into the Che +# property 'che.workspace.auto_snapshot=false'. +#CHE_WORKSPACE_AUTO__SNAPSHOT=false -# Docker Host -# How Che will connect to the Docker Host. -#DOCKER_HOST=tcp://localhost:2375 \ No newline at end of file +# A complete list of internal properties used by Che are available in the default +# properties file that is embedded in the server's runtime. You can view it in our +# GitHub repository: https://github.com/eclipse/che/blob/master/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..f30166e8256 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,525 @@ +# Eclipse Che Installation and Operation +Eclipse Che is an Eclipse next-generation IDE, developer workspace server, and cloud IDE. + +### Quick Start +With Docker 1.11+ on Windows, Mac, or Linux: +``` +$ docker run eclipse/che-cli start +``` +This command will give you additional instructions on how to run the Che CLI while setting your hostname, configuring volume mounts, and testing your Docker setup. + +### TOC +- [Beta](#beta) +- [Getting Help](#getting-help) +- [Getting Started](#getting-started) +- [System Requirements](#system-requirements) + + [Hardware](#hardware) + + [Software](#software) + + [Sizing](#sizing) +- [Installation](#installation) + + [Linux:](#linux) + + [Mac:](#mac) + + [Windows:](#windows) + + [Verification:](#verification) + + [Proxies](#proxies) + + [Offline Installation](#offline-installation) +- [Usage](#usage) + + [Hosting](#hosting) +- [Uninstall](#uninstall) +- [Configuration](#configuration) + + [Saving Configuration in Version Control](#saving-configuration-in-version-control) + + [Logs and User Data](#logs-and-user-data) + [oAuth](#oauth) + + [LDAP](#ldap) + + [Development Mode](#development-mode) + + [Licensing](#licensing) + + [Hostname](#hostname) + + [HTTP/S](#https) + + [SMTP](#smtp) + + [Workspace Limits](#workspace-limits) + + [Private Docker Registries](#private-docker-registries) +- [Managing](#managing) + + [Scaling](#scaling) + + [Upgrading](#upgrading) + + [Backup (Backup)](#backup-backup) + + [Migration](#migration) + + [Disaster Recovery](#disaster-recovery) +- [CLI Reference](#cli-reference) +- [Architecture](#architecture) +- [Team](#team) + +## Getting Help +If you require immediate help, [Che](http://che.com) provides email and phone support options for Eclipse Che. + +If you run into an issue, please [open a GitHub issue](http://github.com/eclipse/che/issues) providing: +- the host distribution and release version +- output of the `docker version` command +- output of the `docker info` command +- the full Docker run syntax you used for the `che-cli ` +- the output of `cli.log` - see [CLI Reference](#cli-reference) + +## System Requirements +Eclipse Che installs on Linux, Mac and Windows. + +#### Hardware +* 1 core +* 2GB RAM +* 200MB disk space + +Eclipse Che requires 200 MB storage and 1 GB RAM for internal services. The RAM, CPU and storage resources required for your users' workspaces are additive. Che's Docker images consume ~900MB of disk and the Docker images for your workspace templates can each range from 5MB up to 1.5GB. Che and its dependent core containers will consume about 500MB of RAM, and your running workspaces will each require at least 250MB RAM, depending upon user requirements and complexity of the workspace code and intellisense. + +Boot2Docker, docker-machine, Docker for Windows, and Docker for Mac are variations that launch VMs with Docker running in the VM with access to Docker from your host. We recommend increasing your default VM size to at least 4GB. Each of these technologies have different ways to allow host folder mounting into the VM. Please enable this for your OS so that Che data is persisted on your host disk. + +#### Software +* Docker 11.1+ + +The Eclipse Che CLI - a Docker image - manages the other Docker images and supporting utilities that Che uses during its configuration or operations phases. The CLI also provides utilities for downloading an offline bundle to run Che while disconnected from the network. + +Given the nature of the development and release cycle it is important that you have the latest version of Docker installed because any issue that you encounter might have already been fixed with a newer docker release. + +Install the most recent version of Docker Engine for your platform using the [official Docker releases](http://docs.docker.com/engine/installation/), including support for Mac and Windows! If you are on Linux, you can also install using: +```bash +wget -qO- https://get.docker.com/ | sh +``` + +#### Sizing +Che's core services and workspaces run on a common, but single node. + +You need to have enough RAM to support the number of concurrent *running* workspaces. A single user may have multiple running workspaces, but generally the common scenario is a user running a single workspace at a time. Workspace sizes are set by users when they create new workspaces, but you can define workspace limits in the configuration file that prevent RAM sprawl. + +For sizing, determine how much RAM you want each user to consume at a time, and then estimate the peak concurrent utilization to determine how much system-wide RAM you will want. For example, internally at Che, we regularly have 75 concurrently running workspaces, each sized at 16 GB RAM, for a total expectation of 1.2TB of RAM. If you are unable to purchase a single server that supports the maximum RAM that you require, you can consider upgrading to Che, which is an Eclipse Che implementation that supports multiple physical nodes with distributed workspaces. + +Compilation is CPU-heavy and most compilation events are queued to a single CPU. You can assume that the number of cores available to the node that is running Che will determine the maximum amount of parallel compilation activities that occur. + +The default configuration of workspaces is to auto-snapshot the workspace runtime to disk whenever it is stopped, whether by the user or through idle timeout. Many stack base images can grow to be >1GB, especially if you are installing complicated software inside of them, and thus their snapshots can be sizable as well. If you allow users to have many workspaces, even if they are stopped, each of those workspaces will have a snapshot on disk. Che's implementation of Eclipse Che provides system admin limits to cap workspaces, workspaces per user, and RAM for running workspaces. + +## Installation +The Che CLI (a Docker image) is downloaded when you first execute `docker run eclipse/che-cli:` command. The CLI downloads other images that run Eclipse Che and its supporting utilities. The CLI also provides utilities for downloading an offline bundle to run Che while disconnected from a network. + +#### Nightly and Latest +Each version of Che is available as a Docker image tagged with a label that matches the version, such as `eclipse/che-cli:5.0.0-M7`. You can see all versions available by running `docker run eclipse/che-cli version` or by [browsing DockerHub](https://hub.docker.com/r/eclipse/che-cli/tags/). + +We maintain "redirection" labels which reference special versions: + +| Variable | Description | +|----------|-------------| +| `latest` | The most recent stable release. | +| `5.0.0-latest` | The most recent stable release on the 5.x branch. | +| `nightly` | The nightly build. | + +The software referenced by these labels can change over time. Since Docker will cache images locally, the `eclipse/che-cli:` image that you are running locally may not be current with the one cached on DockerHub. Additionally, the `eclipse/che-cli:` image that you are running references a manifest of Docker images that Che depends upon, which can also change if you are using these special redirection tags. + +In the case of 'latest' images, when you initialize an installation using the CLI, we encode your `/instance/che.ver` file with the numbered version that latest references. If you begin using a CLI version that mismatches what was installed, you will be presented with an error. + +To avoid issues that can appear from using 'nightly' or 'latest' redirections, you may: +1. Verify that you have the most recent version with `docker pull eclipse/che-cli:`. +2. When running the CLI, commands that use other Docker images have an optional `--pull` and `--force` command line option which will instruct the CLI to check DockerHub for a newer version and pull it down. Using these flags will slow boot up performance, but ensures that your local cache is current. + +If you are running Che using a tagged version that is a not a redirection label, such as `5.0.0-M7`, then these caching issues will not happen, as the software installed is tagged and specific to that particular version, never changing over time. + +#### Linux: +There is nothing additional you need to install other than Docker. + +#### Mac: +There is nothing additional you need to install other than Docker. + +#### Windows: +There is nothing additional you need to install other than Docker. + +#### Verification: +You can verify that the CLI is working: +``` +docker run eclipse/che-cli +``` +The CLI is bound inside of Docker images that are tagged with different versions. If you were to run `eclipse/che-cli:5.0.0-latest` this will run the latest shipping release of Che and the CLI. This list of all versions available can be seen by running `che-cli version` or browsing the list of [tags available in Docker Hub](https://hub.docker.com/r/eclipse/che-cli/tags/). + +#### Proxies +You can install and operate behind a proxy. There are three parts to configure: +1. Configuring Docker proxy access so that Che can download its images from DockerHub. +2. Configuring Che's system containers so that they can proxy to the Internet. +3. Optionally, configuring workspace proxy settings to allow users within a workspace to proxy to the Internet. + +Before starting Che, configure [Docker's daemon for proxy access](https://docs.docker.com/engine/admin/systemd/#/http-proxy). + +Che's system runs on Java, and the JVM requires proxy environment variables in our `JAVA_OPTS`. We use the JVM for the core Che server and the workspace agents that run within each workspace. TODO: HOW DO YOU CONFIGURE THIS? Please be mindful of the proxy URL formatting. Proxies are unforgiving if do not enter the URL perfectly, inclduing the protocol, port and whether they allow a trailing slash/. + +If you would like your users to have proxified access to the Internet from within their workspace, those workspace runtimes need to have proxy settings applied to their environment variables in their .bashrc or equivalent. TODO: HOW DO YOU CONFIGURE THIS? + +A `NO_PROXY` variable is required if you use a fake local DNS. Java and other internal utilities will avoid accessing a proxy for internal communications when this value is set. + +#### Offline Installation +We support the ability to install and run while disconnected from the Internet. This is helpful for certain restricted environments, regulated datacenters, or offshore installations. + +##### Save Docker Images +While connected to the Internet, download Che's Docker images: +``` +docker run eclipse/che-cli offline +``` +The CLI will download images and save them to `/che/backup/*.tar` with each image saved as its own file. The `/backup` folder will be created as a subdirectory of the folder you volume mounted to `:/che`. You can optionally save these files to a differnet location by volume mounting that folder to `:/backup`. The version tag of the CLI Docker image will be used to determine which versions of dependent images to download. There is about 1GB of data that will be saved. + +##### Save Che CLI +``` +docker save eclipse/che-cli: +``` + +##### Save Che Stacks +Out of the box, Che has configured a few dozen stacks for popular programming languages and frameworks. These stacks use "recipes" which contain links to Docker images that are needed to create workspaces from these stacks. These workspace runtime images are not saved as part of `che-cli offline`. There are many of these images and they consume a lot of disk space. Most users do not require all of these stacks and most replace default stacks with custom stacks using their own Docker images. If you'd like to get the images that are associated with Che's stacks: +``` +docker save > backup/.tar +``` +The list of stack images that you can download are sourced from Eclipse Che's [Dockerfiles repository](https://github.com/eclipse/che-dockerfiles/tree/master/recipes). Each folder is named the same way that our images are stored. The `alpine_jdk8` folder represents the `eclipse/alpine_jdk8` Docker image, which you would save with `docker save eclipse/alpine_jdk8 > backup/alpine_jdk8.tar`. + +##### Start Offline +Extract your files to an offline computer with Docker already configured. Install the CLI files to a directory on your path and ensure that they have execution permissions. Execute the CLI in the directory that has the `offline` sub-folder which contains your tar files. Then start Che in `--offline` mode: +``` +docker run eclipse/che-cli: start --offline +``` +When invoked with the `--offline` parameter, the CLI performs a preboot sequence, which loads all saved `backup/*.tar` images including any stack images you saved. The preboot sequence takes place before any CLI configuration, which itself depends upon Docker. The `che-cli start`, `che-cli download`, and `che-cli init` commands support `--offline` mode which triggers this preboot seequence. + +## Usage +#### Syntax +``` +Usage: docker run -it --rm + -v /var/run/docker.sock:/var/run/docker.sock + -v :/che + ${CHE_MINI_PRODUCT_NAME}/che-cli: [COMMAND] + + help This message + version Installed version and upgrade paths + init Initializes a directory with a ${CHE_MINI_PRODUCT_NAME} install + [--no-force Default - uses cached local Docker images + --pull Checks for newer images from DockerHub + --force Removes all images and re-pulls all images from DockerHub + --offline Uses images saved to disk from the offline command + --accept-license Auto accepts the Che license during installation + --reinit] Reinstalls using existing $CHE_MINI_PRODUCT_NAME.env configuration + start [--pull | --force | --offline] Starts ${CHE_MINI_PRODUCT_NAME} services + stop Stops ${CHE_MINI_PRODUCT_NAME} services + restart [--pull | --force] Restart ${CHE_MINI_PRODUCT_NAME} services + destroy Stops services, and deletes ${CHE_MINI_PRODUCT_NAME} instance data + [--quiet Does not ask for confirmation before destroying instance data + --cli] If :/cli is mounted, will destroy the cli.log + rmi [--quiet] Removes the Docker images for , forcing a repull + config Generates a ${CHE_MINI_PRODUCT_NAME} config from vars; run on any start / restart + add-node Adds a physical node to serve workspaces intto the ${CHE_MINI_PRODUCT_NAME} cluster + remove-node Removes the physical node from the ${CHE_MINI_PRODUCT_NAME} cluster + upgrade Upgrades Che from one version to another with migrations and backups + download [--pull|--force|--offline] Pulls Docker images for the current che-cli version + backup [--quiet | --skip-data] Backups ${CHE_MINI_PRODUCT_NAME} configuration and data to /che/backup volume mount + restore [--quiet] Restores ${CHE_MINI_PRODUCT_NAME} configuration and data from /che/backup mount + offline Saves ${CHE_MINI_PRODUCT_NAME} Docker images into TAR files for offline install + info Displays info about ${CHE_MINI_PRODUCT_NAME} and the CLI + [ --all Run all debugging tests + --debug Displays system information + --network] Test connectivity between ${CHE_MINI_PRODUCT_NAME} sub-systems + ssh [machine-name] SSH to a workspace if SSH agent enabled + mount Synchronize workspace with current working directory + action [--help] Start action on ${CHE_MINI_PRODUCT_NAME} instance + compile SDK - Builds Che source code or modules + test [--help] Start test on ${CHE_MINI_PRODUCT_NAME} instance + +Variables: + CHE_HOST IP address or hostname where ${CHE_MINI_PRODUCT_NAME} will serve its users + CLI_DEBUG Default=false.Prints stack trace during execution + CLI_INFO Default=true. Prints out INFO messages to standard out + CLI_WARN Default=true. Prints WARN messages to standard out + CLI_LOG Default=true. Prints messages to cli.log file +``` + +In these docs, when you see `che-cli [COMMAND]`, it is assumed that you run the CLI with the full `docker run ...` syntax. We short hand the docs for readability. + +#### Sample Start +For example, to start the nightly build of Che with its data saved on Windows in `C:\tmp`: +`docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -v /c/tmp:/che eclipse/che-cli:5.0.0-latest start` + +This installs a configuration, downloads Che's Docker images, run pre-flight port checks, boot Che's services, and run post-flight checks. You do not need root access to start Che, unless your environment requires it for Docker operations. + +A successful start will display: +``` +INFO: (che cli): Downloading cli-latest +INFO: (che cli): Checking registry for version 'nightly' images +INFO: (che-cli config): Generating che-cli configuration... +INFO: (che-cli config): Customizing docker-compose for Windows +INFO: (che-cli start): Preflight checks + port 8080: [OK] + +INFO: (che-cli start): Starting containers... +INFO: (che-cli start): Server logs at "docker logs -f che_che_1" +INFO: (che-cli start): Server booting... +INFO: (che-cli start): Booted and reachable +INFO: (che-cli start): Ver: 5.0.0-M8-SNAPSHOT +INFO: (che-cli start): Use: http://10.0.75.2 +INFO: (che-cli start): API: http://10.0.75.2/swagger +``` + +#### Versions +While we provide `nightly`, `latest`, and `5.0.0-latest` [redirection versions](#nightly-and-latest) which are tags that simplify helping you retrieve a certain build, you should always run Cche with a specific version label to avoid [redirection caching issues](#nightly-and-latest). So, running `docker run eclipse/che-cli` is great syntax for testing and getting started quickly, you should always run `docker run eclipse/che-cli:` for production usage. + +#### Volume Mounts +If you volume mount a single local folder to `:/che`, then Che creates `/che/che.env` (configuration file), `/che/instance` (user data, projects, runtime logs, and database folder), and `/che/backup` (data backup folder). + +However, if you do not want your `/instance`, and `/backup` folder to all be children of the same parent folder, you can set them individually with separate overrides. + +``` +docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock + -v :/che + -v :/che/instance + -v :/che/backup + eclipse/che-cli: [COMMAND] + +``` + +#### Hosting +If you are hosting Che at a cloud service like DigitalOcean, set `CHE_HOST` to the server's IP address or its DNS. We use an internal utility, `eclipse/che-ip`, to determine the default value for `CHE_HOST`, which is your server's IP address. This works well on desktops, but usually fails on hosted servers requiring you to explicitly set this value. + +``` +docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock + -v :/che + -e CHE_HOST= + eclipse/che-cli: [COMMAND] +``` + +## Uninstall +``` +# Remove your che-cli configuration and destroy user projects and database +docker run eclipse/che-cli destroy + +# Deletes Che's images from your Docker registry +docker run eclipse/che-cli rmi +``` + +## Configuration +Configuration is done with environment variables in `che.env` placed into the root of the folder you volume mounted to `:/che`. Environment variables are stored in `che.env`, a file that is generated during the `che-cli init` phase. If you rerun `che-cli init` in an already initialized folder, the process will abort unless you pass `--force`, `--pull`, or `--reinit`. + +Each variable is documented with an explanation and usually commented out. If you need to set a variable, uncomment it and configure it with your value. You can then run `che-cli config` to apply this configuration to your system. `che-cli start` also reapplies the latest configuration. + +You can run `che-cli init` to install a new configuration into an empty directory. This command uses the `che-cli/init:` Docker container to deliver a version-specific set of puppet templates into the folder. + +If you run `che-cli config`, Che runs puppet to transform your puppet templates into a Che instance configuration, placing the results into `/che/instance` if you volume mounted that, or into a `instance` subdirectory of the path you mounted to `/che`. Each time you start Che, `che-cli config` is run to ensure instance configuration files are properly generated and consistent with the configuration you have specified in `che.env`. + +#### Saving Configuration in Version Control +Administration teams that want to version control your che-cli configuration should save `che.env`. This is the only file that should be saved with version control. It is not necessary, and even discouraged, to save the other files. If you were to perform a `che-cli upgrade` we may replace these files with templates that are specific to the version that is being upgraded. The `che.env` file maintains fidelity between versions and we can generate instance configurations from that. + +The version control sequence would be: +1. `che-cli init` to get an initial configuration for a particular version. +2. Edit `che.env` with your environment-specific configuration. +3. Save `che.env` to version control. +4. When pulling from version control, copy `che.env` into the root of the folder you volume mount to `:/che`. +5. You can then run `che-cli config` or `che-cli start` and the instance configuration will be generated from this file. + +#### Logs and User Data +When Che initializes itself, it stores logs, user data, database data, and instance-specific configuration in the folder mounted to `/che/instance` or an `instance` subfolder of what you mounted to `/che`. + +Che's containers save their logs in the same location: +``` +/logs/che/2016 # Server logs +/logs/che/che-machine-logs # Workspace logs +``` + +User data is stored in: +``` +/data/che # Project backups (we synchronize projs from remote ws here) +/data/registry # Workspace snapshots +``` + +Instance configuration is generated by Che and is updated by our internal configuration utilities. These 'generated' configuration files should not be modified and stored in: +``` +/instance/che.ver # Version of Che installed +/instance/docker-compose-container.yml # Docker compose to launch internal services +/instance/docker-compose.yml # Docker compose to launch Che from the host without contianer +/instance/config # Configuration files which are input mounted into the containers +``` + +#### oAuth +TODO: ADD in CHE OAUTH + +#### Development Mode +For Che developers that are building and customizing Che from its source repository, you can run Che in development mode where your local assembly is used instead of the one that is provided in the default containers downloaded from DockerHub. This allows for a rapid edit / build / run cycle. + +Dev mode is activated by volume mounting the Che git repository to `:/repo` in your Docker run command. +``` +docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock \ + -v :/che \ + -v :/repo \ + eclipse/che-cli: [COMMAND] +``` +Dev mode will use files from your host repository in three ways: + +1. During the `che-cli config` phase, the source repository's `/dockerfiles/init/modules` and `/dockerfiles/init/manifests` will be used instead of the ones that are included in the `eclipse/che-init` container. +2. During the CLI bootstrap phase, the source repository's `/dockerfiles/cli/cli.sh` file will be used instead of the one within the `eclipse/che-cli` container. This allows CLI developers to iterate without having to rebuild `eclipse/che-cli` container after each change. +3. During the `che-cli start` phase, a local assembly from `assembly/assembly-main/target/eclipse-che-*` is mounted into the `eclipse/che-server` runtime container. You must `mvn clean install` the `assembly/assembly-main/` folder prior to activating development mode. + +To activate jpda suspend mode for debugging Che server initialization, in the `che.env`: +``` +CHE_DEBUG_SUSPEND=true +``` +To change the Che debug port, in the `che.env`: +``` +CHE_DEBUG_PORT=8000 +``` + +#### Licensing +Eclipse Che is open sourced under the Eclipse Public License. + +#### Hostname +The IP address or DNS name of where the Che endpoint will service your users. If you are running this on a local system, we auto-detect this value as the IP address of your Docker daemon. On many systems, especially those from cloud hosters like DigitalOcean, you may have to explicitly set this to the external IP address or DNS entry provided by the provider. You can pass it during initialization to the docker command: + +``` +docker run -e CHE_HOST= eclipse/che-cli: start +``` + +#### HTTP/S +TODO: GET CONFIRMATION + + +#### Workspace Limits +TODO: REVIEW LIST OF LIMITS + +#### Private Docker Registries +Some enterprises use a trusted Docker registry to store their Docker images. If you want your workspace stacks and machines to be powered by these images, then you need to configure each registry and the credentialed access. Once these registries are configured, then you can have users or team leaders create stacks that use recipes with Dockerfiles or images using the `FROM /` syntax. + +There are different configurations for AWS EC2 and the Docker regsitry. You can define as many different registries as you'd like, using the numerical indicator in the environment variable. In case of adding several registries just copy set of properties and append `REGISTRY[n]` for each variable. + +In `che.env` file: +``` +Che_DOCKER_REGISTRY_AUTH_REGISTRY1_URL=url1 +Che_DOCKER_REGISTRY_AUTH_REGISTRY1_USERNAME=username1 +Che_DOCKER_REGISTRY_AUTH_REGISTRY1_PASSWORD=password1 + +Che_DOCKER_REGISTRY_AWS_REGISTRY1_ID=id1 +Che_DOCKER_REGISTRY_AWS_REGISTRY1_REGION=region1 +Che_DOCKER_REGISTRY_AWS_REGISTRY1_ACCESS__KEY__ID=key_id1 +Che_DOCKER_REGISTRY_AWS_REGISTRY1_SECRET__ACCESS__KEY=secret1 +``` + +## Managing + +#### Scaling +You can resize the physical node that you are running Che without disruptings its services. You can also consider running a Che farm of multiple Che servers with a load balancer or proxy in front, though this does require manual configuration. You can see GitHub issues of users in our GitHub history that have set this up. + +You can also consider using Codenvy, which has an embedded system for adding and removing additional physical nodes to provide additional resources for scaling workspaces. + +#### Upgrading +Upgrading Che is done by downloading a `eclipse/che-cli:` that is newer than the version you currently have installed. For example, if you have 5.0.0-M2 installed and want to upgrade to 5.0.0-M7, then: +``` +# Get the new version of Che +docker pull eclipse/che-cli:5.0.0-M7 + +# You now have two eclipse/che-cli images (one for each version) +# Perform an upgrade - use the new image to upgrade old installation +docker run eclipse/che-cli:5.0.0-M7 upgrade +``` + +The upgrade command has numerous checks to prevent you from upgrading Che if the new image and the old version are not compatible. In order for the upgrade procedure to advance, the CLI image must be newer that the version in `/instance/che.ver`. + +The upgrade process: a) performs a version compatibility check, b) downloads new Docker images that are needed to run the new version of Che, c) stops Che if it is currently running triggering a maintenance window, d) backs up your installation, e) initializes the new version, and f) starts Che. + +You can run `che-cli version` to see the list of available versions that you can upgrade to. + +#### Backup +You can run `che-cli backup` to create a copy of the relevant configuration information, user data, projects, and workspaces. We do not save workspace snapshots as part of a routine backup exercise. You can run `che-cli restore` to recover Che from a particular backup snapshot. The backup is saved as a TAR file that you can keep in your records. + +#### Migration +We currently do not support migrating from the puppet-based configuration of Che to the Dockerized version. We do have a manual process which can be followed to move data between the puppet and Dockerized versions. The versions must be identical. Contact us to let our support team perform this migration for you. + +#### Disaster Recovery +We maintain a disaster recovery [policy and best practices](http://che.readme.io/v5.0/docs/disaster-recovery). + +## CLI Reference +The CLI is configured to hide most error conditions from the output screen. The CLI prints internal stack traces and error output to `cli.log`. To see the output of this log, you will need to volume mount a local path to `:/cli`. For example: + +``` +docker run --rm -it + -v /var/run/docker.sock:/var/run/docker.sock + -v /c/che:/che + -v /c/eclipse/che-cli:/cli eclipse/che-cli:nightly [COMMAND] +``` + +### `che-cli init` +Initializes an empty directory with a Che configuration and instance folder where user data and runtime configuration will be stored. You must provide a `:/che` volume mount, then Che creates an `instance` and `backup` subfolder of ``. You can optionally override the location of `instance` by volume mounting an additional local folder to `:/che/instance`. You can optionally override the location of where backups are stored by volume mounting an additional local folder to `:/che/backup`. After initialization, a `che.env` file is placed into the root of the path that you mounted to `:/che`. + +These variables can be set in your local environment shell before running and they will be respected during initialization: + +| Variable | Description | +|----------|-------------| +| `CHE_HOST` | The IP address or DNS name of the Che service. We use `eclipse/che-ip` to attempt discovery if not set. | + +Che depends upon Docker images. We use Docker images in three ways: +1. As cross-platform utilites within the CLI. For example, in scenarios where we need to perform a `curl` operation, we use a small Docker image to perform this function. We do this as a precaution as many operating systems (like Windows) do not have curl installed. +2. To perform initialization and configuration of Che such as with `eclipse/che-init`. This image contains templates that are delivered as a payload and installed onto your computer. These payload images have different files based upon the image's version. +4. To run the Che server. + +You can control the nature of how che-cli downloads these images with command line options. All image downloads are performed with `docker pull`. + +| Mode>>>> | Description | +|------|-------------| +| `--no-force` | Default behavior. Will download an image if not found locally. A local check of the image will see if an image of a matching name is in your local registry and then skip the pull if it is found. This mode does not check DockerHub for a newer version of the same image. | +| `--pull` | Will always perform a `docker pull` when an image is requested. If there is a newer version of the same tagged image at DockerHub, it will pull it, or use the one in local cache. This keeps your images up to date, but execution is slower. | +| `--force` | Performs a forced removal of the local image using `docker rmi` and then pulls it again (anew) from DockerHub. You can use this as a way to clean your local cache and ensure that all images are new. | +| `--offline` | Loads Docker images from `backup/*.tar` folder during a pre-boot mode of the CLI. Used if you are performing an installation or start while disconnected from the Internet. | + +You can reinstall Che on a folder that is already initialized and preserve your `/che/che.env` values by passing the `--reinit` flag. + +### `che-cli config` +Generates a Che instance configuration thta is placed in `/che/instance`. This command uses puppet to generate configuration files for the Che server and Docker swarm This command is executed on every `start` or `restart`. + +If you are using a `eclipse/che-cli:` image and it does not match the version that is in `/instance/che.ver`, then the configuration will abort to prevent you from running a configuration for a different version than what is currently installed. + +This command respects `--no-force`, `--pull`, `--force`, and `--offline`. + +### `che-cli start` +Starts Che and its services using `docker-compose`. If the system cannot find a valid configuration it will perform a `che-cli init`. Every `start` and `restart` will run a `che-cli config` to generate a new configuration set using the latest configuration. The starting sequence will perform pre-flight testing to see if any ports required by Che are currently used by other services and post-flight checks to verify access to key APIs. + +### `che-cli stop` +Stops all of the Che service containers and removes them. + +### `che-cli restart` +Performs a `che-cli stop` followed by a `che-cli start`, respecting `--pull`, `--force`, and `--offline`. + +### `che-cli destroy` +Deletes `/docs`, `che.env` and `/che/instance`, including destroying all user workspaces, projects, data, and user database. If you pass `--quiet` then the confirmation warning will be skipped. + +If you have mounted the `:/cli` path, then we write the `cli.log` to your host directory. By default, this log is not destroyed in a `che-cli destroy` command so that you can maintain a record of all CLI executions. You can also have this file removed from your host by mounting `:/cli` and passing the `--cli` parameter to this command. + +### `che-cli offline` +Saves all of the Docker images that Che requires into `/backup/*.tar` files. Each image is saved as its own file. If the `backup` folder is available on a machine that is disconnected from the Internet and you start Che with `--offline`, the CLI pre-boot sequence will load all of the Docker images in the `/backup/` folder. + +### `che-cli rmi` +Deletes the Docker images from the local registry that Che has downloaded for this version. + +### `che-cli download` +Used to download Docker images that will be stored in your Docker images repository. This command downloads images that are used by the CLI as utilities, for Che to do initialization and configuration, and for the runtime images that Che needs when it starts. This command respects `--offline`, `--pull`, `--force`, and `--no-force` (default). This command is invoked by `che-cli init`, `che-cli config`, and `che-cli start`. + +This command is invoked by `che-cli init` before initialization to download the images for the version specified by `eclipse/che-cli:`. + +### `che-cli version` +Provides information on the current version and the available versions that are hosted in Che's repositories. `che-cli upgrade` enforces upgrade sequences and will prevent you from upgrading one version to another version where data migrations cannot be guaranteed. + +### `che-cli upgrade` +Manages the sequence of upgrading Che from one version to another. Run `che-cli version` to get a list of available versions that you can upgrade to. + +Upgrading Che is done by using a `eclipse/che-cli:` that is newer than the version you currently have installed. For example, if you have 5.0.0-M2 installed and want to upgrade to 5.0.0-M7, then: +``` +# Get the new version of Che +docker pull eclipse/che-cli:5.0.0-M7 + +# You now have two eclipse/che-cli images (one for each version) +# Perform an upgrade - use the new image to upgrade old installation +docker run eclipse/che-cli:5.0.0-M7 upgrade +``` + +The upgrade command has numerous checks to prevent you from upgrading Che if the new image and the old version are not compatiable. In order for the upgrade procedure to proceed, the CLI image must be newer than the value of '/instance/che.ver'. + +The upgrade process: a) performs a version compatibility check, b) downloads new Docker images that are needed to run the new version of Che, c) stops Che if it is currently running triggering a maintenance window, d) backs up your installation, e) initializes the new version, and f) starts Che. + +You can run `che-cli version` to see the list of available versions that you can upgrade to. + +### `che-cli info` +Displays system state and debugging information. `--network` runs a test to take your `Che_HOST` value to test for networking connectivity simulating browser > Che and Che > workspace connectivity. + +### `che-cli backup` +Tars your `/instance` into files and places them into `/backup`. These files are restoration-ready. + +### `che-cli restore` +Restores `/instance` to its previous state. You do not need to worry about having the right Docker images. The normal start / stop / restart cycle ensures that the proper Docker images are available or downloaded, if not found. + +This command will destroy your existing `/instance` folder, so use with caution, or set these values to different folders when performing a restore. From c7fda4f4b5397384d1f9cf22d2d9d67db1008fe3 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 2 Dec 2016 17:02:31 +0200 Subject: [PATCH 42/74] CHE-3044 Remove temporary workspaces on server shutdown (#3245) --- .../che/api/deploy/WsMasterModule.java | 2 + .../server/TemporaryWorkspaceRemover.java | 84 ++++++++++++++++++ .../workspace/server/WorkspaceManager.java | 13 ++- .../workspace/server/jpa/JpaWorkspaceDao.java | 22 +++++ .../server/model/impl/WorkspaceImpl.java | 5 +- .../workspace/server/spi/WorkspaceDao.java | 19 ++++ .../server/TemporaryWorkspaceRemoverTest.java | 86 +++++++++++++++++++ .../server/spi/tck/WorkspaceDaoTest.java | 32 +++++++ .../1__add_index_on_workspace_temporary.sql | 13 +++ .../che/api/local/LocalWorkspaceDaoImpl.java | 13 +++ 10 files changed, 285 insertions(+), 4 deletions(-) create mode 100644 wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java create mode 100644 wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java create mode 100644 wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M9/1__add_index_on_workspace_temporary.sql diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 290d8ff3494..c2a8c4a09cb 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -20,6 +20,7 @@ import org.eclipse.che.api.core.rest.MessageBodyAdapterInterceptor; import org.eclipse.che.api.machine.shared.Constants; import org.eclipse.che.api.user.server.TokenValidator; +import org.eclipse.che.api.workspace.server.TemporaryWorkspaceRemover; import org.eclipse.che.api.workspace.server.WorkspaceConfigMessageBodyAdapter; import org.eclipse.che.api.workspace.server.WorkspaceMessageBodyAdapter; import org.eclipse.che.api.workspace.server.stack.StackMessageBodyAdapter; @@ -69,6 +70,7 @@ protected void configure() { bind(org.eclipse.che.api.user.server.PreferencesService.class); bind(org.eclipse.che.api.workspace.server.stack.StackLoader.class); bind(org.eclipse.che.api.workspace.server.stack.StackService.class); + bind(org.eclipse.che.api.workspace.server.TemporaryWorkspaceRemover.class); bind(org.eclipse.che.api.workspace.server.WorkspaceService.class); bind(org.eclipse.che.api.workspace.server.event.WorkspaceMessenger.class).asEagerSingleton(); bind(org.eclipse.che.plugin.docker.machine.ext.DockerMachineExtServerChecker.class); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java new file mode 100644 index 00000000000..97867c53a13 --- /dev/null +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.workspace.server; + +import com.google.common.annotations.VisibleForTesting; + +import org.eclipse.che.api.core.ConflictException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; +import org.slf4j.Logger; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; + +import java.util.List; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Removes temporary workspaces on server startup and shutdown. + * + * @author Max Shaposhnik (mshaposhnik@codenvy.com) + */ +@Singleton +public class TemporaryWorkspaceRemover { + + private static final Logger LOG = getLogger(TemporaryWorkspaceRemover.class); + + private final WorkspaceDao workspaceDao; + + @Inject + public TemporaryWorkspaceRemover(WorkspaceDao workspaceDao) { + this.workspaceDao = workspaceDao; + } + + + @PostConstruct + void initialize() { + try { + removeTemporaryWs(); + } catch (ServerException e) { + LOG.warn("Unable to cleanup temporary workspaces on startup: " + e.getLocalizedMessage(), e); + } + } + + @PreDestroy + void shutdown() { + try { + removeTemporaryWs(); + } catch (ServerException e) { + LOG.warn("Unable to cleanup temporary workspaces on shutdown: " + e.getLocalizedMessage(), e); + } + } + + @VisibleForTesting + void removeTemporaryWs() throws ServerException { + final int count = 100; + int skip = 0; + List workspaces = workspaceDao.getWorkspaces(true, skip, count); + while (!workspaces.isEmpty()) { + for (WorkspaceImpl workspace : workspaces) { + try { + workspaceDao.remove(workspace.getId()); + } catch (ServerException | ConflictException e) { + LOG.error("Unable to cleanup temporary workspace {}. Reason is {}",workspace.getId(), e.getLocalizedMessage()); + } + } + skip = skip + count; + workspaces = workspaceDao.getWorkspaces(true, skip, count); + } + } + +} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index 7651f763616..87cf9f2ba2c 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -698,9 +698,7 @@ void performAsyncStop(WorkspaceImpl workspace, @Nullable Boolean createSnapshot) } try { runtimes.stop(workspace.getId()); - if (workspace.isTemporary()) { - workspaceDao.remove(workspace.getId()); - } else { + if (!workspace.isTemporary()) { workspace.getAttributes().put(UPDATED_ATTRIBUTE_NAME, Long.toString(currentTimeMillis())); workspaceDao.update(workspace); } @@ -711,6 +709,15 @@ void performAsyncStop(WorkspaceImpl workspace, @Nullable Boolean createSnapshot) firstNonNull(stoppedBy, "undefined")); } catch (RuntimeException | ConflictException | NotFoundException | ServerException ex) { LOG.error(ex.getLocalizedMessage(), ex); + } finally { + // Remove tmp workspaces even if stop is failed + if (workspace.isTemporary()) { + try { + workspaceDao.remove(workspace.getId()); + } catch (ConflictException | ServerException e) { + LOG.error("Unable to remove temporary workspace {} after stop.", workspace.getId()); + } + } } })); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java index c21e3c511a6..a64c68b7ecd 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java @@ -36,8 +36,10 @@ import java.util.List; import java.util.stream.Collectors; +import static com.google.common.base.Preconditions.checkArgument; import static java.lang.String.format; import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toList; /** * JPA based implementation of {@link WorkspaceDao}. @@ -159,6 +161,26 @@ public List getWorkspaces(String userId) throws ServerException { } } + @Override + @Transactional + public List getWorkspaces(boolean isTemporary, int skipCount, int maxItems) throws ServerException { + checkArgument(maxItems >= 0, "The number of items to return can't be negative."); + checkArgument(skipCount >= 0, "The number of items to skip can't be negative or greater than " + Integer.MAX_VALUE); + try { + return managerProvider.get() + .createNamedQuery("Workspace.getByTemporary", WorkspaceImpl.class) + .setParameter("temporary", isTemporary) + .setMaxResults(maxItems) + .setFirstResult(skipCount) + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(toList()); + } catch (RuntimeException x) { + throw new ServerException(x.getLocalizedMessage(), x); + } + } + @Transactional protected void doCreate(WorkspaceImpl workspace) { if (workspace.getConfig() != null) { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java index 164584e8173..d0f8d99b400 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java @@ -60,7 +60,10 @@ @NamedQuery(name = "Workspace.getByName", query = "SELECT w FROM Workspace w WHERE w.account.name = :namespace AND w.name = :name"), @NamedQuery(name = "Workspace.getAll", - query = "SELECT w FROM Workspace w") + query = "SELECT w FROM Workspace w"), + @NamedQuery(name = "Workspace.getByTemporary", + query = "SELECT w FROM Workspace w WHERE w.isTemporary = :temporary") + } ) @EntityListeners({WorkspaceEntityListener.class, WorkspaceImpl.SyncNameOnUpdateAndPersistEventListener.class}) diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java index ebe77194e5a..aa0a2368c1d 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java @@ -142,4 +142,23 @@ public interface WorkspaceDao { * when any other error occurs during workspaces fetching */ List getWorkspaces(String userId) throws ServerException; + + + /** + * Gets workspaces by temporary attribute. + * + * @param isTemporary + * When {@code true}, only temporary workspaces should be retrieved. + * When {@code false}, only non-temporary workspaces should be retrieved. + * @param skipCount + * the number of workspaces to skip + * @param maxItems + * the maximum number of workspaces to return + * @return list of workspaces or empty list if no workspaces were found + * @throws ServerException + * when any other error occurs during workspaces fetching + * @throws IllegalArgumentException + * when {@code maxItems} or {@code skipCount} is negative + */ + List getWorkspaces(boolean isTemporary, int skipCount, int maxItems) throws ServerException; } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java new file mode 100644 index 00000000000..42363fb62de --- /dev/null +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.workspace.server; + +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.intThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * @author Max Shaposhnik (mshaposhnik@codenvy.com) + */ +@Listeners(MockitoTestNGListener.class) +public class TemporaryWorkspaceRemoverTest { + + static final int COUNT_OF_WORKSPACES = 250; + + @Mock + private WorkspaceDao workspaceDao; + + @InjectMocks + private TemporaryWorkspaceRemover remover; + + @Test + public void shouldRemoveTemporaryWorkspaces() throws Exception { + doNothing().when(workspaceDao).remove(anyString()); + // As we want to check pagination, we return items 100 when skip count is 0 or 100, + // return 50 items when skip count is 200, and return empty list when skip count is 300. + doReturn(createEntities(100)).when(workspaceDao).getWorkspaces(eq(true), intThat(new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return ((int)argument) < 200; + } + }), anyInt()); + doReturn(createEntities(50)).when(workspaceDao).getWorkspaces(eq(true), intThat(new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return ((int)argument) == 200; + } + }), anyInt()); + doReturn(Collections.emptyList()).when(workspaceDao).getWorkspaces(eq(true), intThat(new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return ((int)argument) > COUNT_OF_WORKSPACES; + } + }), anyInt()); + + remover.removeTemporaryWs(); + + verify(workspaceDao, times(COUNT_OF_WORKSPACES)).remove(anyString()); + } + + private List createEntities(int number) { + List wsList = new ArrayList<>(); + for (int i = 0; i < number; i++) { + wsList.add(new WorkspaceImpl("id" + i, null, null)); + } + return wsList; + } + +} diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java index eaa70c8a632..4501aa1d6c0 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java @@ -189,6 +189,38 @@ public void shouldRemoveWorkspace() throws Exception { workspaceDao.get(workspace.getId()); } + + @Test + public void shouldGetWorkspacesByNonTemporary() throws Exception { + List result = workspaceDao.getWorkspaces(false, 0, 2); + + assertEquals(result.size(), 2); + assertEquals(new HashSet<>(result), new HashSet<>(asList(workspaces[0], workspaces[1]))); + } + + @Test + public void shouldGetWorkspacesByTemporary() throws Exception { + final WorkspaceImpl workspace = workspaces[0]; + workspace.setTemporary(true); + workspaceDao.update(workspace); + + List result = workspaceDao.getWorkspaces(true, 0, 0); + + assertEquals(result.size(), 1); + assertEquals(result.iterator().next(), workspaceDao.get(workspace.getId())); + } + + + @Test(expectedExceptions = IllegalArgumentException.class) + public void shouldThrowIllegalStateExceptionOnNegativeLimit() throws Exception { + workspaceDao.getWorkspaces(true, 0, -2); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void shouldThrowIllegalStateExceptionOnNegativeSkipCount() throws Exception { + workspaceDao.getWorkspaces(true, -2, 0); + } + @Test public void shouldPublicRemoveWorkspaceEventAfterRemoveWorkspace() throws Exception { final boolean[] isNotified = new boolean[] {false}; diff --git a/wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M9/1__add_index_on_workspace_temporary.sql b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M9/1__add_index_on_workspace_temporary.sql new file mode 100644 index 00000000000..91d08433a54 --- /dev/null +++ b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/5.0.0-M9/1__add_index_on_workspace_temporary.sql @@ -0,0 +1,13 @@ +-- +-- Copyright (c) 2012-2016 Codenvy, S.A. +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v1.0 +-- which accompanies this distribution, and is available at +-- http://www.eclipse.org/legal/epl-v10.html +-- +-- Contributors: +-- Codenvy, S.A. - initial API and implementation +-- + +--indexes +CREATE INDEX index_workspace_istemporary ON workspace (istemporary); diff --git a/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalWorkspaceDaoImpl.java b/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalWorkspaceDaoImpl.java index b5d0970067b..58e5e3959eb 100644 --- a/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalWorkspaceDaoImpl.java +++ b/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalWorkspaceDaoImpl.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; import static java.lang.String.format; import static java.util.Objects.requireNonNull; @@ -163,6 +164,18 @@ public List getWorkspaces(String userId) throws ServerException { return new ArrayList<>(workspaces.values()); } + @Override + public List getWorkspaces(boolean isTemporary, int skipCount, int maxItems) throws ServerException { + Stream stream = workspaces.values().stream(); + stream.filter(ws -> ws.isTemporary() == isTemporary); + stream.skip(skipCount); + if (maxItems != 0) { + stream.limit(maxItems); + } + return stream.collect(toList()); + } + + private Optional find(String name, String owner) { return workspaces.values() .stream() From a3464548a8fde99ddf6d10d0a98f626c31c957c8 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Mon, 5 Dec 2016 15:57:05 +0100 Subject: [PATCH 43/74] Issue 1793: Language Server Protocol: ShowMessage Notification feature (#3124) Added a ShowMessageProcessor and a ShowMessageMessager classes to process incoming `window/showMessage` notification and display a notification in `float` mode in the UI if the message type is `error` or `warning`, in the events panel otherwise. Note that the notification type for `error` messages is incorrectly set to `Log` because of a bug in the typefox dependency: `io.typefox.lsapi.MessageType#Log` has the value `1` instead of `4`. This issue depends on https://github.com/eclipse/che/pull/3113 (Add a 'warning' state for the notifications) To test the pull request, please follow the instructions on https://github.com/eclipse/che/pull/3123 to run the 'test-lang' server. Once in the workspace, create a project, add a `foo.test` file (the Language Server support for the 'test-lang' will be activated), then type the following line > window/showMessage:error: a message and wait for the editor to save the changes. This will trigger a `window/showMessage` notification from the 'test-lang' server in the Che UI. Signed-off-by: Xavier Coulon --- .gitignore | 1 + .../ide/editor/ShowMessageProcessor.java | 58 ++++++++++++++++ .../service/TextDocumentServiceClient.java | 36 +++++++++- .../ide/service/WorkspaceServiceClient.java | 8 ++- .../languageserver/LanguageServerModule.java | 17 ++--- .../messager/ShowMessageMessenger.java | 68 +++++++++++++++++++ .../registry/ServerInitializerImpl.java | 12 +++- .../registry/ServerInitializerImplTest.java | 5 +- 8 files changed, 187 insertions(+), 18 deletions(-) create mode 100644 plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/ShowMessageProcessor.java create mode 100644 wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/messager/ShowMessageMessenger.java diff --git a/.gitignore b/.gitignore index 193322c7c7b..d1738070c3f 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ config/ ###################### *.log *.sqlite +npm-debug.log.* # OS generated files # ###################### diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/ShowMessageProcessor.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/ShowMessageProcessor.java new file mode 100644 index 00000000000..6012819aabb --- /dev/null +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/ShowMessageProcessor.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ + +package org.eclipse.che.plugin.languageserver.ide.editor; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; + +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.util.loging.Log; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import io.typefox.lsapi.MessageParams; + +/** + * A processor for incoming window/showMessage notifications sent + * by a language server. + * + * @author xcoulon + */ +@Singleton +public class ShowMessageProcessor { + + private final NotificationManager notificationManager; + + @Inject + public ShowMessageProcessor(final NotificationManager notificationManager) { + this.notificationManager = notificationManager; + } + + public void processNotification(final MessageParams messageParams) { + Log.debug(getClass(), "Received a 'ShowMessage' message: " + messageParams.getMessage()); + switch(messageParams.getType()) { + case Error: + this.notificationManager.notify(messageParams.getMessage(), StatusNotification.Status.FAIL, FLOAT_MODE); + break; + case Warning: + this.notificationManager.notify(messageParams.getMessage(), StatusNotification.Status.WARNING, FLOAT_MODE); + break; + case Info: + case Log: + default: + this.notificationManager.notify(messageParams.getMessage(), StatusNotification.Status.SUCCESS, FLOAT_MODE); + break; + } + } + +} diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java index 472063a01c0..50c3bf90fc6 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/TextDocumentServiceClient.java @@ -29,6 +29,7 @@ import org.eclipse.che.api.languageserver.shared.lsapi.LocationDTO; import org.eclipse.che.api.languageserver.shared.lsapi.PublishDiagnosticsParamsDTO; import org.eclipse.che.api.languageserver.shared.lsapi.ReferenceParamsDTO; +import org.eclipse.che.api.languageserver.shared.lsapi.ShowMessageRequestParamsDTO; import org.eclipse.che.api.languageserver.shared.lsapi.SignatureHelpDTO; import org.eclipse.che.api.languageserver.shared.lsapi.SymbolInformationDTO; import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentPositionParamsDTO; @@ -49,6 +50,7 @@ import org.eclipse.che.ide.websocket.WebSocketException; import org.eclipse.che.ide.websocket.rest.SubscriptionHandler; import org.eclipse.che.plugin.languageserver.ide.editor.PublishDiagnosticsProcessor; +import org.eclipse.che.plugin.languageserver.ide.editor.ShowMessageProcessor; import java.util.List; @@ -68,6 +70,7 @@ public class TextDocumentServiceClient { private final AppContext appContext; private final NotificationManager notificationManager; private final PublishDiagnosticsProcessor publishDiagnosticsProcessor; + private final ShowMessageProcessor showMessageProcessor; @Inject public TextDocumentServiceClient( @@ -76,7 +79,8 @@ public TextDocumentServiceClient( final AppContext appContext, final AsyncRequestFactory asyncRequestFactory, final WsAgentStateController wsAgentStateController, - final PublishDiagnosticsProcessor publishDiagnosticsProcessor) { + final PublishDiagnosticsProcessor publishDiagnosticsProcessor, + final ShowMessageProcessor showMessageProcessor) { this.unmarshallerFactory = unmarshallerFactory; this.notificationManager = notificationManager; this.appContext = appContext; @@ -84,10 +88,12 @@ public TextDocumentServiceClient( this.publishDiagnosticsProcessor = publishDiagnosticsProcessor; wsAgentStateController.getMessageBus().then(new Operation() { @Override - public void apply(MessageBus arg) throws OperationException { - subscribeToPublishDiagnostics(arg); + public void apply(MessageBus messageBus) throws OperationException { + subscribeToPublishDiagnostics(messageBus); + subscribeToShowMessages(messageBus); } }); + this.showMessageProcessor = showMessageProcessor; } /** @@ -310,4 +316,28 @@ protected void onErrorReceived(Throwable exception) { } } + /** + * Subscribes to websocket for 'window/showMessage' notifications. + */ + private void subscribeToShowMessages(final MessageBus messageBus) { + final org.eclipse.che.ide.websocket.rest.Unmarshallable unmarshaller = + unmarshallerFactory.newWSUnmarshaller(ShowMessageRequestParamsDTO.class); + try { + messageBus.subscribe("languageserver/window/showMessage", + new SubscriptionHandler(unmarshaller) { + @Override + protected void onMessageReceived(ShowMessageRequestParamsDTO showMessageRequestParamsDTO) { + showMessageProcessor.processNotification(showMessageRequestParamsDTO); + } + + @Override + protected void onErrorReceived(Throwable exception) { + notificationManager.notify(exception.getMessage(), StatusNotification.Status.FAIL, + StatusNotification.DisplayMode.NOT_EMERGE_MODE); + } + }); + } catch (WebSocketException exception) { + Log.error(getClass(), exception); + } + } } diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/WorkspaceServiceClient.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/WorkspaceServiceClient.java index b3c7acafbca..cb88667c4de 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/WorkspaceServiceClient.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/service/WorkspaceServiceClient.java @@ -20,7 +20,6 @@ import org.eclipse.che.ide.rest.AsyncRequestFactory; import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; import org.eclipse.che.ide.rest.Unmarshallable; - import java.util.List; import static org.eclipse.che.ide.MimeType.APPLICATION_JSON; @@ -35,11 +34,13 @@ public class WorkspaceServiceClient { private final DtoUnmarshallerFactory unmarshallerFactory; private final AppContext appContext; private final AsyncRequestFactory asyncRequestFactory; - + + @Inject public WorkspaceServiceClient(final DtoUnmarshallerFactory unmarshallerFactory, final AppContext appContext, - final AsyncRequestFactory asyncRequestFactory) { + final AsyncRequestFactory asyncRequestFactory + ) { this.unmarshallerFactory = unmarshallerFactory; this.appContext = appContext; this.asyncRequestFactory = asyncRequestFactory; @@ -59,4 +60,5 @@ public Promise> symbol(WorkspaceSymbolParamsDTO param .header(CONTENT_TYPE, APPLICATION_JSON) .send(unmarshaller); } + } diff --git a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/LanguageServerModule.java b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/LanguageServerModule.java index 2fd68b280d8..ed5d7801fb5 100644 --- a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/LanguageServerModule.java +++ b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/LanguageServerModule.java @@ -10,18 +10,19 @@ *******************************************************************************/ package org.eclipse.che.api.languageserver; -import com.google.inject.AbstractModule; - -import org.eclipse.che.api.languageserver.messager.PublishDiagnosticsParamsMessenger; -import org.eclipse.che.api.languageserver.registry.ServerInitializer; -import org.eclipse.che.api.languageserver.service.LanguageRegistryService; -import org.eclipse.che.api.languageserver.service.TextDocumentService; -import org.eclipse.che.inject.DynaModule; import org.eclipse.che.api.languageserver.messager.InitializeEventMessenger; +import org.eclipse.che.api.languageserver.messager.PublishDiagnosticsParamsMessenger; +import org.eclipse.che.api.languageserver.messager.ShowMessageMessenger; import org.eclipse.che.api.languageserver.registry.LanguageServerRegistry; import org.eclipse.che.api.languageserver.registry.LanguageServerRegistryImpl; +import org.eclipse.che.api.languageserver.registry.ServerInitializer; import org.eclipse.che.api.languageserver.registry.ServerInitializerImpl; +import org.eclipse.che.api.languageserver.service.LanguageRegistryService; +import org.eclipse.che.api.languageserver.service.TextDocumentService; import org.eclipse.che.api.languageserver.service.WorkspaceService; +import org.eclipse.che.inject.DynaModule; + +import com.google.inject.AbstractModule; @DynaModule public class LanguageServerModule extends AbstractModule { @@ -30,11 +31,11 @@ public class LanguageServerModule extends AbstractModule { protected void configure() { bind(LanguageServerRegistry.class).to(LanguageServerRegistryImpl.class); bind(ServerInitializer.class).to(ServerInitializerImpl.class); - bind(LanguageRegistryService.class); bind(TextDocumentService.class); bind(WorkspaceService.class); bind(PublishDiagnosticsParamsMessenger.class); + bind(ShowMessageMessenger.class); bind(InitializeEventMessenger.class); } } diff --git a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/messager/ShowMessageMessenger.java b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/messager/ShowMessageMessenger.java new file mode 100644 index 00000000000..11703b2a28b --- /dev/null +++ b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/messager/ShowMessageMessenger.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.languageserver.messager; + +import java.io.IOException; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.websocket.EncodeException; + +import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.core.notification.EventSubscriber; +import org.everrest.websockets.WSConnectionContext; +import org.everrest.websockets.message.ChannelBroadcastMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +import io.typefox.lsapi.MessageParams; + +/** + * {@link EventSubscriber} for incoming window/showMessage notifications. + * @author xcoulon + */ +@Singleton +public class ShowMessageMessenger implements EventSubscriber { + + private final static Logger LOG = LoggerFactory.getLogger(ShowMessageMessenger.class); + + private final EventService eventService; + + @Inject + public ShowMessageMessenger(EventService eventService) { + this.eventService = eventService; + } + + public void onEvent(final MessageParams event) { + try { + final ChannelBroadcastMessage bm = new ChannelBroadcastMessage(); + bm.setChannel("languageserver/window/showMessage"); + bm.setBody(new Gson().toJson(event)); + WSConnectionContext.sendMessage(bm); + } catch (EncodeException | IOException e) { + LOG.error(e.getMessage(), e); + } + } + + @PostConstruct + public void subscribe() { + eventService.subscribe(this); + } + + @PreDestroy + public void unsubscribe() { + eventService.unsubscribe(this); + } +} diff --git a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImpl.java b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImpl.java index 0e78f25053e..9fae7038894 100644 --- a/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImpl.java +++ b/wsagent/che-core-api-languageserver/src/main/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImpl.java @@ -22,6 +22,7 @@ import org.eclipse.che.api.languageserver.exception.LanguageServerException; import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncher; import org.eclipse.che.api.languageserver.messager.PublishDiagnosticsParamsMessenger; +import org.eclipse.che.api.languageserver.messager.ShowMessageMessenger; import org.eclipse.che.api.languageserver.shared.model.LanguageDescription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +36,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; /** * @author Anatoliy Bazko @@ -48,16 +50,19 @@ public class ServerInitializerImpl implements ServerInitializer { private final List observers; private final PublishDiagnosticsParamsMessenger publishDiagnosticsParamsMessenger; - + private final ShowMessageMessenger showMessageMessenger; + private final ConcurrentHashMap languageIdToServers; private final ConcurrentHashMap serversToInitResult; @Inject - public ServerInitializerImpl(PublishDiagnosticsParamsMessenger publishDiagnosticsParamsMessenger) { + public ServerInitializerImpl(final PublishDiagnosticsParamsMessenger publishDiagnosticsParamsMessenger, + final ShowMessageMessenger showMessageMessenger) { this.observers = new ArrayList<>(); this.languageIdToServers = new ConcurrentHashMap<>(); this.serversToInitResult = new ConcurrentHashMap<>(); this.publishDiagnosticsParamsMessenger = publishDiagnosticsParamsMessenger; + this.showMessageMessenger = showMessageMessenger; } private static int getProcessId() { @@ -137,7 +142,8 @@ protected LanguageServer doInitialize(LanguageServerLauncher launcher, String pr protected void registerCallbacks(LanguageServer server) { server.getTextDocumentService().onPublishDiagnostics(publishDiagnosticsParamsMessenger::onEvent); - server.getWindowService().onLogMessage(messageParams -> LOG.error(messageParams.getType() + " " + messageParams.getMessage())); + server.getWindowService().onLogMessage(messageParams -> LOG.error(messageParams.getType() + " " + messageParams.getMessage())); + server.getWindowService().onShowMessage(showMessageMessenger::onEvent); server.onTelemetryEvent(o -> LOG.error(o.toString())); if (server instanceof ServerInitializerObserver) { diff --git a/wsagent/che-core-api-languageserver/src/test/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImplTest.java b/wsagent/che-core-api-languageserver/src/test/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImplTest.java index 17791051cd2..f0ee3db0f80 100644 --- a/wsagent/che-core-api-languageserver/src/test/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImplTest.java +++ b/wsagent/che-core-api-languageserver/src/test/java/org/eclipse/che/api/languageserver/registry/ServerInitializerImplTest.java @@ -17,6 +17,7 @@ import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncher; import org.eclipse.che.api.languageserver.messager.PublishDiagnosticsParamsMessenger; +import org.eclipse.che.api.languageserver.messager.ShowMessageMessenger; import org.eclipse.che.api.languageserver.shared.model.LanguageDescription; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -47,6 +48,8 @@ public class ServerInitializerImplTest { @Mock private PublishDiagnosticsParamsMessenger publishDiagnosticsParamsMessenger; @Mock + private ShowMessageMessenger showMessageParamsMessenger; + @Mock private LanguageDescription languageDescription; @Mock private LanguageServerLauncher launcher; @@ -59,7 +62,7 @@ public class ServerInitializerImplTest { @BeforeMethod public void setUp() throws Exception { - initializer = spy(new ServerInitializerImpl(publishDiagnosticsParamsMessenger)); + initializer = spy(new ServerInitializerImpl(publishDiagnosticsParamsMessenger, showMessageParamsMessenger)); } @Test From 9dadb3a9024b5fc3597fbd47aa919632e1bad670 Mon Sep 17 00:00:00 2001 From: Eugene Ivantsov Date: Tue, 6 Dec 2016 07:51:07 +0200 Subject: [PATCH 44/74] Add new arch type (#3279) --- .../src/main/resources/agents/org.eclipse.che.terminal.json | 2 +- .../resources/agents/scripts/org.eclipse.che.terminal.script.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.terminal.json b/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.terminal.json index 033442f648a..b241107f710 100644 --- a/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.terminal.json +++ b/wsmaster/che-core-api-agent/src/main/resources/agents/org.eclipse.che.terminal.json @@ -10,5 +10,5 @@ "protocol": "http" } }, -"script" : "#\n# Copyright (c) 2012-2016 Codenvy, S.A.\n# All rights reserved. This program and the accompanying materials\n# are made available under the terms of the Eclipse Public License v1.0\n# which accompanies this distribution, and is available at\n# http://www.eclipse.org/legal/epl-v10.html\n#\n# Contributors:\n# Codenvy, S.A. - initial API and implementation\n#\n\nunset PACKAGES\nunset SUDO\ncommand -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" tar\"; }\ncommand -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" curl\"; }\ntest \"$(id -u)\" = 0 || SUDO=\"sudo\"\n\nCHE_DIR=$HOME/che\nLOCAL_AGENT_BINARIES_URI='/mnt/che/terminal/websocket-terminal-${PREFIX}.tar.gz'\nDOWNLOAD_AGENT_BINARIES_URI='${WORKSPACE_MASTER_URI}/agent-binaries/${PREFIX}/terminal/websocket-terminal-${PREFIX}.tar.gz'\nTARGET_AGENT_BINARIES_URI='file://${CHE_DIR}/websocket-terminal-${PREFIX}.tar.gz'\n\nif [ -f /etc/centos-release ]; then\n FILE=\"/etc/centos-release\"\n LINUX_TYPE=$(cat $FILE | awk '{print $1}')\n elif [ -f /etc/redhat-release ]; then\n FILE=\"/etc/redhat-release\"\n LINUX_TYPE=$(cat $FILE | cut -c 1-8)\n else\n FILE=\"/etc/os-release\"\n LINUX_TYPE=$(cat $FILE | grep ^ID= | tr '[:upper:]' '[:lower:]')\n LINUX_VERSION=$(cat $FILE | grep ^VERSION_ID=)\nfi\nMACHINE_TYPE=$(uname -m)\nSHELL_INTERPRETER=\"/bin/sh\"\n\n\nmkdir -p ${CHE_DIR}\n\n########################\n### Install packages ###\n########################\n\n# Red Hat Enterprise Linux 7 \n############################\nif echo ${LINUX_TYPE} | grep -qi \"rhel\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\n# Ubuntu 14.04 16.04 / Linux Mint 17 \n####################################\nelif echo ${LINUX_TYPE} | grep -qi \"ubuntu\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Debian 8\n##########\nelif echo ${LINUX_TYPE} | grep -qi \"debian\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Fedora 23 \n###########\nelif echo ${LINUX_TYPE} | grep -qi \"fedora\"; then\n PACKAGES=${PACKAGES}\" procps-ng\"\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} dnf -y install ${PACKAGES};\n }\n\n# CentOS 7.1 & Oracle Linux 7.1\n###############################\nelif echo ${LINUX_TYPE} | grep -qi \"centos\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# openSUSE 13.2\n###############\nelif echo ${LINUX_TYPE} | grep -qi \"opensuse\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} zypper install -y ${PACKAGES};\n }\n\n# Alpine 3.3\n############\nelif echo ${LINUX_TYPE} | grep -qi \"alpine\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apk update\n ${SUDO} apk add ${PACKAGES};\n }\n\n# Centos 6.6, 6.7, 6.8\n############\nelif echo ${LINUX_TYPE} | grep -qi \"CentOS\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# Red Hat Enterprise Linux 6 \n############################\n\nelif echo ${LINUX_TYPE} | grep -qi \"Red Hat\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\nelse\n >&2 echo \"Unrecognized Linux Type\"\n >&2 cat $FILE\n exit 1\nfi\n\ncommand -v pidof >/dev/null 2>&1 && {\n pidof che-websocket-terminal >/dev/null 2>&1 && exit\n} || {\n ps -fC che-websocket-terminal >/dev/null 2>&1 && exit\n}\n\n\n########################\n### Install Terminal ###\n########################\nif echo ${MACHINE_TYPE} | grep -qi \"x86_64\"; then\n PREFIX=linux_amd64\nelif echo ${MACHINE_TYPE} | grep -qi \"arm5\"; then\n PREFIX=linux_arm7\nelif echo ${MACHINE_TYPE} | grep -qi \"arm6\"; then\n PREFIX=linux_arm7\nelif echo ${MACHINE_TYPE} | grep -qi \"arm7\"; then\n PREFIX=linux_arm7\nelse\n >&2 echo \"Unrecognized Machine Type\"\n >&2 uname -a\n exit 1\nfi\n\n# Compute URI of workspace master\nWORKSPACE_MASTER_URI=$(echo $CHE_API | cut -d / -f 1-3)\n\n## Evaluate variables now that prefix is defined\neval \"LOCAL_AGENT_BINARIES_URI=${LOCAL_AGENT_BINARIES_URI}\"\neval \"DOWNLOAD_AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\"\neval \"TARGET_AGENT_BINARIES_URI=${TARGET_AGENT_BINARIES_URI}\"\n\nif [ -f \"${LOCAL_AGENT_BINARIES_URI}\" ]; then\n AGENT_BINARIES_URI=\"file://${LOCAL_AGENT_BINARIES_URI}\"\nelif [ -f $(echo \"${LOCAL_AGENT_BINARIES_URI}\" | sed \"s/-${PREFIX}//g\") ]; then\n AGENT_BINARIES_URI=\"file://\"$(echo \"${LOCAL_AGENT_BINARIES_URI}\" | sed \"s/-${PREFIX}//g\")\nelse\n echo \"Terminal Agent will be downloaded from Workspace Master\"\n AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\nfi\n\n\nif curl -o /dev/null --silent --head --fail $(echo ${AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g'); then\n curl -o $(echo ${TARGET_AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g' | sed 's/file:\\/\\///g') -s $(echo ${AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g')\nelif curl -o /dev/null --silent --head --fail $(echo ${AGENT_BINARIES_URI} | sed 's/-\\${PREFIX}//g'); then\n curl -o $(echo ${TARGET_AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g' | sed 's/file:\\/\\///g') -s $(echo ${AGENT_BINARIES_URI} | sed 's/-\\${PREFIX}//g')\nfi\n\ncurl -s $(echo ${TARGET_AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g') | tar xzf - -C ${CHE_DIR}\n\nif [ -f /bin/bash ]; then\n SHELL_INTERPRETER=\"/bin/bash\"\nfi\n\n$HOME/che/terminal/che-websocket-terminal -addr :4411 -cmd ${SHELL_INTERPRETER} -static $HOME/che/terminal/" +"script" : "#\n# Copyright (c) 2012-2016 Codenvy, S.A.\n# All rights reserved. This program and the accompanying materials\n# are made available under the terms of the Eclipse Public License v1.0\n# which accompanies this distribution, and is available at\n# http://www.eclipse.org/legal/epl-v10.html\n#\n# Contributors:\n# Codenvy, S.A. - initial API and implementation\n#\n\nunset PACKAGES\nunset SUDO\ncommand -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" tar\"; }\ncommand -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}\" curl\"; }\ntest \"$(id -u)\" = 0 || SUDO=\"sudo\"\n\nCHE_DIR=$HOME/che\nLOCAL_AGENT_BINARIES_URI='/mnt/che/terminal/websocket-terminal-${PREFIX}.tar.gz'\nDOWNLOAD_AGENT_BINARIES_URI='${WORKSPACE_MASTER_URI}/agent-binaries/${PREFIX}/terminal/websocket-terminal-${PREFIX}.tar.gz'\nTARGET_AGENT_BINARIES_URI='file://${CHE_DIR}/websocket-terminal-${PREFIX}.tar.gz'\n\nif [ -f /etc/centos-release ]; then\n FILE=\"/etc/centos-release\"\n LINUX_TYPE=$(cat $FILE | awk '{print $1}')\n elif [ -f /etc/redhat-release ]; then\n FILE=\"/etc/redhat-release\"\n LINUX_TYPE=$(cat $FILE | cut -c 1-8)\n else\n FILE=\"/etc/os-release\"\n LINUX_TYPE=$(cat $FILE | grep ^ID= | tr '[:upper:]' '[:lower:]')\n LINUX_VERSION=$(cat $FILE | grep ^VERSION_ID=)\nfi\nMACHINE_TYPE=$(uname -m)\nSHELL_INTERPRETER=\"/bin/sh\"\n\n\nmkdir -p ${CHE_DIR}\n\n########################\n### Install packages ###\n########################\n\n# Red Hat Enterprise Linux 7 \n############################\nif echo ${LINUX_TYPE} | grep -qi \"rhel\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\n# Ubuntu 14.04 16.04 / Linux Mint 17 \n####################################\nelif echo ${LINUX_TYPE} | grep -qi \"ubuntu\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Debian 8\n##########\nelif echo ${LINUX_TYPE} | grep -qi \"debian\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apt-get update;\n ${SUDO} apt-get -y install ${PACKAGES};\n }\n\n# Fedora 23 \n###########\nelif echo ${LINUX_TYPE} | grep -qi \"fedora\"; then\n PACKAGES=${PACKAGES}\" procps-ng\"\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} dnf -y install ${PACKAGES};\n }\n\n# CentOS 7.1 & Oracle Linux 7.1\n###############################\nelif echo ${LINUX_TYPE} | grep -qi \"centos\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# openSUSE 13.2\n###############\nelif echo ${LINUX_TYPE} | grep -qi \"opensuse\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} zypper install -y ${PACKAGES};\n }\n\n# Alpine 3.3\n############\nelif echo ${LINUX_TYPE} | grep -qi \"alpine\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} apk update\n ${SUDO} apk add ${PACKAGES};\n }\n\n# Centos 6.6, 6.7, 6.8\n############\nelif echo ${LINUX_TYPE} | grep -qi \"CentOS\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum -y install ${PACKAGES};\n }\n\n# Red Hat Enterprise Linux 6 \n############################\n\nelif echo ${LINUX_TYPE} | grep -qi \"Red Hat\"; then\n test \"${PACKAGES}\" = \"\" || {\n ${SUDO} yum install ${PACKAGES};\n }\n\nelse\n >&2 echo \"Unrecognized Linux Type\"\n >&2 cat $FILE\n exit 1\nfi\n\ncommand -v pidof >/dev/null 2>&1 && {\n pidof che-websocket-terminal >/dev/null 2>&1 && exit\n} || {\n ps -fC che-websocket-terminal >/dev/null 2>&1 && exit\n}\n\n\n########################\n### Install Terminal ###\n########################\nif echo ${MACHINE_TYPE} | grep -qi \"x86_64\"; then\n PREFIX=linux_amd64\nelif echo ${MACHINE_TYPE} | grep -qi \"arm5\"; then\n PREFIX=linux_arm7\nelif echo ${MACHINE_TYPE} | grep -qi \"arm6\"; then\n PREFIX=linux_arm7\nelif echo ${MACHINE_TYPE} | grep -qi \"arm7\"; then\n PREFIX=linux_arm7\nelif echo ${MACHINE_TYPE} | grep -qi \"armv7l\"; then\n PREFIX=linux_arm7\nelse\n >&2 echo \"Unrecognized Machine Type\"\n >&2 uname -a\n exit 1\nfi\n\n# Compute URI of workspace master\nWORKSPACE_MASTER_URI=$(echo $CHE_API | cut -d / -f 1-3)\n\n## Evaluate variables now that prefix is defined\neval \"LOCAL_AGENT_BINARIES_URI=${LOCAL_AGENT_BINARIES_URI}\"\neval \"DOWNLOAD_AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\"\neval \"TARGET_AGENT_BINARIES_URI=${TARGET_AGENT_BINARIES_URI}\"\n\nif [ -f \"${LOCAL_AGENT_BINARIES_URI}\" ]; then\n AGENT_BINARIES_URI=\"file://${LOCAL_AGENT_BINARIES_URI}\"\nelif [ -f $(echo \"${LOCAL_AGENT_BINARIES_URI}\" | sed \"s/-${PREFIX}//g\") ]; then\n AGENT_BINARIES_URI=\"file://\"$(echo \"${LOCAL_AGENT_BINARIES_URI}\" | sed \"s/-${PREFIX}//g\")\nelse\n echo \"Terminal Agent will be downloaded from Workspace Master\"\n AGENT_BINARIES_URI=${DOWNLOAD_AGENT_BINARIES_URI}\nfi\n\n\nif curl -o /dev/null --silent --head --fail $(echo ${AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g'); then\n curl -o $(echo ${TARGET_AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g' | sed 's/file:\\/\\///g') -s $(echo ${AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g')\nelif curl -o /dev/null --silent --head --fail $(echo ${AGENT_BINARIES_URI} | sed 's/-\\${PREFIX}//g'); then\n curl -o $(echo ${TARGET_AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g' | sed 's/file:\\/\\///g') -s $(echo ${AGENT_BINARIES_URI} | sed 's/-\\${PREFIX}//g')\nfi\n\ncurl -s $(echo ${TARGET_AGENT_BINARIES_URI} | sed 's/\\${PREFIX}/'${PREFIX}'/g') | tar xzf - -C ${CHE_DIR}\n\nif [ -f /bin/bash ]; then\n SHELL_INTERPRETER=\"/bin/bash\"\nfi\n\n$HOME/che/terminal/che-websocket-terminal -addr :4411 -cmd ${SHELL_INTERPRETER} -static $HOME/che/terminal/" } diff --git a/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.terminal.script.sh b/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.terminal.script.sh index 9abeb04aac3..4edd129db9f 100644 --- a/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.terminal.script.sh +++ b/wsmaster/che-core-api-agent/src/main/resources/agents/scripts/org.eclipse.che.terminal.script.sh @@ -133,6 +133,8 @@ elif echo ${MACHINE_TYPE} | grep -qi "arm6"; then PREFIX=linux_arm7 elif echo ${MACHINE_TYPE} | grep -qi "arm7"; then PREFIX=linux_arm7 +elif echo ${MACHINE_TYPE} | grep -qi "armv7l"; then + PREFIX=linux_arm7 else >&2 echo "Unrecognized Machine Type" >&2 uname -a From 1eece936660181e566675bb050f338a706e954ed Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Tue, 6 Dec 2016 10:15:09 +0200 Subject: [PATCH 45/74] fix typo Signed-off-by: Oleksii Kurinnyi --- .../environments/machine-config/machine-config.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard/src/app/workspaces/workspace-details/environments/machine-config/machine-config.html b/dashboard/src/app/workspaces/workspace-details/environments/machine-config/machine-config.html index 04d92cc25b9..0220170d5c2 100644 --- a/dashboard/src/app/workspaces/workspace-details/environments/machine-config/machine-config.html +++ b/dashboard/src/app/workspaces/workspace-details/environments/machine-config/machine-config.html @@ -84,7 +84,7 @@ - +
    From a62a56f333f23807a0f680d4ce89975c39252713 Mon Sep 17 00:00:00 2001 From: Evgen Vidolob Date: Tue, 6 Dec 2016 12:40:46 +0200 Subject: [PATCH 46/74] #2353 fix style to prevent line wrap in terminal (#3284) Signed-off-by: Evgen Vidolob --- .../org/eclipse/che/ide/extension/machine/client/machine.css | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css index da6752a6fa6..60d97ecd963 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css @@ -35,6 +35,7 @@ color: outputFontColor; line-height: 13px; padding: 3px; + white-space: nowrap; } .terminal-cursor { From 5ab033126dc17bbba50593583e8d29a9653f7993 Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Tue, 6 Dec 2016 13:07:37 +0200 Subject: [PATCH 47/74] CHE-3175: close all editors on WS stop event Signed-off-by: Vitalii Parfonov --- .../che/ide/api/machine/WsAgentStateController.java | 6 +++--- .../org/eclipse/che/ide/actions/StopWorkspaceAction.java | 5 ++--- .../java/org/eclipse/che/ide/context/AppContextImpl.java | 8 +++++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java index d53dceaa0f3..ca1da3b1500 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java @@ -203,17 +203,17 @@ private void started() { private void checkStateOfWsAgent(WsAgentHealthStateDto agentHealthStateDto) { final int statusCode = agentHealthStateDto.getCode(); final String infoWindowTitle = "Workspace Agent Not Responding"; - final ConfirmCallback restartCallback = new StopCallback(); + final ConfirmCallback stopCallback = new StopCallback(); if (statusCode == 200) { dialogFactory.createMessageDialog(infoWindowTitle, "Our workspace agent is no longer responding. To fix the problem, verify you have a" + " good network connection and restart the workspace.", - restartCallback).show(); + stopCallback).show(); } else { dialogFactory.createMessageDialog(infoWindowTitle, "Our workspace agent is no longer responding. To fix the problem, restart the workspace.", - restartCallback).show(); + stopCallback).show(); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/StopWorkspaceAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/StopWorkspaceAction.java index 4f70640e78a..62c1faae7b7 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/StopWorkspaceAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/StopWorkspaceAction.java @@ -12,16 +12,15 @@ import com.google.inject.Inject; -import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient; import javax.validation.constraints.NotNull; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.Collections.singletonList; import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java index 513545dea5a..115be2e6b49 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java @@ -452,8 +452,14 @@ public void apply(Void arg) throws OperationException { resourceManager = null; } }); - devMachine = null; + + //goto close all editors + final EditorAgent editorAgent = editorAgentProvider.get(); + final List openedEditors = editorAgent.getOpenedEditors(); + for (EditorPartPresenter editor : openedEditors) { + editorAgent.closeEditor(editor); + } } @Override From 871437aa9e2e5f6a07ac4941c9cb77a6458391a8 Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Tue, 6 Dec 2016 16:00:19 +0200 Subject: [PATCH 48/74] single compose file template (#3290) * single compose file template --- .../init/modules/compose/manifests/init.pp | 19 ++++++++------- .../docker-compose-container.yml.erb | 24 ------------------- .../compose/templates/docker-compose.yml.erb | 4 ++++ 3 files changed, 15 insertions(+), 32 deletions(-) delete mode 100644 dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb diff --git a/dockerfiles/init/modules/compose/manifests/init.pp b/dockerfiles/init/modules/compose/manifests/init.pp index 8fa71835bfb..08a7cf95348 100644 --- a/dockerfiles/init/modules/compose/manifests/init.pp +++ b/dockerfiles/init/modules/compose/manifests/init.pp @@ -1,14 +1,17 @@ class compose { - file { "/opt/che/docker-compose-container.yml": - ensure => "present", - content => template("compose/docker-compose-container.yml.erb"), - mode => '644', + define generate_compose_file($compose_file_name = $name, $compose_file_for_containers = false) { + file { "/opt/che/$compose_file_name": + ensure => "present", + content => template("compose/docker-compose.yml.erb"), + mode => '644', + } } - file { "/opt/che/docker-compose.yml": - ensure => "present", - content => template("compose/docker-compose.yml.erb"), - mode => '644', + compose::generate_compose_file { "docker-compose-container.yml" : + compose_file_for_containers => true } + compose::generate_compose_file { "docker-compose.yml" : + compose_file_for_containers => false + } } diff --git a/dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb b/dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb deleted file mode 100644 index 2dd0f57c4b4..00000000000 --- a/dockerfiles/init/modules/compose/templates/docker-compose-container.yml.erb +++ /dev/null @@ -1,24 +0,0 @@ -# ################################### -# This file is generated by puppet -# PLEASE DON'T MODIFY BY HAND -# ################################### - -che: - image: <%= ENV["IMAGE_CHE"] %> - env_file: - - '/che/instance/config/che.env' - volumes: - - '/var/run/docker.sock:/var/run/docker.sock' - - '<%= scope.lookupvar('che::che_instance') -%>/data:/data' - - '<%= scope.lookupvar('che::che_instance') -%>/logs:/logs' - - '<%= scope.lookupvar('che::che_instance') -%>/config:/conf' -<% if scope.lookupvar('che::che_env') != 'production' -%> - - '<%= scope.lookupvar('che::che_assembly') -%>:/assembly' -<% end -%> - ports: - - '<%= scope.lookupvar('che::che_port') -%>:8080' -<% if scope.lookupvar('che::che_env') != 'production' -%> - - '8000:8000' -<% end -%> - restart: always - container_name: che diff --git a/dockerfiles/init/modules/compose/templates/docker-compose.yml.erb b/dockerfiles/init/modules/compose/templates/docker-compose.yml.erb index 9b266bf33a2..8cd03de0e34 100644 --- a/dockerfiles/init/modules/compose/templates/docker-compose.yml.erb +++ b/dockerfiles/init/modules/compose/templates/docker-compose.yml.erb @@ -6,7 +6,11 @@ che: image: <%= ENV["IMAGE_CHE"] %> env_file: +<% if @compose_file_for_containers == true -%> + - '/che/instance/config/che.env' +<% else -%> - '<%= ENV["CHE_ENV_FILE"] %>' +<% end -%> volumes: - '/var/run/docker.sock:/var/run/docker.sock' - '<%= scope.lookupvar('che::che_instance') -%>/data:/data' From 2bd99e815e9a73b909a0f6e54958596a6a59a8cd Mon Sep 17 00:00:00 2001 From: Mihail Kuznyetsov Date: Tue, 6 Dec 2016 10:48:52 +0200 Subject: [PATCH 49/74] Add Workspace settings service --- .../workspace/server/WorkspaceService.java | 22 +++++++++++++++++-- .../server/WorkspaceServiceTest.java | 20 ++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index 3cc88a08c99..ea12e0f7502 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -18,6 +18,7 @@ import io.swagger.annotations.Example; import io.swagger.annotations.ExampleProperty; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import org.eclipse.che.api.agent.server.WsAgentHealthChecker; @@ -83,13 +84,16 @@ @Api(value = "/workspace", description = "Workspace REST API") @Path("/workspace") public class WorkspaceService extends Service { + private static final String CHE_WORKSPACE_AUTO_SNAPSHOT= "che.workspace.auto_snapshot"; + private static final String CHE_WORKSPACE_AUTO_RESTORE= "che.workspace.auto_restore"; private final WorkspaceManager workspaceManager; private final WorkspaceValidator validator; private final WsAgentHealthChecker agentHealthChecker; private final WorkspaceServiceLinksInjector linksInjector; private final String apiEndpoint; - + private final boolean cheWorkspaceAutoSnapshot; + private final boolean cheWorkspaceAutoRestore; @Context private SecurityContext securityContext; @@ -98,12 +102,16 @@ public WorkspaceService(@Named("che.api") String apiEndpoint, WorkspaceManager workspaceManager, WorkspaceValidator validator, WsAgentHealthChecker agentHealthChecker, - WorkspaceServiceLinksInjector workspaceServiceLinksInjector) { + WorkspaceServiceLinksInjector workspaceServiceLinksInjector, + @Named(CHE_WORKSPACE_AUTO_SNAPSHOT) boolean cheWorkspaceAutoSnapshot, + @Named(CHE_WORKSPACE_AUTO_RESTORE) boolean cheWorkspaceAutoRestore) { this.apiEndpoint = apiEndpoint; this.workspaceManager = workspaceManager; this.validator = validator; this.agentHealthChecker = agentHealthChecker; this.linksInjector = workspaceServiceLinksInjector; + this.cheWorkspaceAutoSnapshot = cheWorkspaceAutoSnapshot; + this.cheWorkspaceAutoRestore = cheWorkspaceAutoRestore; } @POST @@ -704,6 +712,16 @@ public WsAgentHealthStateDto checkAgentHealth(@ApiParam(value = "Workspace id") return check; } + @GET + @Path("/settings") + @Produces(APPLICATION_JSON) + @ApiOperation(value = "Get workspace server configuration values") + @ApiResponses({@ApiResponse(code = 200, message = "The response contains server settings")}) + public Map getSettings() { + return ImmutableMap.of(CHE_WORKSPACE_AUTO_SNAPSHOT, Boolean.toString(cheWorkspaceAutoSnapshot), + CHE_WORKSPACE_AUTO_RESTORE, Boolean.toString(cheWorkspaceAutoRestore)); + } + private static Map parseAttrs(List attributes) throws BadRequestException { if (attributes == null) { return emptyMap(); diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java index 351fb637461..37312d5687c 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java @@ -13,6 +13,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.jayway.restassured.response.Response; import org.eclipse.che.account.shared.model.Account; @@ -149,7 +151,9 @@ public void setup() { wsManager, validator, wsAgentHealthChecker, - new WorkspaceServiceLinksInjector(new MachineServiceLinksInjector())); + new WorkspaceServiceLinksInjector(new MachineServiceLinksInjector()), + true, + false); } @Test @@ -959,6 +963,20 @@ public void shouldReturnEmptyListIfNotSnapshotsFound() throws Exception { verify(wsManager).getSnapshot(workspaceId); } + @Test + public void shouldBeAbleToGetSettings() throws Exception { + final Response response = given().auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .when() + .get(SECURE_PATH + "/workspace/settings"); + + assertEquals(response.getStatusCode(), 200); + final Map settings = new Gson().fromJson(response.print(), + new TypeToken>() {}.getType()); + assertEquals(settings, ImmutableMap.of("che.workspace.auto_snapshot", "true", + "che.workspace.auto_restore", "false")); + } + private static String unwrapError(Response response) { return unwrapDto(response, ServiceError.class).getMessage(); } From 664bbf82ef2ec8e20674e7e66f3665518a61f2e6 Mon Sep 17 00:00:00 2001 From: Gennady Azarenkov Date: Thu, 1 Dec 2016 16:58:52 +0200 Subject: [PATCH 50/74] Make Project related (importer) OutputLineConsumer to be passed as a parameter to related ProjectManager methods instead of creating it inside. Modify RequestDispatcher to make it accept Array of DTO, String and Void --- .../core/jsonrpc/impl/RequestDispatcher.java | 70 ++++++++++++++----- wsagent/che-core-api-project/pom.xml | 4 ++ .../api/project/server/ProjectManager.java | 19 +++-- .../ProjectOutputLineConsumerFactory.java | 49 +++++++++++++ .../api/project/server/ProjectService.java | 10 ++- .../ProjectImportOutputWSLineConsumer.java | 13 ++-- .../server/ProjectManagerWriteTest.java | 39 ++++++----- ...ProjectImportOutputWSLineConsumerTest.java | 4 +- 8 files changed, 154 insertions(+), 54 deletions(-) create mode 100644 wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java index 0c76b240721..21779359c2e 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java @@ -10,17 +10,21 @@ *******************************************************************************/ package org.eclipse.che.api.core.jsonrpc.impl; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.eclipse.che.api.core.jsonrpc.RequestHandler; import org.eclipse.che.api.core.websocket.WebSocketMessageTransmitter; import org.eclipse.che.dto.server.DtoFactory; +import org.eclipse.che.dto.server.JsonSerializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Singleton; +import java.util.Collection; import java.util.Map; /** @@ -60,50 +64,75 @@ public void dispatch(String endpointId, JsonObject incomingJson) { LOG.debug("Extracted request method: " + method); final RequestHandler handler = handlers.get(method); + if(handler == null) { + LOG.error("Handler not found: " + method); + // TODO make a centralized standard errors structure + transmitter.transmit(endpointId, error(-32601, "Method not found: " + method)); + return; + } final Class resultClass = handler.getResultClass(); LOG.debug("Extracted request result class: " + resultClass); - JsonObject result; + JsonElement result; if (incomingJson.has("params")) { final JsonObject params = incomingJson.get("params").getAsJsonObject(); LOG.debug("Request is parametrized, processing parameters: " + params); final Class paramsClass = handler.getParamsClass(); LOG.debug("Extracted request params class: " + paramsClass); - - result = dispatch(endpointId, handler, params, paramsClass, resultClass); + result = response(endpointId, handler, params, paramsClass, resultClass); } else { - LOG.debug("Request is parametrized."); - - result = dispatch(endpointId, handler, resultClass); + LOG.debug("Request is not parametrized."); + result = response(endpointId, handler, null, null, resultClass); } - final JsonObject response = prepareResponse(id, result); + final JsonElement response = prepareResponse(id, result); LOG.debug("Generated response: " + response); transmitter.transmit(endpointId, response.toString()); } - private JsonObject dispatch(String endpointId, + private JsonElement response(String endpointId, RequestHandler handler, JsonObject params, Class

    paramClass, Class resultClass) { - final P param = DtoFactory.getInstance().createDtoFromJson(params.toString(), paramClass); - final R result = handler.handleRequest(endpointId, param); - final String resultString = DtoFactory.getInstance().toJson(result); - return new JsonParser().parse(resultString).getAsJsonObject(); - } - private JsonObject dispatch(String endpointId, RequestHandler handler, Class resultClass) { - final R result = handler.handleRequest(endpointId); + R result; + + if(paramClass != null) { + final P param = DtoFactory.getInstance().createDtoFromJson(params.toString(), paramClass); + result = handler.handleRequest(endpointId, param); + } else { + result = handler.handleRequest(endpointId); + } + + LOG.debug("Dispatch response: " + result); + + if(result instanceof Void) + return new JsonObject(); + else if(result instanceof String) { + JsonObject response = new JsonObject(); + response.addProperty("text", (String)result); + return response; + } else if(result instanceof Collection) { // list of DTO objects + JsonArray valueArray = new JsonArray(); + ((Collection)result).stream().filter(r -> r instanceof JsonSerializable).forEach(r -> { + String resultString = DtoFactory.getInstance().toJson(r); + valueArray.add(new JsonParser().parse(resultString).getAsJsonObject()); + }); + return valueArray; + } + + // DTO object otherwise final String resultString = DtoFactory.getInstance().toJson(result); return new JsonParser().parse(resultString).getAsJsonObject(); } - private JsonObject prepareResponse(String id, JsonObject result) { + + private JsonElement prepareResponse(String id, JsonElement result) { final JsonObject response = new JsonObject(); response.addProperty("jsonrpc", "2.0"); @@ -112,4 +141,13 @@ private JsonObject prepareResponse(String id, JsonObject result) { return response; } + + private String error(int code, String message) { + final JsonObject response = new JsonObject(); + + response.addProperty("code", code); + response.addProperty("message", message); + + return response.toString(); + } } diff --git a/wsagent/che-core-api-project/pom.xml b/wsagent/che-core-api-project/pom.xml index ef95ea88d4a..ca1b23431a1 100644 --- a/wsagent/che-core-api-project/pom.xml +++ b/wsagent/che-core-api-project/pom.xml @@ -22,6 +22,10 @@ jar Che Core :: API :: Project + + com.google.code.gson + gson + com.google.guava guava diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java index 5c771b59074..03d3535248c 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java @@ -25,10 +25,8 @@ import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.core.util.LineConsumerFactory; import org.eclipse.che.api.project.server.RegisteredProject.Problem; -import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.project.server.handlers.CreateProjectHandler; import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry; -import org.eclipse.che.api.project.server.importer.ProjectImportOutputWSLineConsumer; import org.eclipse.che.api.project.server.importer.ProjectImporter; import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry; import org.eclipse.che.api.project.server.type.AttributeValue; @@ -48,6 +46,7 @@ import org.eclipse.che.api.vfs.impl.file.event.detectors.ProjectTreeChangesDetector; import org.eclipse.che.api.vfs.search.Searcher; import org.eclipse.che.api.vfs.search.SearcherProvider; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -314,7 +313,7 @@ private RegisteredProject doCreateProject(ProjectConfig projectConfig, Map createBatchProjects(List projectConfigList, boolean rewrite) + public List createBatchProjects(List projectConfigList, boolean rewrite, ProjectOutputLineConsumerFactory lineConsumerFactory) throws BadRequestException, ConflictException, ForbiddenException, NotFoundException, ServerException, UnauthorizedException, IOException { projectTreeChangesDetector.suspend(); @@ -335,7 +334,7 @@ public List createBatchProjects(List new ProjectImportOutputWSLineConsumer(path, workspaceProjectsHolder.getWorkspaceId(), 300); +// final LineConsumerFactory outputOutputConsumerFactory = +// () -> new ProjectImportOutputWSLineConsumer(path, workspaceProjectsHolder.getWorkspaceId(), 300); String normalizePath = (path.startsWith("/")) ? path : "/".concat(path); FolderEntry folder = asFolder(normalizePath); @@ -509,7 +508,7 @@ private RegisteredProject doImportProject(String path, SourceStorage sourceStora } try { - importer.importSources(folder, sourceStorage, outputOutputConsumerFactory); + importer.importSources(folder, sourceStorage, lineConsumerFactory); } catch (final Exception e) { folder.remove(); throw e; diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java new file mode 100644 index 00000000000..c4fed9c3b9b --- /dev/null +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.project.server; + +import org.eclipse.che.api.core.util.LineConsumer; +import org.eclipse.che.api.core.util.LineConsumerFactory; +import org.eclipse.che.api.project.server.importer.ProjectImportOutputWSLineConsumer; + +/** + * LineConsumerFactory dedicated to project related operations long output + * extended standard factory with setProjectName method to make it possible + * change it runtime inside ProjectManager + * + * @author gazarenkov + */ +public class ProjectOutputLineConsumerFactory implements LineConsumerFactory { + + private String projectName; + private final String workspaceId; + private final int delay; + + public ProjectOutputLineConsumerFactory(String projectName, String workspaceId, int delay) { + this.projectName = projectName; + this.workspaceId = workspaceId; + this.delay = delay; + } + + public ProjectOutputLineConsumerFactory(String workspaceId, int delay) { + this(null, workspaceId, delay); + } + + public ProjectOutputLineConsumerFactory setProjectName(String projectName) { + this.projectName = projectName; + return this; + } + + @Override + public LineConsumer newLineConsumer() { + return new ProjectImportOutputWSLineConsumer(projectName, workspaceId, delay); + } +} diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java index a6f98a2fd0a..24d5574d176 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java @@ -31,6 +31,7 @@ import org.eclipse.che.api.core.rest.annotations.Description; import org.eclipse.che.api.core.rest.annotations.GenerateLink; import org.eclipse.che.api.core.rest.shared.dto.Link; +import org.eclipse.che.api.project.server.importer.ProjectImportOutputWSLineConsumer; import org.eclipse.che.api.project.server.notification.ProjectItemModifiedEvent; import org.eclipse.che.api.project.server.type.ProjectTypeResolution; import org.eclipse.che.api.project.shared.dto.CopyOptions; @@ -230,7 +231,11 @@ public List createBatchProjects( BadRequestException { List result = new ArrayList<>(projectConfigList.size()); - for (RegisteredProject registeredProject : projectManager.createBatchProjects(projectConfigList, rewrite)) { + final ProjectOutputLineConsumerFactory outputOutputConsumerFactory = new ProjectOutputLineConsumerFactory(workspace, 300); +// () -> new ProjectImportOutputWSLineConsumer("BATCH", workspace, 300); + + for (RegisteredProject registeredProject : projectManager.createBatchProjects(projectConfigList, rewrite, outputOutputConsumerFactory)) { + ProjectConfigDto projectConfig = injectProjectLinks(asDto(registeredProject)); result.add(projectConfig); @@ -356,7 +361,8 @@ public void importProject(@ApiParam(value = "Path in the project", required = tr ServerException, NotFoundException, BadRequestException { - projectManager.importProject(path, sourceStorage, force); + projectManager.importProject(path, sourceStorage, force, + () -> new ProjectImportOutputWSLineConsumer(path, workspace, 300)); } @POST diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java index e804e071681..40e0695735e 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumer.java @@ -10,11 +10,11 @@ *******************************************************************************/ package org.eclipse.che.api.project.server.importer; -import org.eclipse.che.api.core.util.LineConsumer; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.gson.JsonObject; +import org.eclipse.che.api.core.util.LineConsumer; import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; -import org.everrest.core.impl.provider.json.JsonUtils; import org.everrest.websockets.WSConnectionContext; import org.everrest.websockets.message.ChannelBroadcastMessage; import org.slf4j.Logger; @@ -81,9 +81,12 @@ public void writeLine(String line) throws IOException { protected void sendMessage(String line) { final ChannelBroadcastMessage bm = new ChannelBroadcastMessage(); - bm.setChannel("importProject:output:" + workspaceId + ":" + projectName); - bm.setBody(String.format("{\"num\":%d, \"line\":%s}", - lineCounter.getAndIncrement(), JsonUtils.getJsonString(line))); + bm.setChannel("importProject:output"); + JsonObject json = new JsonObject(); + json.addProperty("num", lineCounter.getAndIncrement()); + json.addProperty("line", line); + json.addProperty("project", projectName); + bm.setBody(json.toString()); sendMessageToWS(bm); } diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java index d3a61e6eed9..9ddc97b3d81 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectManagerWriteTest.java @@ -23,6 +23,7 @@ import org.eclipse.che.api.core.util.ValueHolder; import org.eclipse.che.api.project.server.RegisteredProject.Problem; import org.eclipse.che.api.project.server.handlers.CreateProjectHandler; +import org.eclipse.che.api.project.server.importer.ProjectImportOutputWSLineConsumer; import org.eclipse.che.api.project.server.importer.ProjectImporter; import org.eclipse.che.api.project.server.type.AttributeValue; import org.eclipse.che.api.project.server.type.BaseProjectType; @@ -87,7 +88,7 @@ public void testCreateBatchProjectsByConfigs() throws Exception { configs.add(config1); configs.add(config2); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(projectPath1); checkProjectExist(projectPath2); @@ -119,7 +120,7 @@ public void testCreateBatchProjectsByImportingSourceCode() throws Exception { configs.add(config1); configs.add(config2); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final RegisteredProject project1 = projectRegistry.getProject(projectPath1); final FolderEntry projectFolder1 = project1.getBaseFolder(); @@ -142,7 +143,7 @@ public void testCreateProjectWhenSourceCodeIsNotReachable() throws Exception { configs.add(config); try { - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("Exception should be thrown when source code is not reachable"); } catch (Exception e) { assertEquals(0, projectRegistry.getProjects().size()); @@ -186,7 +187,7 @@ public void shouldRollbackCreatingBatchProjects() throws Exception { configs.add(config3); //we be failed - we have not registered importer - source code will not be imported try { - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("We should rollback operation of creating batch projects when we could not get source code for at least one project"); } catch (Exception e) { assertEquals(0, projectRegistry.getProjects().size()); @@ -229,7 +230,7 @@ public void testCreateBatchProjectsWithInnerProject() throws Exception { configs.add(config1); configs.add(config2); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath); FolderEntry rootProjectFolder = rootProject.getBaseFolder(); @@ -280,7 +281,7 @@ public void testCreateBatchProjectsWithInnerProjectWhenInnerProjectContainsSourc configs.add(config2); configs.add(config1); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath); FolderEntry rootProjectFolder = rootProject.getBaseFolder(); @@ -306,7 +307,7 @@ public void testCreateBatchProjectsWithMixInnerProjects() throws Exception { // configs.add(createProjectConfigObject(path.substring(path.length() - 1, path.length()), path, BaseProjectType.ID, null)); } - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); for (String path : projectsPaths) { checkProjectExist(path); @@ -327,7 +328,7 @@ public void testCreateBatchProjectsWhenConfigContainsOnlyPath() configs.add(config1); configs.add(config2); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(projectPath1); checkProjectExist(projectPath2); @@ -344,7 +345,7 @@ public void shouldThrowBadRequestExceptionAtCreatingBatchProjectsWhenConfigNotCo configs.add(config); try { - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("BadRequestException should be thrown : path field is mandatory"); } catch (BadRequestException e) { assertEquals(0, projectRegistry.getProjects().size()); @@ -359,12 +360,12 @@ public void shouldThrowConflictExceptionAtCreatingBatchProjectsWhenProjectWithPa final List configs = new ArrayList<>(1); configs.add(config); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(path); assertEquals(1, projectRegistry.getProjects().size()); try { - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("ConflictException should be thrown : Project config with the same path is already exists"); } catch (ConflictException e) { assertEquals(1, projectRegistry.getProjects().size()); @@ -381,7 +382,7 @@ public void shouldCreateParentFolderAtCreatingProjectWhenParentDoesNotExist() th final List configs = new ArrayList<>(2); configs.add(config); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(nonExistentParentPath); checkProjectExist(innerProjectPath); @@ -411,7 +412,7 @@ public void shouldRewriteProjectAtCreatingBatchProjectsWhenProjectAlreadyExist() final List configs = new ArrayList<>(1); configs.add(config1); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final FolderEntry projectFolder1 = projectRegistry.getProject(projectPath).getBaseFolder(); checkProjectExist(projectPath); @@ -420,7 +421,7 @@ public void shouldRewriteProjectAtCreatingBatchProjectsWhenProjectAlreadyExist() configs.clear(); configs.add(config2); - pm.createBatchProjects(configs, true); + pm.createBatchProjects(configs, true, new ProjectOutputLineConsumerFactory("ws", 300)); final FolderEntry projectFolder2 = projectRegistry.getProject(projectPath).getBaseFolder(); checkProjectExist(projectPath); @@ -442,7 +443,7 @@ public void shouldSetBlankTypeAtCreatingBatchProjectsWhenConfigContainsUnregiste final List configs = new ArrayList<>(1); configs.add(config); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final RegisteredProject project = projectRegistry.getProject(projectPath); final List problems = project.getProblems(); @@ -466,7 +467,7 @@ public void shouldCreateBatchProjectsWithoutMixinPTWhenThisOneIsUnregistered() final List configs = new ArrayList<>(1); configs.add(config); - pm.createBatchProjects(configs, false); + pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final RegisteredProject project = projectRegistry.getProject(projectPath); final List problems = project.getProblems(); @@ -837,7 +838,7 @@ public void testImportProject() throws Exception { SourceStorage sourceConfig = DtoFactory.newDto(SourceStorageDto.class).withType(importType); - pm.importProject("/testImportProject", sourceConfig, false); + pm.importProject("/testImportProject", sourceConfig, false, () -> new ProjectImportOutputWSLineConsumer("BATCH", "ws", 300)); RegisteredProject project = projectRegistry.getProject("/testImportProject"); @@ -859,7 +860,7 @@ public void testRemoveFolderForSourcesWhenImportingProjectIsFailed() throws Exce SourceStorage sourceConfig = DtoFactory.newDto(SourceStorageDto.class).withType(importType); try { - pm.importProject(projectPath, sourceConfig, false); + pm.importProject(projectPath, sourceConfig, false, () -> new ProjectImportOutputWSLineConsumer("testImportProject", "ws", 300)); } catch (Exception e) { } @@ -872,7 +873,7 @@ public void testImportProjectWithoutImporterFailed() throws Exception { SourceStorage sourceConfig = DtoFactory.newDto(SourceStorageDto.class).withType("nothing"); try { - pm.importProject("/testImportProject", sourceConfig, false); + pm.importProject("/testImportProject", sourceConfig, false, () -> new ProjectImportOutputWSLineConsumer("testImportProject", "ws", 300)); fail("NotFoundException: Unable import sources project from 'null'. Sources type 'nothing' is not supported."); } catch (NotFoundException e) { } diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumerTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumerTest.java index 93c911c419d..6bb5b0dc007 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumerTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/importer/ProjectImportOutputWSLineConsumerTest.java @@ -34,7 +34,7 @@ public void shouldSendMessage() { //then verify(consumer).sendMessageToWS(argumentCaptor.capture()); - assertEquals(argumentCaptor.getValue().getChannel(), "importProject:output:workspace:project"); - assertEquals(argumentCaptor.getValue().getBody(), "{\"num\":1, \"line\":\"message\"}"); + assertEquals(argumentCaptor.getValue().getChannel(), "importProject:output"); + assertEquals(argumentCaptor.getValue().getBody(), "{\"num\":1,\"line\":\"message\",\"project\":\"project\"}"); } } From ca82851bd314ea6384b5e47667432d4e5ca2711b Mon Sep 17 00:00:00 2001 From: Roman Nikitenko Date: Fri, 2 Dec 2016 18:16:27 +0200 Subject: [PATCH 51/74] Change identifier for import project channel --- .../core/jsonrpc/impl/RequestDispatcher.java | 14 ++--- .../create-project.controller.ts | 4 +- .../che/ide/CoreLocalizationConstant.java | 2 +- .../ProjectNotificationSubscriberImpl.java | 58 ++++++++----------- .../ide/CoreLocalizationConstant.properties | 2 +- .../api/project/server/ProjectManager.java | 4 -- .../ProjectOutputLineConsumerFactory.java | 6 +- .../api/project/server/ProjectService.java | 1 - 8 files changed, 37 insertions(+), 54 deletions(-) diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java index 21779359c2e..b9c2b1fc76d 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/impl/RequestDispatcher.java @@ -64,7 +64,7 @@ public void dispatch(String endpointId, JsonObject incomingJson) { LOG.debug("Extracted request method: " + method); final RequestHandler handler = handlers.get(method); - if(handler == null) { + if (handler == null) { LOG.error("Handler not found: " + method); // TODO make a centralized standard errors structure transmitter.transmit(endpointId, error(-32601, "Method not found: " + method)); @@ -100,24 +100,24 @@ private JsonElement response(String endpointId, Class

    paramClass, Class resultClass) { - R result; + final R result; - if(paramClass != null) { + if (paramClass != null) { final P param = DtoFactory.getInstance().createDtoFromJson(params.toString(), paramClass); result = handler.handleRequest(endpointId, param); } else { result = handler.handleRequest(endpointId); } - LOG.debug("Dispatch response: " + result); + LOG.debug("Dispatch response: ", result); - if(result instanceof Void) + if (result instanceof Void) return new JsonObject(); - else if(result instanceof String) { + else if (result instanceof String) { JsonObject response = new JsonObject(); response.addProperty("text", (String)result); return response; - } else if(result instanceof Collection) { // list of DTO objects + } else if (result instanceof Collection) { // list of DTO objects JsonArray valueArray = new JsonArray(); ((Collection)result).stream().filter(r -> r instanceof JsonSerializable).forEach(r -> { String resultString = DtoFactory.getInstance().toJson(r); diff --git a/dashboard/src/app/projects/create-project/create-project.controller.ts b/dashboard/src/app/projects/create-project/create-project.controller.ts index 5f71d8e2799..61463511546 100755 --- a/dashboard/src/app/projects/create-project/create-project.controller.ts +++ b/dashboard/src/app/projects/create-project/create-project.controller.ts @@ -561,7 +561,7 @@ export class CreateProjectController { this.createProjectSvc.setCurrentProgressStep(3); var promise; - var channel = null; + let channel: string = null; // select mode (create or import) if (this.selectSourceOption === 'select-source-new' && this.templatesChoice === 'templates-wizard') { @@ -578,7 +578,7 @@ export class CreateProjectController { } // websocket channel - channel = 'importProject:output:' + workspaceId + ':' + projectName; + channel = 'importProject:output'; // on import bus.subscribe(channel, (message: any) => { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/CoreLocalizationConstant.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/CoreLocalizationConstant.java index 08f75563675..c5b736cf34a 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/CoreLocalizationConstant.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/CoreLocalizationConstant.java @@ -263,7 +263,7 @@ public interface CoreLocalizationConstant extends Messages { String importProjectButton(); @Key("importProject.importing") - String importingProject(); + String importingProject(String projectName); @Key("importProject.uriFieldTitle") String importProjectUriFieldTitle(); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectNotificationSubscriberImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectNotificationSubscriberImpl.java index 85231ab0d6c..c7e18a3b041 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectNotificationSubscriberImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectNotificationSubscriberImpl.java @@ -10,8 +10,9 @@ *******************************************************************************/ package org.eclipse.che.ide.projectimport.wizard; -import com.google.gwt.json.client.JSONObject; -import com.google.gwt.json.client.JSONParser; +import elemental.json.Json; +import elemental.json.JsonObject; + import com.google.inject.Inject; import com.google.inject.Singleton; @@ -19,16 +20,14 @@ import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.CoreLocalizationConstant; -import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.machine.WsAgentStateController; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.api.project.wizard.ProjectNotificationSubscriber; -import org.eclipse.che.ide.commons.exception.UnmarshallerException; import org.eclipse.che.ide.util.loging.Log; -import org.eclipse.che.ide.websocket.Message; import org.eclipse.che.ide.websocket.MessageBus; import org.eclipse.che.ide.websocket.WebSocketException; +import org.eclipse.che.ide.websocket.rest.StringUnmarshallerWS; import org.eclipse.che.ide.websocket.rest.SubscriptionHandler; import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; @@ -48,7 +47,6 @@ public class ProjectNotificationSubscriberImpl implements ProjectNotificationSub private final Operation logErrorHandler; private final CoreLocalizationConstant locale; private final NotificationManager notificationManager; - private final String workspaceId; private final WsAgentStateController wsAgentStateController; private String wsChannel; @@ -58,12 +56,10 @@ public class ProjectNotificationSubscriberImpl implements ProjectNotificationSub @Inject public ProjectNotificationSubscriberImpl(CoreLocalizationConstant locale, - AppContext appContext, NotificationManager notificationManager, WsAgentStateController wsAgentStateController) { this.locale = locale; this.notificationManager = notificationManager; - this.workspaceId = appContext.getWorkspace().getId(); this.wsAgentStateController = wsAgentStateController; this.logErrorHandler = new Operation() { @Override @@ -75,19 +71,32 @@ public void apply(PromiseError error) throws OperationException { @Override public void subscribe(final String projectName) { - notification = notificationManager.notify(locale.importingProject(), PROGRESS, FLOAT_MODE); + notification = notificationManager.notify(locale.importingProject(projectName), PROGRESS, FLOAT_MODE); subscribe(projectName, notification); } @Override - public void subscribe(final String projectName, final StatusNotification existingNotification) { - this.projectName = projectName; - this.wsChannel = "importProject:output:" + workspaceId + ":" + projectName; + public void subscribe(final String name, final StatusNotification existingNotification) { + this.projectName = name; + this.wsChannel = "importProject:output"; this.notification = existingNotification; - this.subscriptionHandler = new SubscriptionHandler(new LineUnmarshaller()) { + this.subscriptionHandler = new SubscriptionHandler(new StringUnmarshallerWS()) { @Override protected void onMessageReceived(String result) { - notification.setContent(result); + JsonObject jsonObject = Json.parse(result); + + if (jsonObject == null) { + return; + } + + if (jsonObject.hasKey("project")) { + projectName = jsonObject.getString("project"); + notification.setTitle(locale.importingProject(projectName)); + } + + if (jsonObject.hasKey("line")) { + notification.setContent(jsonObject.getString("line")); + } } @Override @@ -153,25 +162,4 @@ public void apply(MessageBus messageBus) throws OperationException { } }).catchError(logErrorHandler); } - - static class LineUnmarshaller implements org.eclipse.che.ide.websocket.rest.Unmarshallable { - private String line; - - @Override - public void unmarshal(Message response) throws UnmarshallerException { - JSONObject jsonObject = JSONParser.parseStrict(response.getBody()).isObject(); - if (jsonObject == null) { - return; - } - if (jsonObject.containsKey("line")) { - line = jsonObject.get("line").isString().stringValue(); - } - } - - @Override - public String getPayload() { - return line; - } - } - } diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties index b24fbb34bc7..a84fad97cc4 100644 --- a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties @@ -145,7 +145,7 @@ importLocalProject.openZipTitle = Select Zip archive to import: importProject.importButton = Import importProject.uriFieldTitle = URL: importProject.viewTitle = Import project -importProject.importing = Importing project(s) +importProject.importing = Importing project {0} importProject.message.success = Project {0} imported importProject.message.failure = Failed to import project {0} importProject.message.startWithWhiteSpace = The url can not start with a whitespace. diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java index 03d3535248c..b2c40a2ec5e 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectManager.java @@ -493,10 +493,6 @@ private RegisteredProject doImportProject(String path, SourceStorage sourceStora sourceStorage.getLocation(), sourceStorage.getType())); } - // Preparing websocket output publisher to broadcast output of import process to the ide clients while importing -// final LineConsumerFactory outputOutputConsumerFactory = -// () -> new ProjectImportOutputWSLineConsumer(path, workspaceProjectsHolder.getWorkspaceId(), 300); - String normalizePath = (path.startsWith("/")) ? path : "/".concat(path); FolderEntry folder = asFolder(normalizePath); if (folder != null && !rewrite) { diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java index c4fed9c3b9b..89ca29d76a6 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectOutputLineConsumerFactory.java @@ -15,7 +15,7 @@ import org.eclipse.che.api.project.server.importer.ProjectImportOutputWSLineConsumer; /** - * LineConsumerFactory dedicated to project related operations long output + * {@link LineConsumerFactory} dedicated to project related operations long output * extended standard factory with setProjectName method to make it possible * change it runtime inside ProjectManager * @@ -23,9 +23,9 @@ */ public class ProjectOutputLineConsumerFactory implements LineConsumerFactory { - private String projectName; + private String projectName; private final String workspaceId; - private final int delay; + private final int delay; public ProjectOutputLineConsumerFactory(String projectName, String workspaceId, int delay) { this.projectName = projectName; diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java index 24d5574d176..e711a5422bd 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectService.java @@ -232,7 +232,6 @@ public List createBatchProjects( List result = new ArrayList<>(projectConfigList.size()); final ProjectOutputLineConsumerFactory outputOutputConsumerFactory = new ProjectOutputLineConsumerFactory(workspace, 300); -// () -> new ProjectImportOutputWSLineConsumer("BATCH", workspace, 300); for (RegisteredProject registeredProject : projectManager.createBatchProjects(projectConfigList, rewrite, outputOutputConsumerFactory)) { From e5abb1e457c57798c561baf7fa2c8bfa2b8e5fc0 Mon Sep 17 00:00:00 2001 From: Florent BENOIT Date: Tue, 6 Dec 2016 15:39:51 +0100 Subject: [PATCH 52/74] Fix #3276 Use root user by default to start cha-server another PR is about specifying how to run cha-server with a custom uid/gid Change-Id: Ib2635dc9b8364b92caa768dc8e4de0603cbcf14f Signed-off-by: Florent BENOIT --- Dockerfile | 9 --------- assembly/assembly-main/src/assembly/bin/docker.sh | 4 ---- 2 files changed, 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2bc9aa3d13b..6405f8081a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,18 +34,9 @@ RUN echo "http://dl-4.alpinelinux.org/alpine/edge/community" >> /etc/apk/reposit apk add --update ca-certificates curl openssl openjdk8 sudo bash && \ curl -sSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}" -o /usr/bin/docker && \ chmod +x /usr/bin/docker && \ - addgroup -S user -g 1000 && \ - adduser -S user -h /home/user -s /bin/bash -G root -u 1000 -D && \ - addgroup -S docker -g 101 && \ - adduser user docker && \ - adduser user user && \ - adduser user users && \ - addgroup -g 50 -S docker4mac && \ - adduser user docker4mac && \ echo "%root ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \ rm -rf /tmp/* /var/cache/apk/* EXPOSE 8000 8080 -USER user ADD assembly/assembly-main/target/eclipse-che-*/eclipse-che-* /home/user/che/ ENTRYPOINT ["/home/user/che/bin/docker.sh"] diff --git a/assembly/assembly-main/src/assembly/bin/docker.sh b/assembly/assembly-main/src/assembly/bin/docker.sh index 0b6f06fc5c5..1a0e4fb302e 100644 --- a/assembly/assembly-main/src/assembly/bin/docker.sh +++ b/assembly/assembly-main/src/assembly/bin/docker.sh @@ -121,10 +121,6 @@ init() { export CHE_WORKSPACE_STORAGE_CREATE_FOLDERS=false fi - # Ensure that the user "user" has permissions for CHE_HOME and CHE_DATA - sudo chown -R user:user ${CHE_HOME} - sudo chown -R user:user ${CHE_DATA} - # Move files from /lib to /lib-copy. This puts files onto the host. rm -rf ${CHE_DATA}/lib/* mkdir -p ${CHE_DATA}/lib From 3896cb0d3bb5016eedd991c93203e8560cc17d48 Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 14:04:46 +0200 Subject: [PATCH 53/74] RELEASE: set tag versions (#3306) --- dockerfiles/action/Dockerfile | 2 +- dockerfiles/cli/Dockerfile | 2 +- dockerfiles/cli/version/5.0.0-M8/images | 4 ++++ dockerfiles/cli/version/latest.ver | 2 +- dockerfiles/dir/Dockerfile | 2 +- dockerfiles/lib/dto-pom.xml | 4 ++-- dockerfiles/test/Dockerfile | 2 +- 7 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 dockerfiles/cli/version/5.0.0-M8/images diff --git a/dockerfiles/action/Dockerfile b/dockerfiles/action/Dockerfile index fb41f7e3290..7ec902cd3b2 100644 --- a/dockerfiles/action/Dockerfile +++ b/dockerfiles/action/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action [command] -FROM eclipse/che-lib:nightly +FROM eclipse/che-lib:5.0.0-M8 ENTRYPOINT ["node", "/che-lib/index.js", "che-action"] diff --git a/dockerfiles/cli/Dockerfile b/dockerfiles/cli/Dockerfile index 6c84027ec7b..530565128eb 100644 --- a/dockerfiles/cli/Dockerfile +++ b/dockerfiles/cli/Dockerfile @@ -9,7 +9,7 @@ # # use: # docker run -v $(pwd):/che eclipse/che-cli [command] -FROM eclipse/che-base:nightly +FROM eclipse/che-base:5.0.0-M8 COPY scripts /scripts/ COPY version /version/ diff --git a/dockerfiles/cli/version/5.0.0-M8/images b/dockerfiles/cli/version/5.0.0-M8/images new file mode 100644 index 00000000000..62f7695b92d --- /dev/null +++ b/dockerfiles/cli/version/5.0.0-M8/images @@ -0,0 +1,4 @@ +IMAGE_PUPPET=puppet/puppet-agent-alpine:4.6.2 +IMAGE_REGISTRY=registry:2.5.0 +IMAGE_INIT=eclipse/che-init:5.0.0-M8 +IMAGE_CHE=eclipse/che-server:5.0.0-M8 diff --git a/dockerfiles/cli/version/latest.ver b/dockerfiles/cli/version/latest.ver index f981d9fdbf2..1e78548c440 100644 --- a/dockerfiles/cli/version/latest.ver +++ b/dockerfiles/cli/version/latest.ver @@ -1 +1 @@ -5.0.0-M7 \ No newline at end of file +5.0.0-M8 \ No newline at end of file diff --git a/dockerfiles/dir/Dockerfile b/dockerfiles/dir/Dockerfile index 26c1d378df4..61c4c2118e7 100644 --- a/dockerfiles/dir/Dockerfile +++ b/dockerfiles/dir/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-dir [command] -FROM eclipse/che-lib:nightly +FROM eclipse/che-lib:5.0.0-M8 ENTRYPOINT ["node", "/che-lib/index.js", "che-dir"] diff --git a/dockerfiles/lib/dto-pom.xml b/dockerfiles/lib/dto-pom.xml index ecdb5515ab4..4108a8f7a65 100644 --- a/dockerfiles/lib/dto-pom.xml +++ b/dockerfiles/lib/dto-pom.xml @@ -17,13 +17,13 @@ maven-depmgt-pom org.eclipse.che.depmgt - 5.0.0-M7 + 5.0.0-M8 dto-typescript pom Che TypeScript DTO - 5.0.0-M7 + 5.0.0-M8 diff --git a/dockerfiles/test/Dockerfile b/dockerfiles/test/Dockerfile index 260b89138c8..6e95735574d 100644 --- a/dockerfiles/test/Dockerfile +++ b/dockerfiles/test/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-test [command] -FROM eclipse/che-lib:nightly +FROM eclipse/che-lib:5.0.0-M8 ENTRYPOINT ["node", "/che-lib/index.js", "che-test"] From 423c0b6e8db2c76851ee136f4167f60cbdeb68df Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 12:11:36 +0000 Subject: [PATCH 54/74] RELEASE:Set tag of parent pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 003e7e3e2fa..d9a83044037 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ maven-depmgt-pom org.eclipse.che.depmgt - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che che-parent From 9b9506362b24c9c2fd21fd028836a8f21635dbb5 Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 12:11:46 +0000 Subject: [PATCH 55/74] RELEASE:Set tag versions --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d9a83044037..b698b2a6d15 100644 --- a/pom.xml +++ b/pom.xml @@ -40,8 +40,8 @@ https://github.com/eclipse/che - 5.0.0-M8-SNAPSHOT - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 + 5.0.0-M8 1.0-beta2 From 1c15a44844c96ff9fd45a74a2f6b8919f07f239b Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 12:34:25 +0000 Subject: [PATCH 56/74] [maven-release-plugin] prepare release 5.0.0-M8 --- assembly/assembly-ide-war/pom.xml | 2 +- assembly/assembly-main/pom.xml | 2 +- assembly/assembly-wsagent-server/pom.xml | 2 +- assembly/assembly-wsagent-war/pom.xml | 2 +- assembly/assembly-wsmaster-war/pom.xml | 2 +- assembly/pom.xml | 4 ++-- core/che-core-api-core/pom.xml | 2 +- core/che-core-api-dto-maven-plugin/pom.xml | 2 +- core/che-core-api-dto/pom.xml | 2 +- core/che-core-api-model/pom.xml | 2 +- core/che-core-db-vendor-h2/pom.xml | 2 +- core/che-core-db-vendor-postgresql/pom.xml | 2 +- core/che-core-db/pom.xml | 2 +- core/che-core-typescript-dto-maven-plugin/pom.xml | 2 +- core/commons/che-core-commons-annotations/pom.xml | 2 +- core/commons/che-core-commons-inject/pom.xml | 2 +- core/commons/che-core-commons-json/pom.xml | 2 +- core/commons/che-core-commons-lang/pom.xml | 2 +- core/commons/che-core-commons-schedule/pom.xml | 2 +- core/commons/che-core-commons-test/pom.xml | 2 +- core/commons/che-core-commons-xml/pom.xml | 2 +- core/commons/pom.xml | 2 +- core/pom.xml | 4 ++-- dashboard/pom.xml | 4 ++-- ide/che-core-dyna-provider-generator-maven-plugin/pom.xml | 2 +- ide/che-core-ide-api/pom.xml | 2 +- ide/che-core-ide-app/pom.xml | 2 +- ide/che-core-ide-generators/pom.xml | 2 +- ide/che-core-ide-stacks/pom.xml | 2 +- ide/che-core-ide-templates/pom.xml | 2 +- ide/che-core-ide-ui/pom.xml | 2 +- ide/commons-gwt/pom.xml | 2 +- ide/pom.xml | 2 +- plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml | 2 +- plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml | 2 +- plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml | 2 +- plugins/plugin-cpp/pom.xml | 2 +- plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml | 2 +- plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml | 2 +- plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml | 2 +- plugins/plugin-csharp/pom.xml | 2 +- plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml | 2 +- plugins/plugin-dashboard/pom.xml | 2 +- plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml | 2 +- plugins/plugin-debugger/pom.xml | 2 +- plugins/plugin-docker/che-plugin-docker-client/pom.xml | 2 +- plugins/plugin-docker/che-plugin-docker-compose/pom.xml | 2 +- plugins/plugin-docker/che-plugin-docker-machine/pom.xml | 2 +- plugins/plugin-docker/pom.xml | 2 +- plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml | 2 +- plugins/plugin-gdb/che-plugin-gdb-server/pom.xml | 2 +- plugins/plugin-gdb/pom.xml | 2 +- plugins/plugin-git/che-plugin-git-ext-git/pom.xml | 2 +- plugins/plugin-git/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-ide/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-oauth2/pom.xml | 2 +- .../plugin-github/che-plugin-github-provider-github/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-server/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-shared/pom.xml | 2 +- plugins/plugin-github/pom.xml | 2 +- plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml | 2 +- plugins/plugin-gwt/pom.xml | 2 +- plugins/plugin-help/che-plugin-help-ext-client/pom.xml | 2 +- plugins/plugin-help/pom.xml | 2 +- .../plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml | 2 +- .../che-plugin-java-debugger-server/pom.xml | 2 +- plugins/plugin-java-debugger/pom.xml | 2 +- .../che-java-testing-classpath-maven-server/pom.xml | 2 +- .../che-java-testing-classpath/pom.xml | 2 +- .../che-java-testing-core/che-java-testing-core-ide/pom.xml | 2 +- .../che-java-testing-core-server/pom.xml | 2 +- .../che-java-testing-core-shared/pom.xml | 2 +- plugins/plugin-java-test-runner/che-java-testing-core/pom.xml | 2 +- .../che-java-testing-junit/che-java-testing-junit-ide/pom.xml | 2 +- .../che-java-testing-junit-server/pom.xml | 2 +- .../che-java-testing-junit-shared/pom.xml | 2 +- .../plugin-java-test-runner/che-java-testing-junit/pom.xml | 2 +- .../che-java-testing-testng-ide/pom.xml | 2 +- .../che-java-testing-testng-server/pom.xml | 2 +- .../plugin-java-test-runner/che-java-testing-testng/pom.xml | 2 +- plugins/plugin-java-test-runner/pom.xml | 2 +- .../org-eclipse-core-filebuffers/pom.xml | 2 +- .../org-eclipse-core-filesystem/pom.xml | 2 +- .../org-eclipse-core-resources/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml | 2 +- .../org-eclipse-ltk-core-refactoring/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-search/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml | 2 +- .../che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml | 2 +- .../che-plugin-java-plain-server/pom.xml | 2 +- .../che-plugin-java-plain-shared/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-plain/pom.xml | 2 +- plugins/plugin-java/pom.xml | 2 +- plugins/plugin-json/che-plugin-json-server/pom.xml | 2 +- plugins/plugin-json/pom.xml | 2 +- .../che-plugin-languageserver-ide/pom.xml | 2 +- plugins/plugin-languageserver/pom.xml | 2 +- plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml | 2 +- plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml | 2 +- plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml | 2 +- plugins/plugin-machine/pom.xml | 2 +- .../plugin-maven/che-plugin-maven-generator-archetype/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-ide/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-server/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-shared/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-tools/pom.xml | 2 +- plugins/plugin-maven/maven-server/maven-server-api/pom.xml | 2 +- plugins/plugin-maven/maven-server/maven-server-impl/pom.xml | 2 +- plugins/plugin-maven/maven-server/pom.xml | 2 +- plugins/plugin-maven/pom.xml | 2 +- .../che-plugin-nodejs-debugger-ide/pom.xml | 2 +- .../che-plugin-nodejs-debugger-server/pom.xml | 2 +- plugins/plugin-nodejs-debugger/pom.xml | 2 +- plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml | 2 +- plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml | 2 +- plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml | 2 +- plugins/plugin-nodejs/pom.xml | 2 +- plugins/plugin-orion/che-plugin-orion-compare/pom.xml | 2 +- plugins/plugin-orion/che-plugin-orion-editor/pom.xml | 2 +- plugins/plugin-orion/pom.xml | 2 +- plugins/plugin-php/che-plugin-php-lang-ide/pom.xml | 2 +- plugins/plugin-php/che-plugin-php-lang-server/pom.xml | 2 +- plugins/plugin-php/che-plugin-php-lang-shared/pom.xml | 2 +- plugins/plugin-php/pom.xml | 2 +- plugins/plugin-product-info/pom.xml | 2 +- plugins/plugin-python/che-plugin-python-lang-ide/pom.xml | 2 +- plugins/plugin-python/che-plugin-python-lang-server/pom.xml | 2 +- plugins/plugin-python/che-plugin-python-lang-shared/pom.xml | 2 +- plugins/plugin-python/pom.xml | 2 +- plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml | 2 +- plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml | 2 +- plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml | 2 +- plugins/plugin-sdk/pom.xml | 2 +- plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml | 2 +- plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml | 2 +- plugins/plugin-ssh-key/pom.xml | 2 +- plugins/plugin-ssh-machine/pom.xml | 2 +- plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml | 2 +- plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml | 2 +- plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml | 2 +- plugins/plugin-svn/pom.xml | 2 +- plugins/plugin-web/che-plugin-web-ext-web/pom.xml | 2 +- plugins/plugin-web/pom.xml | 2 +- plugins/pom.xml | 4 ++-- pom.xml | 4 ++-- samples/pom.xml | 4 ++-- .../che-sample-plugin-actions-ide/pom.xml | 2 +- samples/sample-plugin-actions/pom.xml | 2 +- .../che-sample-plugin-embedjs-ide/pom.xml | 2 +- samples/sample-plugin-embedjs/pom.xml | 2 +- .../che-sample-plugin-filetype-ide/pom.xml | 2 +- samples/sample-plugin-filetype/pom.xml | 2 +- samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml | 2 +- .../sample-plugin-json/che-sample-plugin-json-server/pom.xml | 2 +- .../sample-plugin-json/che-sample-plugin-json-shared/pom.xml | 2 +- samples/sample-plugin-json/pom.xml | 2 +- .../che-sample-plugin-nativeaccess-ide/pom.xml | 2 +- samples/sample-plugin-nativeaccess/pom.xml | 2 +- .../sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml | 2 +- samples/sample-plugin-parts/pom.xml | 2 +- .../che-sample-plugin-serverservice-ide/pom.xml | 2 +- .../che-sample-plugin-serverservice-server/pom.xml | 2 +- samples/sample-plugin-serverservice/pom.xml | 2 +- .../sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml | 2 +- .../che-sample-plugin-wizard-server/pom.xml | 2 +- .../che-sample-plugin-wizard-shared/pom.xml | 2 +- samples/sample-plugin-wizard/pom.xml | 2 +- wsagent/che-core-api-debug-shared/pom.xml | 2 +- wsagent/che-core-api-debug/pom.xml | 2 +- wsagent/che-core-api-git-shared/pom.xml | 2 +- wsagent/che-core-api-git/pom.xml | 2 +- wsagent/che-core-api-languageserver-shared/pom.xml | 2 +- wsagent/che-core-api-languageserver/pom.xml | 2 +- wsagent/che-core-api-project-shared/pom.xml | 2 +- wsagent/che-core-api-project/pom.xml | 4 ++-- wsagent/che-core-git-impl-jgit/pom.xml | 2 +- wsagent/pom.xml | 4 ++-- wsagent/wsagent-local/pom.xml | 2 +- wsmaster/che-core-api-account/pom.xml | 2 +- wsmaster/che-core-api-agent-shared/pom.xml | 2 +- wsmaster/che-core-api-agent/pom.xml | 2 +- wsmaster/che-core-api-auth/pom.xml | 2 +- wsmaster/che-core-api-factory-shared/pom.xml | 2 +- wsmaster/che-core-api-factory/pom.xml | 2 +- wsmaster/che-core-api-machine-shared/pom.xml | 2 +- wsmaster/che-core-api-machine/pom.xml | 2 +- wsmaster/che-core-api-project-templates-shared/pom.xml | 2 +- wsmaster/che-core-api-project-templates/pom.xml | 2 +- wsmaster/che-core-api-ssh-shared/pom.xml | 2 +- wsmaster/che-core-api-ssh/pom.xml | 2 +- wsmaster/che-core-api-user-shared/pom.xml | 2 +- wsmaster/che-core-api-user/pom.xml | 2 +- wsmaster/che-core-api-workspace-shared/pom.xml | 2 +- wsmaster/che-core-api-workspace/pom.xml | 2 +- wsmaster/che-core-sql-schema/pom.xml | 2 +- wsmaster/integration-tests/cascade-removal/pom.xml | 2 +- wsmaster/integration-tests/pom.xml | 2 +- wsmaster/integration-tests/postgresql-tck/pom.xml | 2 +- wsmaster/pom.xml | 4 ++-- wsmaster/wsmaster-local/pom.xml | 2 +- 206 files changed, 215 insertions(+), 215 deletions(-) diff --git a/assembly/assembly-ide-war/pom.xml b/assembly/assembly-ide-war/pom.xml index 397dc7a2ff3..b64ef70c81f 100644 --- a/assembly/assembly-ide-war/pom.xml +++ b/assembly/assembly-ide-war/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 assembly-ide-war war diff --git a/assembly/assembly-main/pom.xml b/assembly/assembly-main/pom.xml index 8590fd26cc9..e80f11359bf 100644 --- a/assembly/assembly-main/pom.xml +++ b/assembly/assembly-main/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 assembly-main pom diff --git a/assembly/assembly-wsagent-server/pom.xml b/assembly/assembly-wsagent-server/pom.xml index 248796b0799..e518e6df5eb 100644 --- a/assembly/assembly-wsagent-server/pom.xml +++ b/assembly/assembly-wsagent-server/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 assembly-wsagent-server pom diff --git a/assembly/assembly-wsagent-war/pom.xml b/assembly/assembly-wsagent-war/pom.xml index 03440bb329c..65dd063b1c5 100644 --- a/assembly/assembly-wsagent-war/pom.xml +++ b/assembly/assembly-wsagent-war/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 assembly-wsagent-war war diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index 4c4a934035c..d8348ccd78f 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 assembly-wsmaster-war war diff --git a/assembly/pom.xml b/assembly/pom.xml index 8812c65f1cb..d84809e1ac0 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml org.eclipse.che che-assembly-parent - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 pom Che IDE :: Parent diff --git a/core/che-core-api-core/pom.xml b/core/che-core-api-core/pom.xml index 5390e07f838..d8a60c5b07f 100644 --- a/core/che-core-api-core/pom.xml +++ b/core/che-core-api-core/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-core jar diff --git a/core/che-core-api-dto-maven-plugin/pom.xml b/core/che-core-api-dto-maven-plugin/pom.xml index 56be45d3309..1a065c01a81 100644 --- a/core/che-core-api-dto-maven-plugin/pom.xml +++ b/core/che-core-api-dto-maven-plugin/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-dto-maven-plugin maven-plugin diff --git a/core/che-core-api-dto/pom.xml b/core/che-core-api-dto/pom.xml index ad9b4a73804..b9481af258d 100644 --- a/core/che-core-api-dto/pom.xml +++ b/core/che-core-api-dto/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-dto jar diff --git a/core/che-core-api-model/pom.xml b/core/che-core-api-model/pom.xml index 1406e520c8f..db14133e136 100644 --- a/core/che-core-api-model/pom.xml +++ b/core/che-core-api-model/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-model jar diff --git a/core/che-core-db-vendor-h2/pom.xml b/core/che-core-db-vendor-h2/pom.xml index 4a4fd45a745..d742a0dd33f 100644 --- a/core/che-core-db-vendor-h2/pom.xml +++ b/core/che-core-db-vendor-h2/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-db-vendor-h2 Che Core :: DB :: Vendor H2 diff --git a/core/che-core-db-vendor-postgresql/pom.xml b/core/che-core-db-vendor-postgresql/pom.xml index 67e01d807b6..5440bf661d8 100644 --- a/core/che-core-db-vendor-postgresql/pom.xml +++ b/core/che-core-db-vendor-postgresql/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-db-vendor-postgresql Che Core :: DB :: Vendor PostgreSQL diff --git a/core/che-core-db/pom.xml b/core/che-core-db/pom.xml index e55dff20c90..a2758240c0b 100644 --- a/core/che-core-db/pom.xml +++ b/core/che-core-db/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-db Che Core :: DB diff --git a/core/che-core-typescript-dto-maven-plugin/pom.xml b/core/che-core-typescript-dto-maven-plugin/pom.xml index d396414e75c..cb34c282edd 100644 --- a/core/che-core-typescript-dto-maven-plugin/pom.xml +++ b/core/che-core-typescript-dto-maven-plugin/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core che-core-typescript-dto-maven-plugin diff --git a/core/commons/che-core-commons-annotations/pom.xml b/core/commons/che-core-commons-annotations/pom.xml index e95e914b812..4e8e6acb474 100644 --- a/core/commons/che-core-commons-annotations/pom.xml +++ b/core/commons/che-core-commons-annotations/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-annotations jar diff --git a/core/commons/che-core-commons-inject/pom.xml b/core/commons/che-core-commons-inject/pom.xml index d5eea1d9260..2e8dd60df36 100644 --- a/core/commons/che-core-commons-inject/pom.xml +++ b/core/commons/che-core-commons-inject/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-inject jar diff --git a/core/commons/che-core-commons-json/pom.xml b/core/commons/che-core-commons-json/pom.xml index 29e1480de6c..150f9c645c7 100644 --- a/core/commons/che-core-commons-json/pom.xml +++ b/core/commons/che-core-commons-json/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-json jar diff --git a/core/commons/che-core-commons-lang/pom.xml b/core/commons/che-core-commons-lang/pom.xml index 64e1ba096bf..3e5a80e0c93 100644 --- a/core/commons/che-core-commons-lang/pom.xml +++ b/core/commons/che-core-commons-lang/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-lang jar diff --git a/core/commons/che-core-commons-schedule/pom.xml b/core/commons/che-core-commons-schedule/pom.xml index 28f55dfa37a..5ed90cb2063 100644 --- a/core/commons/che-core-commons-schedule/pom.xml +++ b/core/commons/che-core-commons-schedule/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-schedule jar diff --git a/core/commons/che-core-commons-test/pom.xml b/core/commons/che-core-commons-test/pom.xml index 51157543944..e81238e99cc 100644 --- a/core/commons/che-core-commons-test/pom.xml +++ b/core/commons/che-core-commons-test/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-test jar diff --git a/core/commons/che-core-commons-xml/pom.xml b/core/commons/che-core-commons-xml/pom.xml index 92cddd9495e..c476f322bef 100644 --- a/core/commons/che-core-commons-xml/pom.xml +++ b/core/commons/che-core-commons-xml/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-xml jar diff --git a/core/commons/pom.xml b/core/commons/pom.xml index f8b7ce81385..929cb24d923 100644 --- a/core/commons/pom.xml +++ b/core/commons/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-core-commons-parent diff --git a/core/pom.xml b/core/pom.xml index b8a13261083..258899490f5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml org.eclipse.che.core che-core-parent - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 pom Che Core Parent diff --git a/dashboard/pom.xml b/dashboard/pom.xml index 0dcc165af8e..149324cc652 100644 --- a/dashboard/pom.xml +++ b/dashboard/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml org.eclipse.che.dashboard che-dashboard-war - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 war Che Dashboard :: Web App 2015 diff --git a/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml b/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml index 96421da7d47..36ba47e01c6 100644 --- a/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml +++ b/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-dyna-provider-generator-maven-plugin maven-plugin diff --git a/ide/che-core-ide-api/pom.xml b/ide/che-core-ide-api/pom.xml index ee1312bd470..2b4b5faf8d2 100644 --- a/ide/che-core-ide-api/pom.xml +++ b/ide/che-core-ide-api/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core che-core-ide-api diff --git a/ide/che-core-ide-app/pom.xml b/ide/che-core-ide-app/pom.xml index 32991a1b26f..4cde354d0e5 100644 --- a/ide/che-core-ide-app/pom.xml +++ b/ide/che-core-ide-app/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core che-core-ide-app diff --git a/ide/che-core-ide-generators/pom.xml b/ide/che-core-ide-generators/pom.xml index 5259827631a..0e1421fa55b 100644 --- a/ide/che-core-ide-generators/pom.xml +++ b/ide/che-core-ide-generators/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core che-core-ide-generators diff --git a/ide/che-core-ide-stacks/pom.xml b/ide/che-core-ide-stacks/pom.xml index 52ff5c28492..267502c6db2 100644 --- a/ide/che-core-ide-stacks/pom.xml +++ b/ide/che-core-ide-stacks/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core che-core-ide-stacks diff --git a/ide/che-core-ide-templates/pom.xml b/ide/che-core-ide-templates/pom.xml index fc09c7bd31c..2e94e7fc39d 100644 --- a/ide/che-core-ide-templates/pom.xml +++ b/ide/che-core-ide-templates/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core che-core-ide-templates diff --git a/ide/che-core-ide-ui/pom.xml b/ide/che-core-ide-ui/pom.xml index 4f3b031e048..1b30a2ec2c5 100644 --- a/ide/che-core-ide-ui/pom.xml +++ b/ide/che-core-ide-ui/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core che-core-ide-ui diff --git a/ide/commons-gwt/pom.xml b/ide/commons-gwt/pom.xml index c5f0d6178b5..48a43ca7ffe 100644 --- a/ide/commons-gwt/pom.xml +++ b/ide/commons-gwt/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-commons-gwt Che Core :: Commons :: GWT diff --git a/ide/pom.xml b/ide/pom.xml index d9ef6ee000a..35c536d04d0 100644 --- a/ide/pom.xml +++ b/ide/pom.xml @@ -16,7 +16,7 @@ che-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml org.eclipse.che.core diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml index 95c86256e88..dbfc606a65c 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-cpp-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-cpp-lang-ide jar diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml b/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml index b4ffb076405..dd3fe9d5409 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-cpp-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-cpp-lang-server Che Plugin :: C/C++ :: Extension Server diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml b/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml index 860565af0cb..db70380e207 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-cpp-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-cpp-lang-shared Che Plugin :: C/C++ :: Shared diff --git a/plugins/plugin-cpp/pom.xml b/plugins/plugin-cpp/pom.xml index dee77b14dc8..ea5a7a1a803 100644 --- a/plugins/plugin-cpp/pom.xml +++ b/plugins/plugin-cpp/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-cpp-parent diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml index 3af18651708..0fcda4d427b 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-csharp-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-csharp-lang-ide jar diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml b/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml index 58f9872fd08..69e3e6960dc 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-csharp-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-csharp-lang-server Che Plugin :: C# :: Extension Server diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml b/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml index c90a9c41597..202ebda6354 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-csharp-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-csharp-lang-shared Che Plugin :: C# :: Shared diff --git a/plugins/plugin-csharp/pom.xml b/plugins/plugin-csharp/pom.xml index a91a09e9bc8..77f7a4f51ba 100644 --- a/plugins/plugin-csharp/pom.xml +++ b/plugins/plugin-csharp/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-csharp-parent diff --git a/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml b/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml index a739aa87cb8..9368cf502fd 100644 --- a/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml +++ b/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml @@ -16,7 +16,7 @@ che-plugin-dashboard-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-ext-dashboard-client jar diff --git a/plugins/plugin-dashboard/pom.xml b/plugins/plugin-dashboard/pom.xml index 969a4a168e6..4fc7781ef79 100644 --- a/plugins/plugin-dashboard/pom.xml +++ b/plugins/plugin-dashboard/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-dashboard-parent diff --git a/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml b/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml index 13a99355c3f..25cda2e40fc 100644 --- a/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-debugger-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-debugger-ide jar diff --git a/plugins/plugin-debugger/pom.xml b/plugins/plugin-debugger/pom.xml index 0bc38470484..48314e3f7f1 100644 --- a/plugins/plugin-debugger/pom.xml +++ b/plugins/plugin-debugger/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-debugger-parent diff --git a/plugins/plugin-docker/che-plugin-docker-client/pom.xml b/plugins/plugin-docker/che-plugin-docker-client/pom.xml index 61c15c649c8..35a536eb4a3 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/pom.xml +++ b/plugins/plugin-docker/che-plugin-docker-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-docker-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-docker-client jar diff --git a/plugins/plugin-docker/che-plugin-docker-compose/pom.xml b/plugins/plugin-docker/che-plugin-docker-compose/pom.xml index d5e3b12d171..d1393e7b4a2 100644 --- a/plugins/plugin-docker/che-plugin-docker-compose/pom.xml +++ b/plugins/plugin-docker/che-plugin-docker-compose/pom.xml @@ -16,7 +16,7 @@ che-plugin-docker-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-docker-compose jar diff --git a/plugins/plugin-docker/che-plugin-docker-machine/pom.xml b/plugins/plugin-docker/che-plugin-docker-machine/pom.xml index 24a32586d94..5713919b4a1 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/pom.xml +++ b/plugins/plugin-docker/che-plugin-docker-machine/pom.xml @@ -16,7 +16,7 @@ che-plugin-docker-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-docker-machine jar diff --git a/plugins/plugin-docker/pom.xml b/plugins/plugin-docker/pom.xml index d76284325ec..018029c443e 100644 --- a/plugins/plugin-docker/pom.xml +++ b/plugins/plugin-docker/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-docker-parent diff --git a/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml b/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml index aa977f62e34..63a3cf8d607 100644 --- a/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml +++ b/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-gdb-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-gdb-ide jar diff --git a/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml b/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml index 4febdab0eb9..dd8839450e6 100644 --- a/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml +++ b/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-gdb-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-gdb-server jar diff --git a/plugins/plugin-gdb/pom.xml b/plugins/plugin-gdb/pom.xml index 93d8f6f39ee..76354dd0f4c 100644 --- a/plugins/plugin-gdb/pom.xml +++ b/plugins/plugin-gdb/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-gdb-parent pom diff --git a/plugins/plugin-git/che-plugin-git-ext-git/pom.xml b/plugins/plugin-git/che-plugin-git-ext-git/pom.xml index 9ebfff3189c..5aa15dbdc69 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/pom.xml +++ b/plugins/plugin-git/che-plugin-git-ext-git/pom.xml @@ -16,7 +16,7 @@ che-plugin-git-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-git-ext-git jar diff --git a/plugins/plugin-git/pom.xml b/plugins/plugin-git/pom.xml index 62c1f4e3a15..a751aca065a 100644 --- a/plugins/plugin-git/pom.xml +++ b/plugins/plugin-git/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-git-parent diff --git a/plugins/plugin-github/che-plugin-github-ide/pom.xml b/plugins/plugin-github/che-plugin-github-ide/pom.xml index ece57f7afa7..7122a8be428 100644 --- a/plugins/plugin-github/che-plugin-github-ide/pom.xml +++ b/plugins/plugin-github/che-plugin-github-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-github-ide jar diff --git a/plugins/plugin-github/che-plugin-github-oauth2/pom.xml b/plugins/plugin-github/che-plugin-github-oauth2/pom.xml index 780f7e182ad..584e7bb1ab2 100644 --- a/plugins/plugin-github/che-plugin-github-oauth2/pom.xml +++ b/plugins/plugin-github/che-plugin-github-oauth2/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-github-oauth2 jar diff --git a/plugins/plugin-github/che-plugin-github-provider-github/pom.xml b/plugins/plugin-github/che-plugin-github-provider-github/pom.xml index b269dc9e36e..7c90f460405 100644 --- a/plugins/plugin-github/che-plugin-github-provider-github/pom.xml +++ b/plugins/plugin-github/che-plugin-github-provider-github/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-github-provider-github Che Plugin :: Github :: Credential provider diff --git a/plugins/plugin-github/che-plugin-github-server/pom.xml b/plugins/plugin-github/che-plugin-github-server/pom.xml index 888f3a638f6..be304b99e41 100644 --- a/plugins/plugin-github/che-plugin-github-server/pom.xml +++ b/plugins/plugin-github/che-plugin-github-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-github-server jar diff --git a/plugins/plugin-github/che-plugin-github-shared/pom.xml b/plugins/plugin-github/che-plugin-github-shared/pom.xml index f5a3aa618f0..526143e9920 100644 --- a/plugins/plugin-github/che-plugin-github-shared/pom.xml +++ b/plugins/plugin-github/che-plugin-github-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-github-shared Che Plugin :: Github :: Shared diff --git a/plugins/plugin-github/pom.xml b/plugins/plugin-github/pom.xml index 1d4d80f3f65..1ac5fac3fc0 100644 --- a/plugins/plugin-github/pom.xml +++ b/plugins/plugin-github/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-github-parent diff --git a/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml b/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml index 2911924d617..749db932289 100644 --- a/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml +++ b/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml @@ -16,7 +16,7 @@ che-plugin-gwt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-gwt-ext-gwt jar diff --git a/plugins/plugin-gwt/pom.xml b/plugins/plugin-gwt/pom.xml index d876f210d62..38a97c393ce 100644 --- a/plugins/plugin-gwt/pom.xml +++ b/plugins/plugin-gwt/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-gwt-parent diff --git a/plugins/plugin-help/che-plugin-help-ext-client/pom.xml b/plugins/plugin-help/che-plugin-help-ext-client/pom.xml index 5efcfa9ff26..51eca8685f4 100644 --- a/plugins/plugin-help/che-plugin-help-ext-client/pom.xml +++ b/plugins/plugin-help/che-plugin-help-ext-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-help-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-help-ext-client jar diff --git a/plugins/plugin-help/pom.xml b/plugins/plugin-help/pom.xml index bc2d1f78997..6b0895368cc 100644 --- a/plugins/plugin-help/pom.xml +++ b/plugins/plugin-help/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-help-parent diff --git a/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml b/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml index 71903d5427a..3442dbec5cb 100644 --- a/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml +++ b/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-debugger-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-debugger-ide jar diff --git a/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml b/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml index 83bf837924c..8b5f35e925b 100644 --- a/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml +++ b/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-debugger-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-debugger-server jar diff --git a/plugins/plugin-java-debugger/pom.xml b/plugins/plugin-java-debugger/pom.xml index 1cdf0f9fbd0..1b974da35a7 100644 --- a/plugins/plugin-java-debugger/pom.xml +++ b/plugins/plugin-java-debugger/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-debugger-parent pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml index 7e9d6a34ef9..f17200d8360 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-classpath org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-classpath-maven-server Che Plugin :: Java Testing :: Maven Classpath diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml index 36630e9bdc9..5b066c6c87b 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-classpath pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml index bea18bead89..ba705c0744b 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml @@ -16,7 +16,7 @@ che-java-testing-core org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-core-ide Che Plugin :: Java Testing :: Core IDE diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml index 2e758d7d2ae..43cf7f4ac57 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-core org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-core-server Che Plugin :: Java Testing :: Core Server diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml index 5afbb05518f..7198d320375 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml @@ -16,7 +16,7 @@ che-java-testing-core org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-core-shared Che Plugin :: Java Testing :: Core Shared diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml index a2fd7c69ab7..035a80dce20 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-core pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml index 1526887b0c1..1a06d473426 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml @@ -16,7 +16,7 @@ che-java-testing-junit org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-junit-ide Che Plugin :: Java Testing :: JUnit IDE diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml index f1d012d8680..1ed22a6d366 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-junit org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-junit-server Che Plugin :: Java Testing :: JUnit Server diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml index 48f1fb07bac..6cf09d1da2a 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml @@ -16,7 +16,7 @@ che-java-testing-junit org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-junit-shared Che Plugin :: Java Testing :: JUnit Shared diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml index 535bd531d5b..5f5c1f1c679 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-junit pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml index 769506f1fc0..7b771d40795 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml @@ -16,7 +16,7 @@ che-java-testing-testng org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-testng-ide Che Plugin :: Java Testing :: TestNG IDE diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml index ceb00f8223a..c0462c92fbd 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-testng org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-testng-server Che Plugin :: Java Testing :: TestNG Server diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml index e165b4b0614..04575ac02ec 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-java-testing-testng pom diff --git a/plugins/plugin-java-test-runner/pom.xml b/plugins/plugin-java-test-runner/pom.xml index 6fbd6d5464b..a7dcec61148 100644 --- a/plugins/plugin-java-test-runner/pom.xml +++ b/plugins/plugin-java-test-runner/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-test-runner-parent pom diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml index 1cca882ce6e..ede93739a87 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.core.filebuffers jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml index c3a9623eec7..9e8cd69031a 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.core.filesystem jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml index 375f2ff7197..87972711d4a 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.core.resources jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml index fdf6805847f..6ccb7eb583b 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.jdt.ui jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml index 518361ae15f..6714c7d31f3 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.jface.text jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml index d2c6180af55..4008aea1d31 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.jface jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml index d39016fceae..bcf2af091ef 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.ltk.core.refactoring jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml index 4ef44f10b3b..dd58512d87b 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.search jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml index ef8e0551a28..d289e6e6239 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.ui.ide jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml index ccca84d08c4..07e1fa2ff70 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-ext-jdt-parent pom diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml b/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml index 22383fda291..0c416b88edf 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-ext-lang-client jar diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml b/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml index d0ea59e6c1b..df50b3c24ad 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-ext-lang-server Che Plugin :: Java :: Extension Java Server diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml b/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml index d6a23fdb705..ca1ff8fae14 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-ext-lang-shared Che Plugin :: Java :: Extension Java Shared diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml index ae12f20e023..d053f516bba 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-plain org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-plain-ide jar diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml index ea02ed2655b..f6d2371e41b 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-plain org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-plain-server Che Plugin :: Java :: Plain :: Server diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml index 056d3627c03..9af312d87fb 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-plain org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-plain-shared Che Plugin :: Java :: Plain :: Shared diff --git a/plugins/plugin-java/che-plugin-java-plain/pom.xml b/plugins/plugin-java/che-plugin-java-plain/pom.xml index 10b6a338bc9..7c7983861cf 100644 --- a/plugins/plugin-java/che-plugin-java-plain/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-java-plain diff --git a/plugins/plugin-java/pom.xml b/plugins/plugin-java/pom.xml index 944f8c877c5..8df80e7361b 100644 --- a/plugins/plugin-java/pom.xml +++ b/plugins/plugin-java/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-java-parent diff --git a/plugins/plugin-json/che-plugin-json-server/pom.xml b/plugins/plugin-json/che-plugin-json-server/pom.xml index ba8c6f2d2d9..e63b87cbe55 100644 --- a/plugins/plugin-json/che-plugin-json-server/pom.xml +++ b/plugins/plugin-json/che-plugin-json-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-json-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-json-server Che Plugin :: JSON :: Extension Server diff --git a/plugins/plugin-json/pom.xml b/plugins/plugin-json/pom.xml index 86e88f9c200..34b59212c51 100644 --- a/plugins/plugin-json/pom.xml +++ b/plugins/plugin-json/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-json-parent diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml index d226d1c53b3..41dcbb40309 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-languageserver-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 .. che-plugin-languageserver-ide diff --git a/plugins/plugin-languageserver/pom.xml b/plugins/plugin-languageserver/pom.xml index 98d2a008da0..8111df30821 100644 --- a/plugins/plugin-languageserver/pom.xml +++ b/plugins/plugin-languageserver/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-languageserver-parent diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml b/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml index 4f4635bf546..5a47ee2bab5 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-machine-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-machine-ext-client jar diff --git a/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml b/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml index 4e37b98cc69..dc102e0b188 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml +++ b/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-machine-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-machine-ext-server diff --git a/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml b/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml index d198b5c0939..77eb1c25fe2 100644 --- a/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml +++ b/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-machine-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-machine-ssh-client jar diff --git a/plugins/plugin-machine/pom.xml b/plugins/plugin-machine/pom.xml index b50d1c70cca..e9130a6f249 100644 --- a/plugins/plugin-machine/pom.xml +++ b/plugins/plugin-machine/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-machine-parent 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 b0d61b010e4..bfaffeddf51 100644 --- a/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-maven-generator-archetype jar diff --git a/plugins/plugin-maven/che-plugin-maven-ide/pom.xml b/plugins/plugin-maven/che-plugin-maven-ide/pom.xml index 935b90a0d30..bba6752dd66 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-maven-ide Che Plugin :: Maven :: Extension Maven Client diff --git a/plugins/plugin-maven/che-plugin-maven-server/pom.xml b/plugins/plugin-maven/che-plugin-maven-server/pom.xml index df88133a94e..440b408f37c 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-maven-server jar diff --git a/plugins/plugin-maven/che-plugin-maven-shared/pom.xml b/plugins/plugin-maven/che-plugin-maven-shared/pom.xml index 9af31a9a622..49576d3773d 100644 --- a/plugins/plugin-maven/che-plugin-maven-shared/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-maven-shared Che Plugin :: Maven :: Extension Maven Shared diff --git a/plugins/plugin-maven/che-plugin-maven-tools/pom.xml b/plugins/plugin-maven/che-plugin-maven-tools/pom.xml index e44f9845de5..c4d473c2671 100644 --- a/plugins/plugin-maven/che-plugin-maven-tools/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-tools/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-java-maven-tools jar diff --git a/plugins/plugin-maven/maven-server/maven-server-api/pom.xml b/plugins/plugin-maven/maven-server/maven-server-api/pom.xml index f7cdf11d1e9..ecc02f3f2ea 100644 --- a/plugins/plugin-maven/maven-server/maven-server-api/pom.xml +++ b/plugins/plugin-maven/maven-server/maven-server-api/pom.xml @@ -16,7 +16,7 @@ che-maven-server org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 maven-server-api jar diff --git a/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml b/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml index aa6e98ca11d..ca099c280be 100644 --- a/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml +++ b/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml @@ -16,7 +16,7 @@ che-maven-server org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 maven-server-impl jar diff --git a/plugins/plugin-maven/maven-server/pom.xml b/plugins/plugin-maven/maven-server/pom.xml index 95a9ef3ca12..304d55a17f1 100644 --- a/plugins/plugin-maven/maven-server/pom.xml +++ b/plugins/plugin-maven/maven-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-maven-server pom diff --git a/plugins/plugin-maven/pom.xml b/plugins/plugin-maven/pom.xml index 0c60a9affd4..ab25bf3abdc 100644 --- a/plugins/plugin-maven/pom.xml +++ b/plugins/plugin-maven/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-maven-parent diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml index cbb7f8b44cf..7f12d47ce27 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml +++ b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-debugger-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-nodejs-debugger-ide jar diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml index 3c5f5dd2ad2..8ec1d224303 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml +++ b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-debugger-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-nodejs-debugger-server jar diff --git a/plugins/plugin-nodejs-debugger/pom.xml b/plugins/plugin-nodejs-debugger/pom.xml index c88f8881c5b..f2a4dc0dd41 100644 --- a/plugins/plugin-nodejs-debugger/pom.xml +++ b/plugins/plugin-nodejs-debugger/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-nodejs-debugger-parent pom diff --git a/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml b/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml index 1f848cda01c..3f493afb9eb 100644 --- a/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml +++ b/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-nodejs-lang-ide jar diff --git a/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml b/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml index fdbb5a18853..b1fc01efb95 100644 --- a/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml +++ b/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-nodejs-lang-server Che Plugin :: NodeJs :: Extension Server diff --git a/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml b/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml index 766c8e44289..00279d15ea4 100644 --- a/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml +++ b/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-nodejs-lang-shared Che Plugin :: NodeJs :: Extension Shared diff --git a/plugins/plugin-nodejs/pom.xml b/plugins/plugin-nodejs/pom.xml index 45f1e99e74f..9ad51ee9776 100644 --- a/plugins/plugin-nodejs/pom.xml +++ b/plugins/plugin-nodejs/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-nodejs-parent diff --git a/plugins/plugin-orion/che-plugin-orion-compare/pom.xml b/plugins/plugin-orion/che-plugin-orion-compare/pom.xml index d85e7ce603c..7a46961efdb 100644 --- a/plugins/plugin-orion/che-plugin-orion-compare/pom.xml +++ b/plugins/plugin-orion/che-plugin-orion-compare/pom.xml @@ -16,7 +16,7 @@ che-plugin-orion-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-orion-compare jar diff --git a/plugins/plugin-orion/che-plugin-orion-editor/pom.xml b/plugins/plugin-orion/che-plugin-orion-editor/pom.xml index f107986d5c0..e5ff4f78b50 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/pom.xml +++ b/plugins/plugin-orion/che-plugin-orion-editor/pom.xml @@ -16,7 +16,7 @@ che-plugin-orion-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-orion-editor diff --git a/plugins/plugin-orion/pom.xml b/plugins/plugin-orion/pom.xml index 6711863d317..c8a7bc190ce 100644 --- a/plugins/plugin-orion/pom.xml +++ b/plugins/plugin-orion/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-orion-parent diff --git a/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml b/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml index 6f9ef2e1fbf..b40b4e46238 100644 --- a/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml +++ b/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-php-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-php-lang-ide jar diff --git a/plugins/plugin-php/che-plugin-php-lang-server/pom.xml b/plugins/plugin-php/che-plugin-php-lang-server/pom.xml index 40c22432f05..c5ee891b2a7 100644 --- a/plugins/plugin-php/che-plugin-php-lang-server/pom.xml +++ b/plugins/plugin-php/che-plugin-php-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-php-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-php-lang-server Che Plugin :: PHP :: Extension Server diff --git a/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml b/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml index be8923453cc..43ec22f5c7e 100644 --- a/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml +++ b/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-php-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-php-lang-shared Che Plugin :: PHP :: Shared diff --git a/plugins/plugin-php/pom.xml b/plugins/plugin-php/pom.xml index 3a5a0b68893..2a15c16e234 100644 --- a/plugins/plugin-php/pom.xml +++ b/plugins/plugin-php/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-php-parent diff --git a/plugins/plugin-product-info/pom.xml b/plugins/plugin-product-info/pom.xml index bb671511d7a..10978e99fa7 100644 --- a/plugins/plugin-product-info/pom.xml +++ b/plugins/plugin-product-info/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-product-info diff --git a/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml b/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml index 7a43cd622ec..0aa009dc285 100644 --- a/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml +++ b/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-python-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-python-lang-ide jar diff --git a/plugins/plugin-python/che-plugin-python-lang-server/pom.xml b/plugins/plugin-python/che-plugin-python-lang-server/pom.xml index 1463a67a9d0..010627dd38f 100644 --- a/plugins/plugin-python/che-plugin-python-lang-server/pom.xml +++ b/plugins/plugin-python/che-plugin-python-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-python-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-python-lang-server Che Plugin :: Python :: Extension Server diff --git a/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml b/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml index 7b001cb1d0f..7e1ee22f0b2 100644 --- a/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml +++ b/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-python-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-python-lang-shared che-plugin-python-lang-shared diff --git a/plugins/plugin-python/pom.xml b/plugins/plugin-python/pom.xml index 3e50dfb396b..dd54929e1ff 100644 --- a/plugins/plugin-python/pom.xml +++ b/plugins/plugin-python/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-python-parent diff --git a/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml b/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml index a8269f78cf5..b914af3394b 100644 --- a/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml +++ b/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml @@ -16,7 +16,7 @@ che-plugin-sdk-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-sdk-env-local jar diff --git a/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml b/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml index 3c900dde325..9dc63e59386 100644 --- a/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml +++ b/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml @@ -16,7 +16,7 @@ che-plugin-sdk-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-sdk-ext-plugins jar diff --git a/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml b/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml index 59fe7079f81..34b5da82dce 100644 --- a/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml +++ b/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml @@ -16,7 +16,7 @@ che-plugin-sdk-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-sdk-tools jar diff --git a/plugins/plugin-sdk/pom.xml b/plugins/plugin-sdk/pom.xml index 84c1cecdb97..f5aba519d94 100644 --- a/plugins/plugin-sdk/pom.xml +++ b/plugins/plugin-sdk/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-sdk-parent diff --git a/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml b/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml index c3027605c50..9fcf3d8e9c4 100644 --- a/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml +++ b/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-ssh-key-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-ssh-key-ide jar diff --git a/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml b/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml index c7c42c7e07c..1973df104a1 100644 --- a/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml +++ b/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-ssh-key-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-ssh-key-server jar diff --git a/plugins/plugin-ssh-key/pom.xml b/plugins/plugin-ssh-key/pom.xml index 919f9f9e948..c94b3a8878d 100644 --- a/plugins/plugin-ssh-key/pom.xml +++ b/plugins/plugin-ssh-key/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-ssh-key-parent diff --git a/plugins/plugin-ssh-machine/pom.xml b/plugins/plugin-ssh-machine/pom.xml index 6d4443b42da..6d2c7c8aabe 100644 --- a/plugins/plugin-ssh-machine/pom.xml +++ b/plugins/plugin-ssh-machine/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-ssh-machine diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml b/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml index ecce8d7d86d..9c6dc321a84 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-svn-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-svn-ext-ide jar diff --git a/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml b/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml index 3b0a364b80e..64acffb4b7c 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml +++ b/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-svn-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-svn-ext-server jar diff --git a/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml b/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml index 5f8cfad7f33..8a4a3e600ed 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml +++ b/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-svn-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-svn-ext-shared jar diff --git a/plugins/plugin-svn/pom.xml b/plugins/plugin-svn/pom.xml index 7d3545c3d0d..41b17ab5a9b 100644 --- a/plugins/plugin-svn/pom.xml +++ b/plugins/plugin-svn/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-svn-parent diff --git a/plugins/plugin-web/che-plugin-web-ext-web/pom.xml b/plugins/plugin-web/che-plugin-web-ext-web/pom.xml index ff2b624395d..d118b1b4518 100644 --- a/plugins/plugin-web/che-plugin-web-ext-web/pom.xml +++ b/plugins/plugin-web/che-plugin-web-ext-web/pom.xml @@ -16,7 +16,7 @@ che-plugin-web-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-plugin-web-ext-web jar diff --git a/plugins/plugin-web/pom.xml b/plugins/plugin-web/pom.xml index 94d9afe759c..19b7c2054f6 100644 --- a/plugins/plugin-web/pom.xml +++ b/plugins/plugin-web/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-plugin-web-parent diff --git a/plugins/pom.xml b/plugins/pom.xml index 1bc9eaba9d7..e91e9fe16a2 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml org.eclipse.che.plugin che-plugin-parent - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 pom Che Plugin :: Parent diff --git a/pom.xml b/pom.xml index b698b2a6d15..21157c42c71 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ org.eclipse.che che-parent - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 pom Che Parent @@ -36,7 +36,7 @@ scm:git:git@github.com:eclipse/che.git scm:git:git@github.com:eclipse/che.git - HEAD + 5.0.0-M8 https://github.com/eclipse/che diff --git a/samples/pom.xml b/samples/pom.xml index 6b07ad57f3a..c4c0f02c16b 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml org.eclipse.che.sample che-sample-parent - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 pom Che Sample :: Parent diff --git a/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml b/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml index 15a3979d489..7672cee1980 100644 --- a/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml +++ b/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-actions-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-actions-ide jar diff --git a/samples/sample-plugin-actions/pom.xml b/samples/sample-plugin-actions/pom.xml index dd5581625d6..4d5b5b025aa 100644 --- a/samples/sample-plugin-actions/pom.xml +++ b/samples/sample-plugin-actions/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-actions-parent diff --git a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml index 8d45a285c7c..143b7122339 100644 --- a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml +++ b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-embedjs-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-embedjs-ide jar diff --git a/samples/sample-plugin-embedjs/pom.xml b/samples/sample-plugin-embedjs/pom.xml index b4e572e8ac3..5a298fd9140 100644 --- a/samples/sample-plugin-embedjs/pom.xml +++ b/samples/sample-plugin-embedjs/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-embedjs-parent diff --git a/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml b/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml index 9712376824f..b31c8228d0b 100644 --- a/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml +++ b/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-filetype-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-filetype-ide jar diff --git a/samples/sample-plugin-filetype/pom.xml b/samples/sample-plugin-filetype/pom.xml index 8f7de911616..8d592ee3b79 100644 --- a/samples/sample-plugin-filetype/pom.xml +++ b/samples/sample-plugin-filetype/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-filetype-parent diff --git a/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml b/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml index b96948d197a..51267a25bb1 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml +++ b/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-json-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-json-ide jar diff --git a/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml b/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml index dd6223ca922..b01bc49b82d 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml +++ b/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-json-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-json-server Che Sample :: Plugin JSON :: Server diff --git a/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml b/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml index b3f7e234352..d01edf3738a 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml +++ b/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-json-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-json-shared Che Sample :: Plugin JSON :: Shared diff --git a/samples/sample-plugin-json/pom.xml b/samples/sample-plugin-json/pom.xml index 7fba67b147b..86eb1b5e289 100644 --- a/samples/sample-plugin-json/pom.xml +++ b/samples/sample-plugin-json/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-json-parent diff --git a/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml b/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml index 8397a77c408..8444e5d9ff3 100644 --- a/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml +++ b/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-nativeaccess-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-nativeaccess-ide jar diff --git a/samples/sample-plugin-nativeaccess/pom.xml b/samples/sample-plugin-nativeaccess/pom.xml index 5d3f63f86d6..238fda00118 100644 --- a/samples/sample-plugin-nativeaccess/pom.xml +++ b/samples/sample-plugin-nativeaccess/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-nativeaccess-parent diff --git a/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml b/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml index 0f756f1e1bc..511eec13ce8 100644 --- a/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml +++ b/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-parts-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-parts-ide jar diff --git a/samples/sample-plugin-parts/pom.xml b/samples/sample-plugin-parts/pom.xml index a070d3993da..6fa558d5b6e 100644 --- a/samples/sample-plugin-parts/pom.xml +++ b/samples/sample-plugin-parts/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-parts-parent diff --git a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml index 93752331969..ef869de4116 100644 --- a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml +++ b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-serverservice-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-serverservice-ide jar diff --git a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml index 0ab9c8e2b00..f41c0f46887 100644 --- a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml +++ b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-serverservice-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-serverservice-server Che Sample :: Plugin ServerService :: Server diff --git a/samples/sample-plugin-serverservice/pom.xml b/samples/sample-plugin-serverservice/pom.xml index 0265af4c335..1636b2c88c7 100644 --- a/samples/sample-plugin-serverservice/pom.xml +++ b/samples/sample-plugin-serverservice/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-serverservice-parent diff --git a/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml b/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml index d46082d6f2d..90660a97315 100644 --- a/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml +++ b/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-wizard-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-wizard-ide jar diff --git a/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml b/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml index 3a6871b8965..c5f303a18c8 100644 --- a/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml +++ b/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-wizard-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-wizard-server Che Sample :: Plugin Wizard :: Server diff --git a/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml b/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml index 3a97b771cd4..32ef7a27dee 100644 --- a/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml +++ b/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-wizard-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-sample-plugin-wizard-shared Che Sample :: Plugin Wizard :: Shared diff --git a/samples/sample-plugin-wizard/pom.xml b/samples/sample-plugin-wizard/pom.xml index 86f1bfc2b4f..eb35639fbd3 100644 --- a/samples/sample-plugin-wizard/pom.xml +++ b/samples/sample-plugin-wizard/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml che-sample-plugin-wizard-parent diff --git a/wsagent/che-core-api-debug-shared/pom.xml b/wsagent/che-core-api-debug-shared/pom.xml index 02afbf98e3b..88b39d582de 100644 --- a/wsagent/che-core-api-debug-shared/pom.xml +++ b/wsagent/che-core-api-debug-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-debug-shared jar diff --git a/wsagent/che-core-api-debug/pom.xml b/wsagent/che-core-api-debug/pom.xml index 047536e470b..d99dc3b9431 100644 --- a/wsagent/che-core-api-debug/pom.xml +++ b/wsagent/che-core-api-debug/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-debug Che Core :: API :: Debug diff --git a/wsagent/che-core-api-git-shared/pom.xml b/wsagent/che-core-api-git-shared/pom.xml index c5bf10cbeab..2ea3b031f24 100644 --- a/wsagent/che-core-api-git-shared/pom.xml +++ b/wsagent/che-core-api-git-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-git-shared jar diff --git a/wsagent/che-core-api-git/pom.xml b/wsagent/che-core-api-git/pom.xml index 779cf74f23f..536c4f88f6c 100644 --- a/wsagent/che-core-api-git/pom.xml +++ b/wsagent/che-core-api-git/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-git jar diff --git a/wsagent/che-core-api-languageserver-shared/pom.xml b/wsagent/che-core-api-languageserver-shared/pom.xml index 91b82af4ef4..3e010a2ceaf 100644 --- a/wsagent/che-core-api-languageserver-shared/pom.xml +++ b/wsagent/che-core-api-languageserver-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-languageserver-shared jar diff --git a/wsagent/che-core-api-languageserver/pom.xml b/wsagent/che-core-api-languageserver/pom.xml index 69a5dc6a24c..e18893c0d9d 100644 --- a/wsagent/che-core-api-languageserver/pom.xml +++ b/wsagent/che-core-api-languageserver/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-languageserver jar diff --git a/wsagent/che-core-api-project-shared/pom.xml b/wsagent/che-core-api-project-shared/pom.xml index 6362084d9c5..aabbf7e6f8f 100644 --- a/wsagent/che-core-api-project-shared/pom.xml +++ b/wsagent/che-core-api-project-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-project-shared jar diff --git a/wsagent/che-core-api-project/pom.xml b/wsagent/che-core-api-project/pom.xml index ca1b23431a1..c876717b71d 100644 --- a/wsagent/che-core-api-project/pom.xml +++ b/wsagent/che-core-api-project/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-project jar @@ -101,7 +101,7 @@ org.eclipse.che.core che-core-api-project-shared - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 org.eclipse.che.core diff --git a/wsagent/che-core-git-impl-jgit/pom.xml b/wsagent/che-core-git-impl-jgit/pom.xml index f700ffdc1e5..4f87779ac4e 100644 --- a/wsagent/che-core-git-impl-jgit/pom.xml +++ b/wsagent/che-core-git-impl-jgit/pom.xml @@ -17,7 +17,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-git-impl-jgit jar diff --git a/wsagent/pom.xml b/wsagent/pom.xml index 4acf917e091..0f459ecbaaf 100644 --- a/wsagent/pom.xml +++ b/wsagent/pom.xml @@ -16,12 +16,12 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../core/pom.xml org.eclipse.che.core che-agent-parent - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 pom Che Agent Parent diff --git a/wsagent/wsagent-local/pom.xml b/wsagent/wsagent-local/pom.xml index c02404bd674..04133ab431a 100644 --- a/wsagent/wsagent-local/pom.xml +++ b/wsagent/wsagent-local/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 wsagent-local Che Core :: API :: Agent diff --git a/wsmaster/che-core-api-account/pom.xml b/wsmaster/che-core-api-account/pom.xml index 18c440ba4ab..d2e47bd8c67 100644 --- a/wsmaster/che-core-api-account/pom.xml +++ b/wsmaster/che-core-api-account/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-account Che Core :: API :: Account diff --git a/wsmaster/che-core-api-agent-shared/pom.xml b/wsmaster/che-core-api-agent-shared/pom.xml index 19c267f756b..e7603f2db46 100644 --- a/wsmaster/che-core-api-agent-shared/pom.xml +++ b/wsmaster/che-core-api-agent-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-agent-shared jar diff --git a/wsmaster/che-core-api-agent/pom.xml b/wsmaster/che-core-api-agent/pom.xml index 138a2fbc0eb..44d65825304 100644 --- a/wsmaster/che-core-api-agent/pom.xml +++ b/wsmaster/che-core-api-agent/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-agent jar diff --git a/wsmaster/che-core-api-auth/pom.xml b/wsmaster/che-core-api-auth/pom.xml index 638afe8a577..d4b242c8bb6 100644 --- a/wsmaster/che-core-api-auth/pom.xml +++ b/wsmaster/che-core-api-auth/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-auth jar diff --git a/wsmaster/che-core-api-factory-shared/pom.xml b/wsmaster/che-core-api-factory-shared/pom.xml index 3b36bf408e1..a8904051b3f 100644 --- a/wsmaster/che-core-api-factory-shared/pom.xml +++ b/wsmaster/che-core-api-factory-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-factory-shared jar diff --git a/wsmaster/che-core-api-factory/pom.xml b/wsmaster/che-core-api-factory/pom.xml index 08baecd1e1a..e095e8eb7d8 100644 --- a/wsmaster/che-core-api-factory/pom.xml +++ b/wsmaster/che-core-api-factory/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-factory jar diff --git a/wsmaster/che-core-api-machine-shared/pom.xml b/wsmaster/che-core-api-machine-shared/pom.xml index 187575fef31..31f3640ed11 100644 --- a/wsmaster/che-core-api-machine-shared/pom.xml +++ b/wsmaster/che-core-api-machine-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-machine-shared jar diff --git a/wsmaster/che-core-api-machine/pom.xml b/wsmaster/che-core-api-machine/pom.xml index c6ebcbdb97b..b73fdc9986c 100644 --- a/wsmaster/che-core-api-machine/pom.xml +++ b/wsmaster/che-core-api-machine/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-machine jar diff --git a/wsmaster/che-core-api-project-templates-shared/pom.xml b/wsmaster/che-core-api-project-templates-shared/pom.xml index 63cf3be8a01..ad427c225bd 100644 --- a/wsmaster/che-core-api-project-templates-shared/pom.xml +++ b/wsmaster/che-core-api-project-templates-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-project-templates-shared Che Core :: API :: Project Templates :: Shared diff --git a/wsmaster/che-core-api-project-templates/pom.xml b/wsmaster/che-core-api-project-templates/pom.xml index d7f7c37ecaf..e83631d6cbc 100644 --- a/wsmaster/che-core-api-project-templates/pom.xml +++ b/wsmaster/che-core-api-project-templates/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-project-templates Che Core :: API :: Project Templates diff --git a/wsmaster/che-core-api-ssh-shared/pom.xml b/wsmaster/che-core-api-ssh-shared/pom.xml index 8a9ba1b64d0..064650c8163 100644 --- a/wsmaster/che-core-api-ssh-shared/pom.xml +++ b/wsmaster/che-core-api-ssh-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-ssh-shared jar diff --git a/wsmaster/che-core-api-ssh/pom.xml b/wsmaster/che-core-api-ssh/pom.xml index a434d8575db..474e60b1636 100644 --- a/wsmaster/che-core-api-ssh/pom.xml +++ b/wsmaster/che-core-api-ssh/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-ssh jar diff --git a/wsmaster/che-core-api-user-shared/pom.xml b/wsmaster/che-core-api-user-shared/pom.xml index bd49c4aa097..c82e620e4ea 100644 --- a/wsmaster/che-core-api-user-shared/pom.xml +++ b/wsmaster/che-core-api-user-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-user-shared Che Core :: API :: User :: Shared diff --git a/wsmaster/che-core-api-user/pom.xml b/wsmaster/che-core-api-user/pom.xml index da43480eed7..c1e6968b7a8 100644 --- a/wsmaster/che-core-api-user/pom.xml +++ b/wsmaster/che-core-api-user/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-user Che Core :: API :: User diff --git a/wsmaster/che-core-api-workspace-shared/pom.xml b/wsmaster/che-core-api-workspace-shared/pom.xml index 148a9b5b62b..cb962355097 100644 --- a/wsmaster/che-core-api-workspace-shared/pom.xml +++ b/wsmaster/che-core-api-workspace-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-workspace-shared jar diff --git a/wsmaster/che-core-api-workspace/pom.xml b/wsmaster/che-core-api-workspace/pom.xml index a4b77075b14..4c8cd0bf69e 100644 --- a/wsmaster/che-core-api-workspace/pom.xml +++ b/wsmaster/che-core-api-workspace/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-api-workspace jar diff --git a/wsmaster/che-core-sql-schema/pom.xml b/wsmaster/che-core-sql-schema/pom.xml index f69d2a3f2b9..a5185f7e655 100644 --- a/wsmaster/che-core-sql-schema/pom.xml +++ b/wsmaster/che-core-sql-schema/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 che-core-sql-schema Che Core :: SQL :: Schema diff --git a/wsmaster/integration-tests/cascade-removal/pom.xml b/wsmaster/integration-tests/cascade-removal/pom.xml index a62055f9a42..551307ab90e 100644 --- a/wsmaster/integration-tests/cascade-removal/pom.xml +++ b/wsmaster/integration-tests/cascade-removal/pom.xml @@ -16,7 +16,7 @@ integration-tests-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 cascade-removal Integration Tests :: Cascade Removal diff --git a/wsmaster/integration-tests/pom.xml b/wsmaster/integration-tests/pom.xml index 24aa197970b..466c67ec259 100644 --- a/wsmaster/integration-tests/pom.xml +++ b/wsmaster/integration-tests/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../pom.xml integration-tests-parent diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml index 9f27b5ba604..c6877b7082e 100644 --- a/wsmaster/integration-tests/postgresql-tck/pom.xml +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -16,7 +16,7 @@ integration-tests-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 postgresql-tck jar diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index 01cb27bc711..994ffa45a42 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -16,11 +16,11 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 ../core/pom.xml che-master-parent - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 pom Che Master Parent diff --git a/wsmaster/wsmaster-local/pom.xml b/wsmaster/wsmaster-local/pom.xml index d9e4c4e2b96..6b37a367019 100644 --- a/wsmaster/wsmaster-local/pom.xml +++ b/wsmaster/wsmaster-local/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8-SNAPSHOT + 5.0.0-M8 wsmaster-local Che Core :: API :: Impl Local From 7850cc2908f283d36c15eafa6c76a8a9d20f96f6 Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 12:34:30 +0000 Subject: [PATCH 57/74] [maven-release-plugin] prepare for next development iteration --- assembly/assembly-ide-war/pom.xml | 2 +- assembly/assembly-main/pom.xml | 2 +- assembly/assembly-wsagent-server/pom.xml | 2 +- assembly/assembly-wsagent-war/pom.xml | 2 +- assembly/assembly-wsmaster-war/pom.xml | 2 +- assembly/pom.xml | 4 ++-- core/che-core-api-core/pom.xml | 2 +- core/che-core-api-dto-maven-plugin/pom.xml | 2 +- core/che-core-api-dto/pom.xml | 2 +- core/che-core-api-model/pom.xml | 2 +- core/che-core-db-vendor-h2/pom.xml | 2 +- core/che-core-db-vendor-postgresql/pom.xml | 2 +- core/che-core-db/pom.xml | 2 +- core/che-core-typescript-dto-maven-plugin/pom.xml | 2 +- core/commons/che-core-commons-annotations/pom.xml | 2 +- core/commons/che-core-commons-inject/pom.xml | 2 +- core/commons/che-core-commons-json/pom.xml | 2 +- core/commons/che-core-commons-lang/pom.xml | 2 +- core/commons/che-core-commons-schedule/pom.xml | 2 +- core/commons/che-core-commons-test/pom.xml | 2 +- core/commons/che-core-commons-xml/pom.xml | 2 +- core/commons/pom.xml | 2 +- core/pom.xml | 4 ++-- dashboard/pom.xml | 4 ++-- ide/che-core-dyna-provider-generator-maven-plugin/pom.xml | 2 +- ide/che-core-ide-api/pom.xml | 2 +- ide/che-core-ide-app/pom.xml | 2 +- ide/che-core-ide-generators/pom.xml | 2 +- ide/che-core-ide-stacks/pom.xml | 2 +- ide/che-core-ide-templates/pom.xml | 2 +- ide/che-core-ide-ui/pom.xml | 2 +- ide/commons-gwt/pom.xml | 2 +- ide/pom.xml | 2 +- plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml | 2 +- plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml | 2 +- plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml | 2 +- plugins/plugin-cpp/pom.xml | 2 +- plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml | 2 +- plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml | 2 +- plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml | 2 +- plugins/plugin-csharp/pom.xml | 2 +- plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml | 2 +- plugins/plugin-dashboard/pom.xml | 2 +- plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml | 2 +- plugins/plugin-debugger/pom.xml | 2 +- plugins/plugin-docker/che-plugin-docker-client/pom.xml | 2 +- plugins/plugin-docker/che-plugin-docker-compose/pom.xml | 2 +- plugins/plugin-docker/che-plugin-docker-machine/pom.xml | 2 +- plugins/plugin-docker/pom.xml | 2 +- plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml | 2 +- plugins/plugin-gdb/che-plugin-gdb-server/pom.xml | 2 +- plugins/plugin-gdb/pom.xml | 2 +- plugins/plugin-git/che-plugin-git-ext-git/pom.xml | 2 +- plugins/plugin-git/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-ide/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-oauth2/pom.xml | 2 +- .../plugin-github/che-plugin-github-provider-github/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-server/pom.xml | 2 +- plugins/plugin-github/che-plugin-github-shared/pom.xml | 2 +- plugins/plugin-github/pom.xml | 2 +- plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml | 2 +- plugins/plugin-gwt/pom.xml | 2 +- plugins/plugin-help/che-plugin-help-ext-client/pom.xml | 2 +- plugins/plugin-help/pom.xml | 2 +- .../che-plugin-java-debugger-ide/pom.xml | 2 +- .../che-plugin-java-debugger-server/pom.xml | 2 +- plugins/plugin-java-debugger/pom.xml | 2 +- .../che-java-testing-classpath-maven-server/pom.xml | 2 +- .../che-java-testing-classpath/pom.xml | 2 +- .../che-java-testing-core/che-java-testing-core-ide/pom.xml | 2 +- .../che-java-testing-core-server/pom.xml | 2 +- .../che-java-testing-core-shared/pom.xml | 2 +- .../plugin-java-test-runner/che-java-testing-core/pom.xml | 2 +- .../che-java-testing-junit-ide/pom.xml | 2 +- .../che-java-testing-junit-server/pom.xml | 2 +- .../che-java-testing-junit-shared/pom.xml | 2 +- .../plugin-java-test-runner/che-java-testing-junit/pom.xml | 2 +- .../che-java-testing-testng-ide/pom.xml | 2 +- .../che-java-testing-testng-server/pom.xml | 2 +- .../plugin-java-test-runner/che-java-testing-testng/pom.xml | 2 +- plugins/plugin-java-test-runner/pom.xml | 2 +- .../org-eclipse-core-filebuffers/pom.xml | 2 +- .../org-eclipse-core-filesystem/pom.xml | 2 +- .../org-eclipse-core-resources/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml | 2 +- .../org-eclipse-ltk-core-refactoring/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-search/pom.xml | 2 +- .../che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml | 2 +- .../che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml | 2 +- .../che-plugin-java-plain-server/pom.xml | 2 +- .../che-plugin-java-plain-shared/pom.xml | 2 +- plugins/plugin-java/che-plugin-java-plain/pom.xml | 2 +- plugins/plugin-java/pom.xml | 2 +- plugins/plugin-json/che-plugin-json-server/pom.xml | 2 +- plugins/plugin-json/pom.xml | 2 +- .../che-plugin-languageserver-ide/pom.xml | 2 +- plugins/plugin-languageserver/pom.xml | 2 +- .../plugin-machine/che-plugin-machine-ext-client/pom.xml | 2 +- .../plugin-machine/che-plugin-machine-ext-server/pom.xml | 2 +- .../plugin-machine/che-plugin-machine-ssh-client/pom.xml | 2 +- plugins/plugin-machine/pom.xml | 2 +- .../che-plugin-maven-generator-archetype/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-ide/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-server/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-shared/pom.xml | 2 +- plugins/plugin-maven/che-plugin-maven-tools/pom.xml | 2 +- plugins/plugin-maven/maven-server/maven-server-api/pom.xml | 2 +- plugins/plugin-maven/maven-server/maven-server-impl/pom.xml | 2 +- plugins/plugin-maven/maven-server/pom.xml | 2 +- plugins/plugin-maven/pom.xml | 2 +- .../che-plugin-nodejs-debugger-ide/pom.xml | 2 +- .../che-plugin-nodejs-debugger-server/pom.xml | 2 +- plugins/plugin-nodejs-debugger/pom.xml | 2 +- plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml | 2 +- plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml | 2 +- plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml | 2 +- plugins/plugin-nodejs/pom.xml | 2 +- plugins/plugin-orion/che-plugin-orion-compare/pom.xml | 2 +- plugins/plugin-orion/che-plugin-orion-editor/pom.xml | 2 +- plugins/plugin-orion/pom.xml | 2 +- plugins/plugin-php/che-plugin-php-lang-ide/pom.xml | 2 +- plugins/plugin-php/che-plugin-php-lang-server/pom.xml | 2 +- plugins/plugin-php/che-plugin-php-lang-shared/pom.xml | 2 +- plugins/plugin-php/pom.xml | 2 +- plugins/plugin-product-info/pom.xml | 2 +- plugins/plugin-python/che-plugin-python-lang-ide/pom.xml | 2 +- plugins/plugin-python/che-plugin-python-lang-server/pom.xml | 2 +- plugins/plugin-python/che-plugin-python-lang-shared/pom.xml | 2 +- plugins/plugin-python/pom.xml | 2 +- plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml | 2 +- plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml | 2 +- plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml | 2 +- plugins/plugin-sdk/pom.xml | 2 +- plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml | 2 +- plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml | 2 +- plugins/plugin-ssh-key/pom.xml | 2 +- plugins/plugin-ssh-machine/pom.xml | 2 +- plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml | 2 +- plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml | 2 +- plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml | 2 +- plugins/plugin-svn/pom.xml | 2 +- plugins/plugin-web/che-plugin-web-ext-web/pom.xml | 2 +- plugins/plugin-web/pom.xml | 2 +- plugins/pom.xml | 4 ++-- pom.xml | 6 +++--- samples/pom.xml | 4 ++-- .../che-sample-plugin-actions-ide/pom.xml | 2 +- samples/sample-plugin-actions/pom.xml | 2 +- .../che-sample-plugin-embedjs-ide/pom.xml | 2 +- samples/sample-plugin-embedjs/pom.xml | 2 +- .../che-sample-plugin-filetype-ide/pom.xml | 2 +- samples/sample-plugin-filetype/pom.xml | 2 +- .../sample-plugin-json/che-sample-plugin-json-ide/pom.xml | 2 +- .../che-sample-plugin-json-server/pom.xml | 2 +- .../che-sample-plugin-json-shared/pom.xml | 2 +- samples/sample-plugin-json/pom.xml | 2 +- .../che-sample-plugin-nativeaccess-ide/pom.xml | 2 +- samples/sample-plugin-nativeaccess/pom.xml | 2 +- .../sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml | 2 +- samples/sample-plugin-parts/pom.xml | 2 +- .../che-sample-plugin-serverservice-ide/pom.xml | 2 +- .../che-sample-plugin-serverservice-server/pom.xml | 2 +- samples/sample-plugin-serverservice/pom.xml | 2 +- .../che-sample-plugin-wizard-ide/pom.xml | 2 +- .../che-sample-plugin-wizard-server/pom.xml | 2 +- .../che-sample-plugin-wizard-shared/pom.xml | 2 +- samples/sample-plugin-wizard/pom.xml | 2 +- wsagent/che-core-api-debug-shared/pom.xml | 2 +- wsagent/che-core-api-debug/pom.xml | 2 +- wsagent/che-core-api-git-shared/pom.xml | 2 +- wsagent/che-core-api-git/pom.xml | 2 +- wsagent/che-core-api-languageserver-shared/pom.xml | 2 +- wsagent/che-core-api-languageserver/pom.xml | 2 +- wsagent/che-core-api-project-shared/pom.xml | 2 +- wsagent/che-core-api-project/pom.xml | 4 ++-- wsagent/che-core-git-impl-jgit/pom.xml | 2 +- wsagent/pom.xml | 4 ++-- wsagent/wsagent-local/pom.xml | 2 +- wsmaster/che-core-api-account/pom.xml | 2 +- wsmaster/che-core-api-agent-shared/pom.xml | 2 +- wsmaster/che-core-api-agent/pom.xml | 2 +- wsmaster/che-core-api-auth/pom.xml | 2 +- wsmaster/che-core-api-factory-shared/pom.xml | 2 +- wsmaster/che-core-api-factory/pom.xml | 2 +- wsmaster/che-core-api-machine-shared/pom.xml | 2 +- wsmaster/che-core-api-machine/pom.xml | 2 +- wsmaster/che-core-api-project-templates-shared/pom.xml | 2 +- wsmaster/che-core-api-project-templates/pom.xml | 2 +- wsmaster/che-core-api-ssh-shared/pom.xml | 2 +- wsmaster/che-core-api-ssh/pom.xml | 2 +- wsmaster/che-core-api-user-shared/pom.xml | 2 +- wsmaster/che-core-api-user/pom.xml | 2 +- wsmaster/che-core-api-workspace-shared/pom.xml | 2 +- wsmaster/che-core-api-workspace/pom.xml | 2 +- wsmaster/che-core-sql-schema/pom.xml | 2 +- wsmaster/integration-tests/cascade-removal/pom.xml | 2 +- wsmaster/integration-tests/pom.xml | 2 +- wsmaster/integration-tests/postgresql-tck/pom.xml | 2 +- wsmaster/pom.xml | 4 ++-- wsmaster/wsmaster-local/pom.xml | 2 +- 206 files changed, 216 insertions(+), 216 deletions(-) diff --git a/assembly/assembly-ide-war/pom.xml b/assembly/assembly-ide-war/pom.xml index b64ef70c81f..4662e4257af 100644 --- a/assembly/assembly-ide-war/pom.xml +++ b/assembly/assembly-ide-war/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT assembly-ide-war war diff --git a/assembly/assembly-main/pom.xml b/assembly/assembly-main/pom.xml index e80f11359bf..c446491c365 100644 --- a/assembly/assembly-main/pom.xml +++ b/assembly/assembly-main/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT assembly-main pom diff --git a/assembly/assembly-wsagent-server/pom.xml b/assembly/assembly-wsagent-server/pom.xml index e518e6df5eb..21f79b0cb63 100644 --- a/assembly/assembly-wsagent-server/pom.xml +++ b/assembly/assembly-wsagent-server/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT assembly-wsagent-server pom diff --git a/assembly/assembly-wsagent-war/pom.xml b/assembly/assembly-wsagent-war/pom.xml index 65dd063b1c5..6722dbcb633 100644 --- a/assembly/assembly-wsagent-war/pom.xml +++ b/assembly/assembly-wsagent-war/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT assembly-wsagent-war war diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index d8348ccd78f..4d5085aaed7 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -16,7 +16,7 @@ che-assembly-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT assembly-wsmaster-war war diff --git a/assembly/pom.xml b/assembly/pom.xml index d84809e1ac0..6f4d643455a 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml org.eclipse.che che-assembly-parent - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT pom Che IDE :: Parent diff --git a/core/che-core-api-core/pom.xml b/core/che-core-api-core/pom.xml index d8a60c5b07f..f1fb03cca5a 100644 --- a/core/che-core-api-core/pom.xml +++ b/core/che-core-api-core/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-core jar diff --git a/core/che-core-api-dto-maven-plugin/pom.xml b/core/che-core-api-dto-maven-plugin/pom.xml index 1a065c01a81..cd388bbbc44 100644 --- a/core/che-core-api-dto-maven-plugin/pom.xml +++ b/core/che-core-api-dto-maven-plugin/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-dto-maven-plugin maven-plugin diff --git a/core/che-core-api-dto/pom.xml b/core/che-core-api-dto/pom.xml index b9481af258d..c787eab4796 100644 --- a/core/che-core-api-dto/pom.xml +++ b/core/che-core-api-dto/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-dto jar diff --git a/core/che-core-api-model/pom.xml b/core/che-core-api-model/pom.xml index db14133e136..cd492e4e002 100644 --- a/core/che-core-api-model/pom.xml +++ b/core/che-core-api-model/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-model jar diff --git a/core/che-core-db-vendor-h2/pom.xml b/core/che-core-db-vendor-h2/pom.xml index d742a0dd33f..d1b86cd707c 100644 --- a/core/che-core-db-vendor-h2/pom.xml +++ b/core/che-core-db-vendor-h2/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-db-vendor-h2 Che Core :: DB :: Vendor H2 diff --git a/core/che-core-db-vendor-postgresql/pom.xml b/core/che-core-db-vendor-postgresql/pom.xml index 5440bf661d8..8cbdf982528 100644 --- a/core/che-core-db-vendor-postgresql/pom.xml +++ b/core/che-core-db-vendor-postgresql/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-db-vendor-postgresql Che Core :: DB :: Vendor PostgreSQL diff --git a/core/che-core-db/pom.xml b/core/che-core-db/pom.xml index a2758240c0b..637d29da40e 100644 --- a/core/che-core-db/pom.xml +++ b/core/che-core-db/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-db Che Core :: DB diff --git a/core/che-core-typescript-dto-maven-plugin/pom.xml b/core/che-core-typescript-dto-maven-plugin/pom.xml index cb34c282edd..411aafa2bea 100644 --- a/core/che-core-typescript-dto-maven-plugin/pom.xml +++ b/core/che-core-typescript-dto-maven-plugin/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core che-core-typescript-dto-maven-plugin diff --git a/core/commons/che-core-commons-annotations/pom.xml b/core/commons/che-core-commons-annotations/pom.xml index 4e8e6acb474..1363ea42fe2 100644 --- a/core/commons/che-core-commons-annotations/pom.xml +++ b/core/commons/che-core-commons-annotations/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-annotations jar diff --git a/core/commons/che-core-commons-inject/pom.xml b/core/commons/che-core-commons-inject/pom.xml index 2e8dd60df36..267ccfae0cb 100644 --- a/core/commons/che-core-commons-inject/pom.xml +++ b/core/commons/che-core-commons-inject/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-inject jar diff --git a/core/commons/che-core-commons-json/pom.xml b/core/commons/che-core-commons-json/pom.xml index 150f9c645c7..d6d32258b69 100644 --- a/core/commons/che-core-commons-json/pom.xml +++ b/core/commons/che-core-commons-json/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-json jar diff --git a/core/commons/che-core-commons-lang/pom.xml b/core/commons/che-core-commons-lang/pom.xml index 3e5a80e0c93..ea8f0cdf002 100644 --- a/core/commons/che-core-commons-lang/pom.xml +++ b/core/commons/che-core-commons-lang/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-lang jar diff --git a/core/commons/che-core-commons-schedule/pom.xml b/core/commons/che-core-commons-schedule/pom.xml index 5ed90cb2063..4e096486ac5 100644 --- a/core/commons/che-core-commons-schedule/pom.xml +++ b/core/commons/che-core-commons-schedule/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-schedule jar diff --git a/core/commons/che-core-commons-test/pom.xml b/core/commons/che-core-commons-test/pom.xml index e81238e99cc..a74a461fba6 100644 --- a/core/commons/che-core-commons-test/pom.xml +++ b/core/commons/che-core-commons-test/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-test jar diff --git a/core/commons/che-core-commons-xml/pom.xml b/core/commons/che-core-commons-xml/pom.xml index c476f322bef..62b093c6d17 100644 --- a/core/commons/che-core-commons-xml/pom.xml +++ b/core/commons/che-core-commons-xml/pom.xml @@ -16,7 +16,7 @@ che-core-commons-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-xml jar diff --git a/core/commons/pom.xml b/core/commons/pom.xml index 929cb24d923..178bb7e9c1b 100644 --- a/core/commons/pom.xml +++ b/core/commons/pom.xml @@ -16,7 +16,7 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-core-commons-parent diff --git a/core/pom.xml b/core/pom.xml index 258899490f5..266e3a78d85 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml org.eclipse.che.core che-core-parent - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT pom Che Core Parent diff --git a/dashboard/pom.xml b/dashboard/pom.xml index 149324cc652..63a4d839843 100644 --- a/dashboard/pom.xml +++ b/dashboard/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml org.eclipse.che.dashboard che-dashboard-war - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT war Che Dashboard :: Web App 2015 diff --git a/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml b/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml index 36ba47e01c6..8a84d6aff32 100644 --- a/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml +++ b/ide/che-core-dyna-provider-generator-maven-plugin/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-dyna-provider-generator-maven-plugin maven-plugin diff --git a/ide/che-core-ide-api/pom.xml b/ide/che-core-ide-api/pom.xml index 2b4b5faf8d2..771dcc56127 100644 --- a/ide/che-core-ide-api/pom.xml +++ b/ide/che-core-ide-api/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core che-core-ide-api diff --git a/ide/che-core-ide-app/pom.xml b/ide/che-core-ide-app/pom.xml index 4cde354d0e5..1db29b814c6 100644 --- a/ide/che-core-ide-app/pom.xml +++ b/ide/che-core-ide-app/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core che-core-ide-app diff --git a/ide/che-core-ide-generators/pom.xml b/ide/che-core-ide-generators/pom.xml index 0e1421fa55b..2b7b169c924 100644 --- a/ide/che-core-ide-generators/pom.xml +++ b/ide/che-core-ide-generators/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core che-core-ide-generators diff --git a/ide/che-core-ide-stacks/pom.xml b/ide/che-core-ide-stacks/pom.xml index 267502c6db2..ae247700e5f 100644 --- a/ide/che-core-ide-stacks/pom.xml +++ b/ide/che-core-ide-stacks/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core che-core-ide-stacks diff --git a/ide/che-core-ide-templates/pom.xml b/ide/che-core-ide-templates/pom.xml index 2e94e7fc39d..83d10dd9041 100644 --- a/ide/che-core-ide-templates/pom.xml +++ b/ide/che-core-ide-templates/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core che-core-ide-templates diff --git a/ide/che-core-ide-ui/pom.xml b/ide/che-core-ide-ui/pom.xml index 1b30a2ec2c5..1dd90ed6bea 100644 --- a/ide/che-core-ide-ui/pom.xml +++ b/ide/che-core-ide-ui/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core che-core-ide-ui diff --git a/ide/commons-gwt/pom.xml b/ide/commons-gwt/pom.xml index 48a43ca7ffe..9360ecccd07 100644 --- a/ide/commons-gwt/pom.xml +++ b/ide/commons-gwt/pom.xml @@ -16,7 +16,7 @@ che-core-ide-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-commons-gwt Che Core :: Commons :: GWT diff --git a/ide/pom.xml b/ide/pom.xml index 35c536d04d0..2b46700a79f 100644 --- a/ide/pom.xml +++ b/ide/pom.xml @@ -16,7 +16,7 @@ che-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml org.eclipse.che.core diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml index dbfc606a65c..be2dc77d34c 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-cpp-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-cpp-lang-ide jar diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml b/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml index dd3fe9d5409..98d3c194332 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-cpp-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-cpp-lang-server Che Plugin :: C/C++ :: Extension Server diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml b/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml index db70380e207..983b3e8354e 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-cpp-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-cpp-lang-shared Che Plugin :: C/C++ :: Shared diff --git a/plugins/plugin-cpp/pom.xml b/plugins/plugin-cpp/pom.xml index ea5a7a1a803..59ddfb87088 100644 --- a/plugins/plugin-cpp/pom.xml +++ b/plugins/plugin-cpp/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-cpp-parent diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml index 0fcda4d427b..c0bf7ef5edf 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-csharp-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-csharp-lang-ide jar diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml b/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml index 69e3e6960dc..d012693abd3 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-csharp-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-csharp-lang-server Che Plugin :: C# :: Extension Server diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml b/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml index 202ebda6354..06b43d47673 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-csharp-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-csharp-lang-shared Che Plugin :: C# :: Shared diff --git a/plugins/plugin-csharp/pom.xml b/plugins/plugin-csharp/pom.xml index 77f7a4f51ba..df09357f2a0 100644 --- a/plugins/plugin-csharp/pom.xml +++ b/plugins/plugin-csharp/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-csharp-parent diff --git a/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml b/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml index 9368cf502fd..9f14281c3cb 100644 --- a/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml +++ b/plugins/plugin-dashboard/che-plugin-ext-dashboard/pom.xml @@ -16,7 +16,7 @@ che-plugin-dashboard-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-ext-dashboard-client jar diff --git a/plugins/plugin-dashboard/pom.xml b/plugins/plugin-dashboard/pom.xml index 4fc7781ef79..0a7fd900515 100644 --- a/plugins/plugin-dashboard/pom.xml +++ b/plugins/plugin-dashboard/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-dashboard-parent diff --git a/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml b/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml index 25cda2e40fc..c4845496426 100644 --- a/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-debugger-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-debugger-ide jar diff --git a/plugins/plugin-debugger/pom.xml b/plugins/plugin-debugger/pom.xml index 48314e3f7f1..63701685980 100644 --- a/plugins/plugin-debugger/pom.xml +++ b/plugins/plugin-debugger/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-debugger-parent diff --git a/plugins/plugin-docker/che-plugin-docker-client/pom.xml b/plugins/plugin-docker/che-plugin-docker-client/pom.xml index 35a536eb4a3..746f89da177 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/pom.xml +++ b/plugins/plugin-docker/che-plugin-docker-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-docker-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-docker-client jar diff --git a/plugins/plugin-docker/che-plugin-docker-compose/pom.xml b/plugins/plugin-docker/che-plugin-docker-compose/pom.xml index d1393e7b4a2..ea855462eae 100644 --- a/plugins/plugin-docker/che-plugin-docker-compose/pom.xml +++ b/plugins/plugin-docker/che-plugin-docker-compose/pom.xml @@ -16,7 +16,7 @@ che-plugin-docker-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-docker-compose jar diff --git a/plugins/plugin-docker/che-plugin-docker-machine/pom.xml b/plugins/plugin-docker/che-plugin-docker-machine/pom.xml index 5713919b4a1..f6d420afe7a 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/pom.xml +++ b/plugins/plugin-docker/che-plugin-docker-machine/pom.xml @@ -16,7 +16,7 @@ che-plugin-docker-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-docker-machine jar diff --git a/plugins/plugin-docker/pom.xml b/plugins/plugin-docker/pom.xml index 018029c443e..956289579fd 100644 --- a/plugins/plugin-docker/pom.xml +++ b/plugins/plugin-docker/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-docker-parent diff --git a/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml b/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml index 63a3cf8d607..a171bb2fc30 100644 --- a/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml +++ b/plugins/plugin-gdb/che-plugin-gdb-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-gdb-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-gdb-ide jar diff --git a/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml b/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml index dd8839450e6..9f0364c5470 100644 --- a/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml +++ b/plugins/plugin-gdb/che-plugin-gdb-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-gdb-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-gdb-server jar diff --git a/plugins/plugin-gdb/pom.xml b/plugins/plugin-gdb/pom.xml index 76354dd0f4c..397a637d051 100644 --- a/plugins/plugin-gdb/pom.xml +++ b/plugins/plugin-gdb/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-gdb-parent pom diff --git a/plugins/plugin-git/che-plugin-git-ext-git/pom.xml b/plugins/plugin-git/che-plugin-git-ext-git/pom.xml index 5aa15dbdc69..b145bd70f7c 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/pom.xml +++ b/plugins/plugin-git/che-plugin-git-ext-git/pom.xml @@ -16,7 +16,7 @@ che-plugin-git-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-git-ext-git jar diff --git a/plugins/plugin-git/pom.xml b/plugins/plugin-git/pom.xml index a751aca065a..e209011f338 100644 --- a/plugins/plugin-git/pom.xml +++ b/plugins/plugin-git/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-git-parent diff --git a/plugins/plugin-github/che-plugin-github-ide/pom.xml b/plugins/plugin-github/che-plugin-github-ide/pom.xml index 7122a8be428..e83dc04fdbe 100644 --- a/plugins/plugin-github/che-plugin-github-ide/pom.xml +++ b/plugins/plugin-github/che-plugin-github-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-github-ide jar diff --git a/plugins/plugin-github/che-plugin-github-oauth2/pom.xml b/plugins/plugin-github/che-plugin-github-oauth2/pom.xml index 584e7bb1ab2..19e0c90364e 100644 --- a/plugins/plugin-github/che-plugin-github-oauth2/pom.xml +++ b/plugins/plugin-github/che-plugin-github-oauth2/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-github-oauth2 jar diff --git a/plugins/plugin-github/che-plugin-github-provider-github/pom.xml b/plugins/plugin-github/che-plugin-github-provider-github/pom.xml index 7c90f460405..6c601c2ccbc 100644 --- a/plugins/plugin-github/che-plugin-github-provider-github/pom.xml +++ b/plugins/plugin-github/che-plugin-github-provider-github/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-github-provider-github Che Plugin :: Github :: Credential provider diff --git a/plugins/plugin-github/che-plugin-github-server/pom.xml b/plugins/plugin-github/che-plugin-github-server/pom.xml index be304b99e41..a5ddd84ec49 100644 --- a/plugins/plugin-github/che-plugin-github-server/pom.xml +++ b/plugins/plugin-github/che-plugin-github-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-github-server jar diff --git a/plugins/plugin-github/che-plugin-github-shared/pom.xml b/plugins/plugin-github/che-plugin-github-shared/pom.xml index 526143e9920..188b4e7a827 100644 --- a/plugins/plugin-github/che-plugin-github-shared/pom.xml +++ b/plugins/plugin-github/che-plugin-github-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-github-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-github-shared Che Plugin :: Github :: Shared diff --git a/plugins/plugin-github/pom.xml b/plugins/plugin-github/pom.xml index 1ac5fac3fc0..2dc03a57307 100644 --- a/plugins/plugin-github/pom.xml +++ b/plugins/plugin-github/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-github-parent diff --git a/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml b/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml index 749db932289..3733519588b 100644 --- a/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml +++ b/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/pom.xml @@ -16,7 +16,7 @@ che-plugin-gwt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-gwt-ext-gwt jar diff --git a/plugins/plugin-gwt/pom.xml b/plugins/plugin-gwt/pom.xml index 38a97c393ce..d31ae328fb8 100644 --- a/plugins/plugin-gwt/pom.xml +++ b/plugins/plugin-gwt/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-gwt-parent diff --git a/plugins/plugin-help/che-plugin-help-ext-client/pom.xml b/plugins/plugin-help/che-plugin-help-ext-client/pom.xml index 51eca8685f4..9e5e4b14861 100644 --- a/plugins/plugin-help/che-plugin-help-ext-client/pom.xml +++ b/plugins/plugin-help/che-plugin-help-ext-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-help-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-help-ext-client jar diff --git a/plugins/plugin-help/pom.xml b/plugins/plugin-help/pom.xml index 6b0895368cc..d35fb30f5a7 100644 --- a/plugins/plugin-help/pom.xml +++ b/plugins/plugin-help/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-help-parent diff --git a/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml b/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml index 3442dbec5cb..85b9cdd30a1 100644 --- a/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml +++ b/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-debugger-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-debugger-ide jar diff --git a/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml b/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml index 8b5f35e925b..119dcb839a9 100644 --- a/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml +++ b/plugins/plugin-java-debugger/che-plugin-java-debugger-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-debugger-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-debugger-server jar diff --git a/plugins/plugin-java-debugger/pom.xml b/plugins/plugin-java-debugger/pom.xml index 1b974da35a7..e4a074b8ce5 100644 --- a/plugins/plugin-java-debugger/pom.xml +++ b/plugins/plugin-java-debugger/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-debugger-parent pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml index f17200d8360..cf3330585f3 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/che-java-testing-classpath-maven-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-classpath org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-classpath-maven-server Che Plugin :: Java Testing :: Maven Classpath diff --git a/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml index 5b066c6c87b..faae69ec2d9 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-classpath/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-classpath pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml index ba705c0744b..455ba6e837e 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml @@ -16,7 +16,7 @@ che-java-testing-core org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-core-ide Che Plugin :: Java Testing :: Core IDE diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml index 43cf7f4ac57..d9ef0352724 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-core org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-core-server Che Plugin :: Java Testing :: Core Server diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml index 7198d320375..c3517761cce 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-shared/pom.xml @@ -16,7 +16,7 @@ che-java-testing-core org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-core-shared Che Plugin :: Java Testing :: Core Shared diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml index 035a80dce20..98bf4094516 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-core pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml index 1a06d473426..0a5fd18c5b1 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-ide/pom.xml @@ -16,7 +16,7 @@ che-java-testing-junit org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-junit-ide Che Plugin :: Java Testing :: JUnit IDE diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml index 1ed22a6d366..e11f4c348a3 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-junit org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-junit-server Che Plugin :: Java Testing :: JUnit Server diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml index 6cf09d1da2a..82bad31dc1c 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/che-java-testing-junit-shared/pom.xml @@ -16,7 +16,7 @@ che-java-testing-junit org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-junit-shared Che Plugin :: Java Testing :: JUnit Shared diff --git a/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml index 5f5c1f1c679..df5a8de7d6d 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-junit/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-junit pom diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml index 7b771d40795..194b18a1e13 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-ide/pom.xml @@ -16,7 +16,7 @@ che-java-testing-testng org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-testng-ide Che Plugin :: Java Testing :: TestNG IDE diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml index c0462c92fbd..65ea905fffd 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/che-java-testing-testng-server/pom.xml @@ -16,7 +16,7 @@ che-java-testing-testng org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-testng-server Che Plugin :: Java Testing :: TestNG Server diff --git a/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml index 04575ac02ec..3a89b2de375 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-testng/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-test-runner-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-java-testing-testng pom diff --git a/plugins/plugin-java-test-runner/pom.xml b/plugins/plugin-java-test-runner/pom.xml index a7dcec61148..3236d4dcbfc 100644 --- a/plugins/plugin-java-test-runner/pom.xml +++ b/plugins/plugin-java-test-runner/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-test-runner-parent pom diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml index ede93739a87..109f60a4055 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filebuffers/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.core.filebuffers jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml index 9e8cd69031a..ac9d2a1a612 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-filesystem/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.core.filesystem jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml index 87972711d4a..12ea4577357 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-core-resources/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.core.resources jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml index 6ccb7eb583b..08a937a9689 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.jdt.ui jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml index 6714c7d31f3..76724579981 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface-text/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.jface.text jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml index 4008aea1d31..3f6cba6f4c1 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jface/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.jface jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml index bcf2af091ef..7bb48b06085 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ltk-core-refactoring/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.ltk.core.refactoring jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml index dd58512d87b..0f6f62f5424 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-search/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.search jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml index d289e6e6239..41814deaa43 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-ui-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-ext-jdt-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.ui.ide jar diff --git a/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml b/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml index 07e1fa2ff70..0c56c9e9494 100644 --- a/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-jdt/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-ext-jdt-parent pom diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml b/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml index 0c416b88edf..cc3506ddcd0 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-ext-lang-client jar diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml b/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml index df50b3c24ad..92cb253a006 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-ext-lang-server Che Plugin :: Java :: Extension Java Server diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml b/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml index ca1ff8fae14..2e16b63e34c 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml +++ b/plugins/plugin-java/che-plugin-java-ext-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-ext-lang-shared Che Plugin :: Java :: Extension Java Shared diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml index d053f516bba..0bc6a8c2d82 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-plain org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-plain-ide jar diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml index f6d2371e41b..ccba26de85a 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-plain org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-plain-server Che Plugin :: Java :: Plain :: Server diff --git a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml index 9af312d87fb..088a10fb79a 100644 --- a/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/che-plugin-java-plain-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-plain org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-plain-shared Che Plugin :: Java :: Plain :: Shared diff --git a/plugins/plugin-java/che-plugin-java-plain/pom.xml b/plugins/plugin-java/che-plugin-java-plain/pom.xml index 7c7983861cf..93cfca960dd 100644 --- a/plugins/plugin-java/che-plugin-java-plain/pom.xml +++ b/plugins/plugin-java/che-plugin-java-plain/pom.xml @@ -16,7 +16,7 @@ che-plugin-java-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-java-plain diff --git a/plugins/plugin-java/pom.xml b/plugins/plugin-java/pom.xml index 8df80e7361b..c44b3b0199e 100644 --- a/plugins/plugin-java/pom.xml +++ b/plugins/plugin-java/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-java-parent diff --git a/plugins/plugin-json/che-plugin-json-server/pom.xml b/plugins/plugin-json/che-plugin-json-server/pom.xml index e63b87cbe55..87edd5e49aa 100644 --- a/plugins/plugin-json/che-plugin-json-server/pom.xml +++ b/plugins/plugin-json/che-plugin-json-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-json-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-json-server Che Plugin :: JSON :: Extension Server diff --git a/plugins/plugin-json/pom.xml b/plugins/plugin-json/pom.xml index 34b59212c51..6431cb9a9e5 100644 --- a/plugins/plugin-json/pom.xml +++ b/plugins/plugin-json/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-json-parent diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml index 41dcbb40309..562bd459cae 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-languageserver-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT .. che-plugin-languageserver-ide diff --git a/plugins/plugin-languageserver/pom.xml b/plugins/plugin-languageserver/pom.xml index 8111df30821..b22d3819f14 100644 --- a/plugins/plugin-languageserver/pom.xml +++ b/plugins/plugin-languageserver/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-languageserver-parent diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml b/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml index 5a47ee2bab5..ab0f9aff1e6 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-machine-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-machine-ext-client jar diff --git a/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml b/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml index dc102e0b188..1cff225a5ca 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml +++ b/plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-machine-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-machine-ext-server diff --git a/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml b/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml index 77eb1c25fe2..0aa0e2b4c1c 100644 --- a/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml +++ b/plugins/plugin-machine/che-plugin-machine-ssh-client/pom.xml @@ -16,7 +16,7 @@ che-plugin-machine-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-machine-ssh-client jar diff --git a/plugins/plugin-machine/pom.xml b/plugins/plugin-machine/pom.xml index e9130a6f249..afd8c520168 100644 --- a/plugins/plugin-machine/pom.xml +++ b/plugins/plugin-machine/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-machine-parent 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 bfaffeddf51..fd4426fac46 100644 --- a/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-generator-archetype/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-maven-generator-archetype jar diff --git a/plugins/plugin-maven/che-plugin-maven-ide/pom.xml b/plugins/plugin-maven/che-plugin-maven-ide/pom.xml index bba6752dd66..ef839a1c912 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-maven-ide Che Plugin :: Maven :: Extension Maven Client diff --git a/plugins/plugin-maven/che-plugin-maven-server/pom.xml b/plugins/plugin-maven/che-plugin-maven-server/pom.xml index 440b408f37c..efc1af469ef 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-maven-server jar diff --git a/plugins/plugin-maven/che-plugin-maven-shared/pom.xml b/plugins/plugin-maven/che-plugin-maven-shared/pom.xml index 49576d3773d..726fa50c72e 100644 --- a/plugins/plugin-maven/che-plugin-maven-shared/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-maven-shared Che Plugin :: Maven :: Extension Maven Shared diff --git a/plugins/plugin-maven/che-plugin-maven-tools/pom.xml b/plugins/plugin-maven/che-plugin-maven-tools/pom.xml index c4d473c2671..666fc463073 100644 --- a/plugins/plugin-maven/che-plugin-maven-tools/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-tools/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-java-maven-tools jar diff --git a/plugins/plugin-maven/maven-server/maven-server-api/pom.xml b/plugins/plugin-maven/maven-server/maven-server-api/pom.xml index ecc02f3f2ea..ce5d11e5cb6 100644 --- a/plugins/plugin-maven/maven-server/maven-server-api/pom.xml +++ b/plugins/plugin-maven/maven-server/maven-server-api/pom.xml @@ -16,7 +16,7 @@ che-maven-server org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT maven-server-api jar diff --git a/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml b/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml index ca099c280be..d7253d18c9d 100644 --- a/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml +++ b/plugins/plugin-maven/maven-server/maven-server-impl/pom.xml @@ -16,7 +16,7 @@ che-maven-server org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT maven-server-impl jar diff --git a/plugins/plugin-maven/maven-server/pom.xml b/plugins/plugin-maven/maven-server/pom.xml index 304d55a17f1..99b73d6559f 100644 --- a/plugins/plugin-maven/maven-server/pom.xml +++ b/plugins/plugin-maven/maven-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-maven-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-maven-server pom diff --git a/plugins/plugin-maven/pom.xml b/plugins/plugin-maven/pom.xml index ab25bf3abdc..9f8f5b5a629 100644 --- a/plugins/plugin-maven/pom.xml +++ b/plugins/plugin-maven/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-maven-parent diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml index 7f12d47ce27..3f85b360ae9 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml +++ b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-debugger-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-nodejs-debugger-ide jar diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml index 8ec1d224303..dbe8e643f59 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml +++ b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-debugger-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-nodejs-debugger-server jar diff --git a/plugins/plugin-nodejs-debugger/pom.xml b/plugins/plugin-nodejs-debugger/pom.xml index f2a4dc0dd41..4eb0a1f1c83 100644 --- a/plugins/plugin-nodejs-debugger/pom.xml +++ b/plugins/plugin-nodejs-debugger/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-nodejs-debugger-parent pom diff --git a/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml b/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml index 3f493afb9eb..2a1b7966bfc 100644 --- a/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml +++ b/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-nodejs-lang-ide jar diff --git a/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml b/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml index b1fc01efb95..2ae1447b494 100644 --- a/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml +++ b/plugins/plugin-nodejs/che-plugin-nodejs-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-nodejs-lang-server Che Plugin :: NodeJs :: Extension Server diff --git a/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml b/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml index 00279d15ea4..0912e6e8ca4 100644 --- a/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml +++ b/plugins/plugin-nodejs/che-plugin-nodejs-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-nodejs-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-nodejs-lang-shared Che Plugin :: NodeJs :: Extension Shared diff --git a/plugins/plugin-nodejs/pom.xml b/plugins/plugin-nodejs/pom.xml index 9ad51ee9776..3e76513594e 100644 --- a/plugins/plugin-nodejs/pom.xml +++ b/plugins/plugin-nodejs/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-nodejs-parent diff --git a/plugins/plugin-orion/che-plugin-orion-compare/pom.xml b/plugins/plugin-orion/che-plugin-orion-compare/pom.xml index 7a46961efdb..b713fbc1e71 100644 --- a/plugins/plugin-orion/che-plugin-orion-compare/pom.xml +++ b/plugins/plugin-orion/che-plugin-orion-compare/pom.xml @@ -16,7 +16,7 @@ che-plugin-orion-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-orion-compare jar diff --git a/plugins/plugin-orion/che-plugin-orion-editor/pom.xml b/plugins/plugin-orion/che-plugin-orion-editor/pom.xml index e5ff4f78b50..2ccec0003b6 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/pom.xml +++ b/plugins/plugin-orion/che-plugin-orion-editor/pom.xml @@ -16,7 +16,7 @@ che-plugin-orion-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-orion-editor diff --git a/plugins/plugin-orion/pom.xml b/plugins/plugin-orion/pom.xml index c8a7bc190ce..0372f977359 100644 --- a/plugins/plugin-orion/pom.xml +++ b/plugins/plugin-orion/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-orion-parent diff --git a/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml b/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml index b40b4e46238..5085cc4a4e4 100644 --- a/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml +++ b/plugins/plugin-php/che-plugin-php-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-php-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-php-lang-ide jar diff --git a/plugins/plugin-php/che-plugin-php-lang-server/pom.xml b/plugins/plugin-php/che-plugin-php-lang-server/pom.xml index c5ee891b2a7..080692c76d0 100644 --- a/plugins/plugin-php/che-plugin-php-lang-server/pom.xml +++ b/plugins/plugin-php/che-plugin-php-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-php-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-php-lang-server Che Plugin :: PHP :: Extension Server diff --git a/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml b/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml index 43ec22f5c7e..18e251ac082 100644 --- a/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml +++ b/plugins/plugin-php/che-plugin-php-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-php-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-php-lang-shared Che Plugin :: PHP :: Shared diff --git a/plugins/plugin-php/pom.xml b/plugins/plugin-php/pom.xml index 2a15c16e234..f734bd540f9 100644 --- a/plugins/plugin-php/pom.xml +++ b/plugins/plugin-php/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-php-parent diff --git a/plugins/plugin-product-info/pom.xml b/plugins/plugin-product-info/pom.xml index 10978e99fa7..19d02d018f1 100644 --- a/plugins/plugin-product-info/pom.xml +++ b/plugins/plugin-product-info/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-product-info diff --git a/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml b/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml index 0aa009dc285..ad20ca82fa1 100644 --- a/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml +++ b/plugins/plugin-python/che-plugin-python-lang-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-python-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-python-lang-ide jar diff --git a/plugins/plugin-python/che-plugin-python-lang-server/pom.xml b/plugins/plugin-python/che-plugin-python-lang-server/pom.xml index 010627dd38f..c65607a9658 100644 --- a/plugins/plugin-python/che-plugin-python-lang-server/pom.xml +++ b/plugins/plugin-python/che-plugin-python-lang-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-python-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-python-lang-server Che Plugin :: Python :: Extension Server diff --git a/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml b/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml index 7e1ee22f0b2..1bd5a687785 100644 --- a/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml +++ b/plugins/plugin-python/che-plugin-python-lang-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-python-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-python-lang-shared che-plugin-python-lang-shared diff --git a/plugins/plugin-python/pom.xml b/plugins/plugin-python/pom.xml index dd54929e1ff..0a93d7184e3 100644 --- a/plugins/plugin-python/pom.xml +++ b/plugins/plugin-python/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-python-parent diff --git a/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml b/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml index b914af3394b..ebd6d597186 100644 --- a/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml +++ b/plugins/plugin-sdk/che-plugin-sdk-env-local/pom.xml @@ -16,7 +16,7 @@ che-plugin-sdk-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-sdk-env-local jar diff --git a/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml b/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml index 9dc63e59386..003c16849b5 100644 --- a/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml +++ b/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/pom.xml @@ -16,7 +16,7 @@ che-plugin-sdk-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-sdk-ext-plugins jar diff --git a/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml b/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml index 34b5da82dce..293b3b2870e 100644 --- a/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml +++ b/plugins/plugin-sdk/che-plugin-sdk-tools/pom.xml @@ -16,7 +16,7 @@ che-plugin-sdk-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-sdk-tools jar diff --git a/plugins/plugin-sdk/pom.xml b/plugins/plugin-sdk/pom.xml index f5aba519d94..cdf9ee0fe56 100644 --- a/plugins/plugin-sdk/pom.xml +++ b/plugins/plugin-sdk/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-sdk-parent diff --git a/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml b/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml index 9fcf3d8e9c4..36936982033 100644 --- a/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml +++ b/plugins/plugin-ssh-key/che-plugin-ssh-key-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-ssh-key-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-ssh-key-ide jar diff --git a/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml b/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml index 1973df104a1..633adffd612 100644 --- a/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml +++ b/plugins/plugin-ssh-key/che-plugin-ssh-key-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-ssh-key-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-ssh-key-server jar diff --git a/plugins/plugin-ssh-key/pom.xml b/plugins/plugin-ssh-key/pom.xml index c94b3a8878d..9a74045e2cd 100644 --- a/plugins/plugin-ssh-key/pom.xml +++ b/plugins/plugin-ssh-key/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-ssh-key-parent diff --git a/plugins/plugin-ssh-machine/pom.xml b/plugins/plugin-ssh-machine/pom.xml index 6d2c7c8aabe..1169abd948c 100644 --- a/plugins/plugin-ssh-machine/pom.xml +++ b/plugins/plugin-ssh-machine/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-ssh-machine diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml b/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml index 9c6dc321a84..a7d7b8e8b6f 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/pom.xml @@ -16,7 +16,7 @@ che-plugin-svn-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-svn-ext-ide jar diff --git a/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml b/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml index 64acffb4b7c..819754be24c 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml +++ b/plugins/plugin-svn/che-plugin-svn-ext-server/pom.xml @@ -16,7 +16,7 @@ che-plugin-svn-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-svn-ext-server jar diff --git a/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml b/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml index 8a4a3e600ed..481439d56f9 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml +++ b/plugins/plugin-svn/che-plugin-svn-ext-shared/pom.xml @@ -16,7 +16,7 @@ che-plugin-svn-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-svn-ext-shared jar diff --git a/plugins/plugin-svn/pom.xml b/plugins/plugin-svn/pom.xml index 41b17ab5a9b..6f638e56f0f 100644 --- a/plugins/plugin-svn/pom.xml +++ b/plugins/plugin-svn/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-svn-parent diff --git a/plugins/plugin-web/che-plugin-web-ext-web/pom.xml b/plugins/plugin-web/che-plugin-web-ext-web/pom.xml index d118b1b4518..221a13b3613 100644 --- a/plugins/plugin-web/che-plugin-web-ext-web/pom.xml +++ b/plugins/plugin-web/che-plugin-web-ext-web/pom.xml @@ -16,7 +16,7 @@ che-plugin-web-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-plugin-web-ext-web jar diff --git a/plugins/plugin-web/pom.xml b/plugins/plugin-web/pom.xml index 19b7c2054f6..e22061b61cc 100644 --- a/plugins/plugin-web/pom.xml +++ b/plugins/plugin-web/pom.xml @@ -16,7 +16,7 @@ che-plugin-parent org.eclipse.che.plugin - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-plugin-web-parent diff --git a/plugins/pom.xml b/plugins/pom.xml index e91e9fe16a2..6356fd1c999 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml org.eclipse.che.plugin che-plugin-parent - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT pom Che Plugin :: Parent diff --git a/pom.xml b/pom.xml index 21157c42c71..cac1871ff37 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ org.eclipse.che che-parent - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT pom Che Parent @@ -36,12 +36,12 @@ scm:git:git@github.com:eclipse/che.git scm:git:git@github.com:eclipse/che.git - 5.0.0-M8 + HEAD https://github.com/eclipse/che 5.0.0-M8 - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT 1.0-beta2 diff --git a/samples/pom.xml b/samples/pom.xml index c4c0f02c16b..5e1c7aa38a7 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -16,12 +16,12 @@ che-parent org.eclipse.che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml org.eclipse.che.sample che-sample-parent - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT pom Che Sample :: Parent diff --git a/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml b/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml index 7672cee1980..85d2c38d044 100644 --- a/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml +++ b/samples/sample-plugin-actions/che-sample-plugin-actions-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-actions-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-actions-ide jar diff --git a/samples/sample-plugin-actions/pom.xml b/samples/sample-plugin-actions/pom.xml index 4d5b5b025aa..e74a2d40ee3 100644 --- a/samples/sample-plugin-actions/pom.xml +++ b/samples/sample-plugin-actions/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-actions-parent diff --git a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml index 143b7122339..0cebd2ab751 100644 --- a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml +++ b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-embedjs-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-embedjs-ide jar diff --git a/samples/sample-plugin-embedjs/pom.xml b/samples/sample-plugin-embedjs/pom.xml index 5a298fd9140..97d0d5cdd8f 100644 --- a/samples/sample-plugin-embedjs/pom.xml +++ b/samples/sample-plugin-embedjs/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-embedjs-parent diff --git a/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml b/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml index b31c8228d0b..1709960f519 100644 --- a/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml +++ b/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-filetype-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-filetype-ide jar diff --git a/samples/sample-plugin-filetype/pom.xml b/samples/sample-plugin-filetype/pom.xml index 8d592ee3b79..48ed3958efd 100644 --- a/samples/sample-plugin-filetype/pom.xml +++ b/samples/sample-plugin-filetype/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-filetype-parent diff --git a/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml b/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml index 51267a25bb1..c4c8831728b 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml +++ b/samples/sample-plugin-json/che-sample-plugin-json-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-json-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-json-ide jar diff --git a/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml b/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml index b01bc49b82d..a1921c937d3 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml +++ b/samples/sample-plugin-json/che-sample-plugin-json-server/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-json-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-json-server Che Sample :: Plugin JSON :: Server diff --git a/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml b/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml index d01edf3738a..cce6abdd221 100644 --- a/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml +++ b/samples/sample-plugin-json/che-sample-plugin-json-shared/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-json-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-json-shared Che Sample :: Plugin JSON :: Shared diff --git a/samples/sample-plugin-json/pom.xml b/samples/sample-plugin-json/pom.xml index 86eb1b5e289..474e44fce7e 100644 --- a/samples/sample-plugin-json/pom.xml +++ b/samples/sample-plugin-json/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-json-parent diff --git a/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml b/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml index 8444e5d9ff3..876bbd085a4 100644 --- a/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml +++ b/samples/sample-plugin-nativeaccess/che-sample-plugin-nativeaccess-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-nativeaccess-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-nativeaccess-ide jar diff --git a/samples/sample-plugin-nativeaccess/pom.xml b/samples/sample-plugin-nativeaccess/pom.xml index 238fda00118..7feb83e23a6 100644 --- a/samples/sample-plugin-nativeaccess/pom.xml +++ b/samples/sample-plugin-nativeaccess/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-nativeaccess-parent diff --git a/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml b/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml index 511eec13ce8..fb596b59d40 100644 --- a/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml +++ b/samples/sample-plugin-parts/che-sample-plugin-parts-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-parts-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-parts-ide jar diff --git a/samples/sample-plugin-parts/pom.xml b/samples/sample-plugin-parts/pom.xml index 6fa558d5b6e..2a36e856f3b 100644 --- a/samples/sample-plugin-parts/pom.xml +++ b/samples/sample-plugin-parts/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-parts-parent diff --git a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml index ef869de4116..20a4f32b85c 100644 --- a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml +++ b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-serverservice-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-serverservice-ide jar diff --git a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml index f41c0f46887..81796dab8b9 100644 --- a/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml +++ b/samples/sample-plugin-serverservice/che-sample-plugin-serverservice-server/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-serverservice-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-serverservice-server Che Sample :: Plugin ServerService :: Server diff --git a/samples/sample-plugin-serverservice/pom.xml b/samples/sample-plugin-serverservice/pom.xml index 1636b2c88c7..23e66602f52 100644 --- a/samples/sample-plugin-serverservice/pom.xml +++ b/samples/sample-plugin-serverservice/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-serverservice-parent diff --git a/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml b/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml index 90660a97315..7c32e7fb203 100644 --- a/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml +++ b/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-wizard-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-wizard-ide jar diff --git a/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml b/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml index c5f303a18c8..5f5b0542df6 100644 --- a/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml +++ b/samples/sample-plugin-wizard/che-sample-plugin-wizard-server/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-wizard-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-wizard-server Che Sample :: Plugin Wizard :: Server diff --git a/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml b/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml index 32ef7a27dee..9ddb06a5feb 100644 --- a/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml +++ b/samples/sample-plugin-wizard/che-sample-plugin-wizard-shared/pom.xml @@ -16,7 +16,7 @@ che-sample-plugin-wizard-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-sample-plugin-wizard-shared Che Sample :: Plugin Wizard :: Shared diff --git a/samples/sample-plugin-wizard/pom.xml b/samples/sample-plugin-wizard/pom.xml index eb35639fbd3..07037de4770 100644 --- a/samples/sample-plugin-wizard/pom.xml +++ b/samples/sample-plugin-wizard/pom.xml @@ -16,7 +16,7 @@ che-sample-parent org.eclipse.che.sample - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml che-sample-plugin-wizard-parent diff --git a/wsagent/che-core-api-debug-shared/pom.xml b/wsagent/che-core-api-debug-shared/pom.xml index 88b39d582de..84f4fe4b0b2 100644 --- a/wsagent/che-core-api-debug-shared/pom.xml +++ b/wsagent/che-core-api-debug-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-debug-shared jar diff --git a/wsagent/che-core-api-debug/pom.xml b/wsagent/che-core-api-debug/pom.xml index d99dc3b9431..cb0bc6b0cce 100644 --- a/wsagent/che-core-api-debug/pom.xml +++ b/wsagent/che-core-api-debug/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-debug Che Core :: API :: Debug diff --git a/wsagent/che-core-api-git-shared/pom.xml b/wsagent/che-core-api-git-shared/pom.xml index 2ea3b031f24..c3162dfb45c 100644 --- a/wsagent/che-core-api-git-shared/pom.xml +++ b/wsagent/che-core-api-git-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-git-shared jar diff --git a/wsagent/che-core-api-git/pom.xml b/wsagent/che-core-api-git/pom.xml index 536c4f88f6c..41e41dcd72a 100644 --- a/wsagent/che-core-api-git/pom.xml +++ b/wsagent/che-core-api-git/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-git jar diff --git a/wsagent/che-core-api-languageserver-shared/pom.xml b/wsagent/che-core-api-languageserver-shared/pom.xml index 3e010a2ceaf..b9c7e5208d1 100644 --- a/wsagent/che-core-api-languageserver-shared/pom.xml +++ b/wsagent/che-core-api-languageserver-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-languageserver-shared jar diff --git a/wsagent/che-core-api-languageserver/pom.xml b/wsagent/che-core-api-languageserver/pom.xml index e18893c0d9d..486edc05db1 100644 --- a/wsagent/che-core-api-languageserver/pom.xml +++ b/wsagent/che-core-api-languageserver/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-languageserver jar diff --git a/wsagent/che-core-api-project-shared/pom.xml b/wsagent/che-core-api-project-shared/pom.xml index aabbf7e6f8f..519e8a2beb5 100644 --- a/wsagent/che-core-api-project-shared/pom.xml +++ b/wsagent/che-core-api-project-shared/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-project-shared jar diff --git a/wsagent/che-core-api-project/pom.xml b/wsagent/che-core-api-project/pom.xml index c876717b71d..09224816502 100644 --- a/wsagent/che-core-api-project/pom.xml +++ b/wsagent/che-core-api-project/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-project jar @@ -101,7 +101,7 @@ org.eclipse.che.core che-core-api-project-shared - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che.core diff --git a/wsagent/che-core-git-impl-jgit/pom.xml b/wsagent/che-core-git-impl-jgit/pom.xml index 4f87779ac4e..a6b1a273f51 100644 --- a/wsagent/che-core-git-impl-jgit/pom.xml +++ b/wsagent/che-core-git-impl-jgit/pom.xml @@ -17,7 +17,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-git-impl-jgit jar diff --git a/wsagent/pom.xml b/wsagent/pom.xml index 0f459ecbaaf..6443d45bc74 100644 --- a/wsagent/pom.xml +++ b/wsagent/pom.xml @@ -16,12 +16,12 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../core/pom.xml org.eclipse.che.core che-agent-parent - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT pom Che Agent Parent diff --git a/wsagent/wsagent-local/pom.xml b/wsagent/wsagent-local/pom.xml index 04133ab431a..081a3542b3f 100644 --- a/wsagent/wsagent-local/pom.xml +++ b/wsagent/wsagent-local/pom.xml @@ -16,7 +16,7 @@ che-agent-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT wsagent-local Che Core :: API :: Agent diff --git a/wsmaster/che-core-api-account/pom.xml b/wsmaster/che-core-api-account/pom.xml index d2e47bd8c67..68bf2241971 100644 --- a/wsmaster/che-core-api-account/pom.xml +++ b/wsmaster/che-core-api-account/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-account Che Core :: API :: Account diff --git a/wsmaster/che-core-api-agent-shared/pom.xml b/wsmaster/che-core-api-agent-shared/pom.xml index e7603f2db46..f050305dc38 100644 --- a/wsmaster/che-core-api-agent-shared/pom.xml +++ b/wsmaster/che-core-api-agent-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-agent-shared jar diff --git a/wsmaster/che-core-api-agent/pom.xml b/wsmaster/che-core-api-agent/pom.xml index 44d65825304..3142202ac63 100644 --- a/wsmaster/che-core-api-agent/pom.xml +++ b/wsmaster/che-core-api-agent/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-agent jar diff --git a/wsmaster/che-core-api-auth/pom.xml b/wsmaster/che-core-api-auth/pom.xml index d4b242c8bb6..92638a2b086 100644 --- a/wsmaster/che-core-api-auth/pom.xml +++ b/wsmaster/che-core-api-auth/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-auth jar diff --git a/wsmaster/che-core-api-factory-shared/pom.xml b/wsmaster/che-core-api-factory-shared/pom.xml index a8904051b3f..eef37e2014c 100644 --- a/wsmaster/che-core-api-factory-shared/pom.xml +++ b/wsmaster/che-core-api-factory-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-factory-shared jar diff --git a/wsmaster/che-core-api-factory/pom.xml b/wsmaster/che-core-api-factory/pom.xml index e095e8eb7d8..b93fd7dafa4 100644 --- a/wsmaster/che-core-api-factory/pom.xml +++ b/wsmaster/che-core-api-factory/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-factory jar diff --git a/wsmaster/che-core-api-machine-shared/pom.xml b/wsmaster/che-core-api-machine-shared/pom.xml index 31f3640ed11..bf525aaf401 100644 --- a/wsmaster/che-core-api-machine-shared/pom.xml +++ b/wsmaster/che-core-api-machine-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-machine-shared jar diff --git a/wsmaster/che-core-api-machine/pom.xml b/wsmaster/che-core-api-machine/pom.xml index b73fdc9986c..323792ac3c1 100644 --- a/wsmaster/che-core-api-machine/pom.xml +++ b/wsmaster/che-core-api-machine/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-machine jar diff --git a/wsmaster/che-core-api-project-templates-shared/pom.xml b/wsmaster/che-core-api-project-templates-shared/pom.xml index ad427c225bd..a5f725a8ac4 100644 --- a/wsmaster/che-core-api-project-templates-shared/pom.xml +++ b/wsmaster/che-core-api-project-templates-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-project-templates-shared Che Core :: API :: Project Templates :: Shared diff --git a/wsmaster/che-core-api-project-templates/pom.xml b/wsmaster/che-core-api-project-templates/pom.xml index e83631d6cbc..8081102a2fe 100644 --- a/wsmaster/che-core-api-project-templates/pom.xml +++ b/wsmaster/che-core-api-project-templates/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-project-templates Che Core :: API :: Project Templates diff --git a/wsmaster/che-core-api-ssh-shared/pom.xml b/wsmaster/che-core-api-ssh-shared/pom.xml index 064650c8163..bb3bf211100 100644 --- a/wsmaster/che-core-api-ssh-shared/pom.xml +++ b/wsmaster/che-core-api-ssh-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-ssh-shared jar diff --git a/wsmaster/che-core-api-ssh/pom.xml b/wsmaster/che-core-api-ssh/pom.xml index 474e60b1636..d1830dcb5e3 100644 --- a/wsmaster/che-core-api-ssh/pom.xml +++ b/wsmaster/che-core-api-ssh/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-ssh jar diff --git a/wsmaster/che-core-api-user-shared/pom.xml b/wsmaster/che-core-api-user-shared/pom.xml index c82e620e4ea..e5df4c8fd51 100644 --- a/wsmaster/che-core-api-user-shared/pom.xml +++ b/wsmaster/che-core-api-user-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-user-shared Che Core :: API :: User :: Shared diff --git a/wsmaster/che-core-api-user/pom.xml b/wsmaster/che-core-api-user/pom.xml index c1e6968b7a8..5f1b39bc91a 100644 --- a/wsmaster/che-core-api-user/pom.xml +++ b/wsmaster/che-core-api-user/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-user Che Core :: API :: User diff --git a/wsmaster/che-core-api-workspace-shared/pom.xml b/wsmaster/che-core-api-workspace-shared/pom.xml index cb962355097..00f88319ff3 100644 --- a/wsmaster/che-core-api-workspace-shared/pom.xml +++ b/wsmaster/che-core-api-workspace-shared/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-workspace-shared jar diff --git a/wsmaster/che-core-api-workspace/pom.xml b/wsmaster/che-core-api-workspace/pom.xml index 4c8cd0bf69e..1fc703c7ebc 100644 --- a/wsmaster/che-core-api-workspace/pom.xml +++ b/wsmaster/che-core-api-workspace/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-api-workspace jar diff --git a/wsmaster/che-core-sql-schema/pom.xml b/wsmaster/che-core-sql-schema/pom.xml index a5185f7e655..c9d2ddfda01 100644 --- a/wsmaster/che-core-sql-schema/pom.xml +++ b/wsmaster/che-core-sql-schema/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT che-core-sql-schema Che Core :: SQL :: Schema diff --git a/wsmaster/integration-tests/cascade-removal/pom.xml b/wsmaster/integration-tests/cascade-removal/pom.xml index 551307ab90e..fcf4907cfbb 100644 --- a/wsmaster/integration-tests/cascade-removal/pom.xml +++ b/wsmaster/integration-tests/cascade-removal/pom.xml @@ -16,7 +16,7 @@ integration-tests-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT cascade-removal Integration Tests :: Cascade Removal diff --git a/wsmaster/integration-tests/pom.xml b/wsmaster/integration-tests/pom.xml index 466c67ec259..c2e28d50f59 100644 --- a/wsmaster/integration-tests/pom.xml +++ b/wsmaster/integration-tests/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../pom.xml integration-tests-parent diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml index c6877b7082e..1913e00f2a7 100644 --- a/wsmaster/integration-tests/postgresql-tck/pom.xml +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -16,7 +16,7 @@ integration-tests-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT postgresql-tck jar diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index 994ffa45a42..767a2167a92 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -16,11 +16,11 @@ che-core-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT ../core/pom.xml che-master-parent - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT pom Che Master Parent diff --git a/wsmaster/wsmaster-local/pom.xml b/wsmaster/wsmaster-local/pom.xml index 6b37a367019..afc2ea2943c 100644 --- a/wsmaster/wsmaster-local/pom.xml +++ b/wsmaster/wsmaster-local/pom.xml @@ -16,7 +16,7 @@ che-master-parent org.eclipse.che.core - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT wsmaster-local Che Core :: API :: Impl Local From 6416d7d63523dff7970eabf8699a869e21eca07c Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 13:00:46 +0000 Subject: [PATCH 58/74] RELEASE:Set next dev versions --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cac1871ff37..dd47d019384 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ https://github.com/eclipse/che - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT 5.0.0-M9-SNAPSHOT 1.0-beta2 From 3ff152e9aa927da8ccd2b9efd1f6530f1c4c691b Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 13:01:20 +0000 Subject: [PATCH 59/74] RELEASE:Set next development version of parent pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dd47d019384..9dfe685afca 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ maven-depmgt-pom org.eclipse.che.depmgt - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT org.eclipse.che che-parent From 5e8ca9e5f376aaeb14789b214e4d5982f80ce6bf Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 13:03:06 +0000 Subject: [PATCH 60/74] Changelog for 5.0.0-M8 --- CHANGELOG.md | 1191 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 798 insertions(+), 393 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73079909417..fdfd5cb1606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,179 @@ # Change Log +## [5.0.0-M8](https://github.com/eclipse/che/tree/5.0.0-M8) (2016-12-07) +[Full Changelog](https://github.com/eclipse/che/compare/5.0.0-M7-artik...5.0.0-M8) + +**Issues with no labels:** + +- maven-server-impl test fails [\#3295](https://github.com/eclipse/che/issues/3295) +- Fail launching agent Terminal [\#3275](https://github.com/eclipse/che/issues/3275) +- Docs reference image eclipse/che-file which doesn't exist [\#3269](https://github.com/eclipse/che/issues/3269) +- Upload a new version of the PHP Language Server [\#3227](https://github.com/eclipse/che/issues/3227) +- che-sample-plugin-json-ide fails to compile [\#3222](https://github.com/eclipse/che/issues/3222) +- Add Clojure Support [\#3217](https://github.com/eclipse/che/issues/3217) +- Is there any possibility from which we can by pass username and password in eclipse che url? [\#3215](https://github.com/eclipse/che/issues/3215) +- Why is there connections between port 4411 and the host where the web browser is opened? [\#3211](https://github.com/eclipse/che/issues/3211) +- Test CPU limits with docker and swarm [\#3198](https://github.com/eclipse/che/issues/3198) +- No refresh in project explorer [\#3195](https://github.com/eclipse/che/issues/3195) +- Upload files into workspace? [\#3194](https://github.com/eclipse/che/issues/3194) +- \[Q\] Issue w/ ws-agent creation when creating project. [\#3190](https://github.com/eclipse/che/issues/3190) +- wsagent 4818 Exception sending context initialized event [\#3184](https://github.com/eclipse/che/issues/3184) +- Failed to change port \(regression\) [\#3179](https://github.com/eclipse/che/issues/3179) +- bazel causes workspace agent to stop responding [\#3178](https://github.com/eclipse/che/issues/3178) +- Is there any way in ehich we can install eclipse che on any virtual machine [\#3172](https://github.com/eclipse/che/issues/3172) +- Can CheConf16 recording play? [\#3148](https://github.com/eclipse/che/issues/3148) +- Moderator as a Contributor [\#3147](https://github.com/eclipse/che/issues/3147) +- Need end point to load project from github branch [\#3134](https://github.com/eclipse/che/issues/3134) +- Fail to start workspace agent [\#3128](https://github.com/eclipse/che/issues/3128) +- Endpoint for create and delete branch in eclipseche--\>git--\>branches [\#3126](https://github.com/eclipse/che/issues/3126) +- Need to push changes to github branch [\#3122](https://github.com/eclipse/che/issues/3122) +- Failed to inject orion editor [\#3118](https://github.com/eclipse/che/issues/3118) +- Cannot create any project in the IDE [\#3114](https://github.com/eclipse/che/issues/3114) +- Does Iresource Model supported in Che? How to achieve Iresource features ? [\#3099](https://github.com/eclipse/che/issues/3099) +- Not able to load eclipse che workspace url in iframe [\#3072](https://github.com/eclipse/che/issues/3072) +- File Sync agent is disabled by default [\#3071](https://github.com/eclipse/che/issues/3071) +- How to run java project in eclipse che [\#3067](https://github.com/eclipse/che/issues/3067) +- Set uncaught exception handler for executors [\#3065](https://github.com/eclipse/che/issues/3065) +- Invalid docker ip address when running by cli [\#3060](https://github.com/eclipse/che/issues/3060) +- Cannot start Eclipse Che using command line tool [\#3058](https://github.com/eclipse/che/issues/3058) +- Are workspaces persistent? [\#3057](https://github.com/eclipse/che/issues/3057) +- Estimate effort to support pull request panel operations with BitBucket \(public and private\) [\#3052](https://github.com/eclipse/che/issues/3052) +- proxying and port exposure.. [\#3037](https://github.com/eclipse/che/issues/3037) +- Add contextual menu associated to right-click action in the editor [\#3030](https://github.com/eclipse/che/issues/3030) +- Wordpress issue www-data:www-data [\#3018](https://github.com/eclipse/che/issues/3018) +- Possibility to develop android with gradle [\#3008](https://github.com/eclipse/che/issues/3008) +- Need to update github url in remotes using swagger [\#2973](https://github.com/eclipse/che/issues/2973) +- Manage empty states in IDE [\#2972](https://github.com/eclipse/che/issues/2972) +- Fail to build che dashboard module using Docker [\#2963](https://github.com/eclipse/che/issues/2963) +- How to change location in origin\(Git--\>Remotes--\>origin\) using curl [\#2951](https://github.com/eclipse/che/issues/2951) +- Can not close Events panel [\#2923](https://github.com/eclipse/che/issues/2923) +- Adding a new project template to custom stack [\#2879](https://github.com/eclipse/che/issues/2879) +- Let users configure the "Z" flag when mouting a volume [\#2874](https://github.com/eclipse/che/issues/2874) +- Wrong behavior of 'get\(\)' method in 'JGitConfigImpl' [\#2870](https://github.com/eclipse/che/issues/2870) +- Cannot build on windows "npm" command not found [\#2858](https://github.com/eclipse/che/issues/2858) +- Overwriting of name of workspace on creation with auto generated value [\#2855](https://github.com/eclipse/che/issues/2855) +- Cordova/Phonegap stacks, templates, and commands [\#2845](https://github.com/eclipse/che/issues/2845) +- maven command does not work [\#2841](https://github.com/eclipse/che/issues/2841) +- Wizard plugin not working [\#2810](https://github.com/eclipse/che/issues/2810) +- Specifying local docker image in stacks.json [\#2806](https://github.com/eclipse/che/issues/2806) +- Compile error [\#2797](https://github.com/eclipse/che/issues/2797) +- CHE using Docker on Mac with Chrome: Can't load project types: Error at Object.window.IDE.eventHandlers.initializationFailed [\#2782](https://github.com/eclipse/che/issues/2782) +- Handle DOCKER\_HOST better [\#2754](https://github.com/eclipse/che/issues/2754) +- Local IDE Mount with docker hangs [\#2742](https://github.com/eclipse/che/issues/2742) +- Documentation for Using Che as an IDE - Intellisense [\#2720](https://github.com/eclipse/che/issues/2720) +- Documentation for Workspace Administration - Workspace Agents [\#2718](https://github.com/eclipse/che/issues/2718) +- Documentation for Workspace Administration - Runtime Machines [\#2716](https://github.com/eclipse/che/issues/2716) +- Documentation for Workspace Administration - Runtime Recipes [\#2688](https://github.com/eclipse/che/issues/2688) +- yellow on white hard to read [\#2676](https://github.com/eclipse/che/issues/2676) +- Investigate how to add possibility to limit CPU consumption by containers. [\#2630](https://github.com/eclipse/che/issues/2630) +- Consider Adding Default Profiles for Maven Build [\#2594](https://github.com/eclipse/che/issues/2594) +- How to authenticate against bitbucket? [\#2581](https://github.com/eclipse/che/issues/2581) +- Cannot Paste commands in Command Definition Window [\#2579](https://github.com/eclipse/che/issues/2579) +- Problems with Eclipse Che build. [\#2576](https://github.com/eclipse/che/issues/2576) +- Port Eclipse Che for POWER \(ppc64le\) [\#2510](https://github.com/eclipse/che/issues/2510) +- How would I preview a typical LAMP project? [\#2497](https://github.com/eclipse/che/issues/2497) +- Highlight issue with custom editor and multiple extension file [\#2488](https://github.com/eclipse/che/issues/2488) +- Problem using Bridge Mode for Server and Workspace Containers \(can't use --net=host\) [\#2450](https://github.com/eclipse/che/issues/2450) +- CLI - che mount Fails [\#2442](https://github.com/eclipse/che/issues/2442) +- dotnet workspace can't create donet/c\# project [\#2374](https://github.com/eclipse/che/issues/2374) +- Cannot paste \(Ctrl+V\) into Text Area widget [\#2329](https://github.com/eclipse/che/issues/2329) +- Request: for better UI on IDE especially for terminal [\#2231](https://github.com/eclipse/che/issues/2231) +- How to integrate Eclipse Che with Perforce or GitSwarm. [\#2201](https://github.com/eclipse/che/issues/2201) +- Preparing a Workspace with a Maven Project [\#2191](https://github.com/eclipse/che/issues/2191) +- Malformed Host Header error on Che startup [\#2124](https://github.com/eclipse/che/issues/2124) +- Orion editor - Highlight issue [\#2078](https://github.com/eclipse/che/issues/2078) +- Improve configurability for third party tools [\#1894](https://github.com/eclipse/che/issues/1894) +- Add third dependency SmartGWT to the che [\#1886](https://github.com/eclipse/che/issues/1886) +- State of the multi-module project is not restored [\#1782](https://github.com/eclipse/che/issues/1782) +- Running workspace results in IOException: Docker image build failed [\#1766](https://github.com/eclipse/che/issues/1766) +- Che git will display empty cell if remote git url starts with spaces [\#638](https://github.com/eclipse/che/issues/638) +- Create GET method to return snapshot configuration [\#3287](https://github.com/eclipse/che/issues/3287) +- Not able to run che with cli [\#3276](https://github.com/eclipse/che/issues/3276) +- Eclipse Che CLI Refactoring + Improvements : phase 1 [\#3229](https://github.com/eclipse/che/issues/3229) +- Import project from dashboard does not work [\#3226](https://github.com/eclipse/che/issues/3226) +- Apaide? Should maybe be Apache? [\#3205](https://github.com/eclipse/che/issues/3205) +- "Restoring project structure..." loader doesn't hide in the workspace without projects. [\#3181](https://github.com/eclipse/che/issues/3181) +- The editor has wrong behavior after restart workspace [\#3175](https://github.com/eclipse/che/issues/3175) +- Workspace does not start from 'Bitnami Codeigniter' stack on dashboard [\#3173](https://github.com/eclipse/che/issues/3173) +- org.eclipse.che.ws-agent should check java version before starting [\#3137](https://github.com/eclipse/che/issues/3137) +- Cannot start workspace [\#3062](https://github.com/eclipse/che/issues/3062) +- Remove temporary workspaces on server shutdown [\#3044](https://github.com/eclipse/che/issues/3044) +- Create and edit workspace using raw config [\#3025](https://github.com/eclipse/che/issues/3025) +- The expanded project is collapsed when workspace is restarted \(regression\) [\#3021](https://github.com/eclipse/che/issues/3021) +- Unexpected enabling of the button create workspace [\#3019](https://github.com/eclipse/che/issues/3019) +- Cannot start a workspace from centos:6.6 [\#3011](https://github.com/eclipse/che/issues/3011) +- Cascade deletion of projects with the same storage fails [\#2993](https://github.com/eclipse/che/issues/2993) +- Adding ssh key by OAuth GitHub form does not work [\#2988](https://github.com/eclipse/che/issues/2988) +- REST method for batch creating Projects suitable for both import and generate [\#2937](https://github.com/eclipse/che/issues/2937) +- Switching editor tabs should move the highlight in the project explorer [\#2934](https://github.com/eclipse/che/issues/2934) +- Docker networks are not deleted when the corresponding workspace is stopped [\#2930](https://github.com/eclipse/che/issues/2930) +- Git history area is not restored after refresh page \(regression\) [\#2924](https://github.com/eclipse/che/issues/2924) +- Use OpenJDK in che-server CentOS Dockerfile [\#2916](https://github.com/eclipse/che/issues/2916) +- can not clone from IP adress in the URL [\#2915](https://github.com/eclipse/che/issues/2915) +- Updating .NET Core Template and Maintainer [\#2862](https://github.com/eclipse/che/issues/2862) +- Find in path does not work [\#2816](https://github.com/eclipse/che/issues/2816) +- Performance issues with code completion [\#2815](https://github.com/eclipse/che/issues/2815) +- Unexpected loss of focus on the project \(regression\) [\#2795](https://github.com/eclipse/che/issues/2795) +- Use relative link to recipe in workspace environment if possible [\#2769](https://github.com/eclipse/che/issues/2769) +- Implement schema initialization/migration components [\#2768](https://github.com/eclipse/che/issues/2768) +- Unexpected notification about updating a file after refactoring operation \(regression\) [\#2745](https://github.com/eclipse/che/issues/2745) +- Add possibility expand of nodes for a project in the Project tree [\#2724](https://github.com/eclipse/che/issues/2724) +- C\# icon has word "c\#" which makes it seem like a duplicate [\#2614](https://github.com/eclipse/che/issues/2614) +- Improved behavior when selecting stack [\#2568](https://github.com/eclipse/che/issues/2568) +- Rename .codenvy --\> .che [\#2550](https://github.com/eclipse/che/issues/2550) +- Manage stack testing [\#2520](https://github.com/eclipse/che/issues/2520) +- Creating a workspace from definition file doesn't work [\#2489](https://github.com/eclipse/che/issues/2489) +- Wrong synchronization of content in editor after split [\#2391](https://github.com/eclipse/che/issues/2391) +- Not all editor tabs are closed after stopping workspace \(regression\) [\#2372](https://github.com/eclipse/che/issues/2372) +- Java package collapses in explorer after some file move operations \(regression\) [\#2367](https://github.com/eclipse/che/issues/2367) +- command instruction not supported in compose file [\#2365](https://github.com/eclipse/che/issues/2365) +- Chefile Phase 2 [\#2266](https://github.com/eclipse/che/issues/2266) +- Wrong behavior when refactor rename package [\#1776](https://github.com/eclipse/che/issues/1776) +- Unable to remove SSH key when including invalid characters [\#1661](https://github.com/eclipse/che/issues/1661) +- Terminal doesn't recieve Alt Gr characters [\#671](https://github.com/eclipse/che/issues/671) + +**Pull requests merged:** + +- RELEASE: set tag versions [\#3306](https://github.com/eclipse/che/pull/3306) ([riuvshin](https://github.com/riuvshin)) +- Start eclipse/che-server docker image as root by default [\#3297](https://github.com/eclipse/che/pull/3297) ([benoitf](https://github.com/benoitf)) +- fix typo [\#3285](https://github.com/eclipse/che/pull/3285) ([akurinnoy](https://github.com/akurinnoy)) +- Send LineConsumerFactory to ProjectManager, improve RequestDispatcher [\#3240](https://github.com/eclipse/che/pull/3240) ([gazarenkov](https://github.com/gazarenkov)) +- Fix ssh client calls for UD and CLI [\#3238](https://github.com/eclipse/che/pull/3238) ([benoitf](https://github.com/benoitf)) +- Save state of expanded containers when refactoring operations are performed [\#3231](https://github.com/eclipse/che/pull/3231) ([vzhukovskii](https://github.com/vzhukovskii)) +- Fix import projects by URL, from GitHub [\#3225](https://github.com/eclipse/che/pull/3225) ([ashumilova](https://github.com/ashumilova)) +- CHE-3175: close all editors on WS stop event [\#3193](https://github.com/eclipse/che/pull/3193) ([vparfonov](https://github.com/vparfonov)) +- Set tooltip with refresh description to the correct button [\#3189](https://github.com/eclipse/che/pull/3189) ([vzhukovskii](https://github.com/vzhukovskii)) +- Unexpected loss of focus on the project [\#3170](https://github.com/eclipse/che/pull/3170) ([vzhukovskii](https://github.com/vzhukovskii)) +- Correct handling parent element during creating new resource [\#3166](https://github.com/eclipse/che/pull/3166) ([vzhukovskii](https://github.com/vzhukovskii)) +- Add ability to auto select first node when tree becomes visible and it has at least one node [\#3163](https://github.com/eclipse/che/pull/3163) ([vzhukovskii](https://github.com/vzhukovskii)) +- Fix $CHE\_DOCKER\_MACHINE\_HOST\_EXTERNAL variable in docker.sh [\#3158](https://github.com/eclipse/che/pull/3158) ([l0rd](https://github.com/l0rd)) +- Performance improvements and other fixes in code completion [\#3146](https://github.com/eclipse/che/pull/3146) ([kaloyan-raev](https://github.com/kaloyan-raev)) +- CODENVY-593: fix workspace stopping [\#3133](https://github.com/eclipse/che/pull/3133) ([garagatyi](https://github.com/garagatyi)) +- Issue 3029 - Add a 'warning' state for the notifications [\#3113](https://github.com/eclipse/che/pull/3113) ([xcoulon](https://github.com/xcoulon)) +- fix position for toolbar buttons [\#3097](https://github.com/eclipse/che/pull/3097) ([olexii4](https://github.com/olexii4)) +- CHE-2157: preparation for merge https://github.com/eclipse/che/pull/2157 [\#3095](https://github.com/eclipse/che/pull/3095) ([vparfonov](https://github.com/vparfonov)) +- debugger improvement [\#3090](https://github.com/eclipse/che/pull/3090) ([olexii4](https://github.com/olexii4)) +- Calculate common path for several paths [\#3089](https://github.com/eclipse/che/pull/3089) ([vzhukovskii](https://github.com/vzhukovskii)) +- Add hotkey for expand/collapse project tree [\#3083](https://github.com/eclipse/che/pull/3083) ([vzhukovskii](https://github.com/vzhukovskii)) +- Introduced after user remove event [\#3056](https://github.com/eclipse/che/pull/3056) ([skabashnyuk](https://github.com/skabashnyuk)) +- Update Bitnami stacks to latest versions [\#3051](https://github.com/eclipse/che/pull/3051) ([amrecio](https://github.com/amrecio)) +- CHE-2520: add stack testing widget [\#3050](https://github.com/eclipse/che/pull/3050) ([olexii4](https://github.com/olexii4)) +- Improve workspace creating flow [\#3028](https://github.com/eclipse/che/pull/3028) ([akurinnoy](https://github.com/akurinnoy)) +- Make it possible to use relative links to recipe in workspace environment [\#3002](https://github.com/eclipse/che/pull/3002) ([mshaposhnik](https://github.com/mshaposhnik)) +- CODENVY-1076: Fix URL provided by Project API [\#2989](https://github.com/eclipse/che/pull/2989) ([vparfonov](https://github.com/vparfonov)) +- CHE-2874 Let users configure the 'Z' flag when mouting a volume [\#2921](https://github.com/eclipse/che/pull/2921) ([snjeza](https://github.com/snjeza)) +- che\#2550: replaced .codenvy folder to .che [\#2919](https://github.com/eclipse/che/pull/2919) ([vparfonov](https://github.com/vparfonov)) +- CHE-2365: Add deserializer for 'command' field ComposeServiceImpl. [\#2807](https://github.com/eclipse/che/pull/2807) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- CODENVY-587: Handle closed consumers in composite line comsumer [\#2549](https://github.com/eclipse/che/pull/2549) ([mmorhun](https://github.com/mmorhun)) + +## [5.0.0-M7-artik](https://github.com/eclipse/che/tree/5.0.0-M7-artik) (2016-11-11) +[Full Changelog](https://github.com/eclipse/che/compare/5.0.0-M7...5.0.0-M7-artik) + +**Issues with no labels:** + +- Endpoint for removing origin in eclipse che [\#3047](https://github.com/eclipse/che/issues/3047) +- Dockerfile for the codenvy/mysql image? [\#2991](https://github.com/eclipse/che/issues/2991) + ## [5.0.0-M7](https://github.com/eclipse/che/tree/5.0.0-M7) (2016-11-10) [Full Changelog](https://github.com/eclipse/che/compare/5.0.0-M6...5.0.0-M7) @@ -16,7 +190,6 @@ - WS Fails Creation - Zombie Docker Networks [\#2945](https://github.com/eclipse/che/issues/2945) - Che launcher is not working if CHE\_VERSION is not set to 'nightly' [\#2943](https://github.com/eclipse/che/issues/2943) - Processes panel's size is not restored after refresh page [\#2926](https://github.com/eclipse/che/issues/2926) -- Git history area is not restored after refresh page \(regression\) [\#2924](https://github.com/eclipse/che/issues/2924) - This Linux user is not in 'docker' group [\#2922](https://github.com/eclipse/che/issues/2922) - Small question: what is inside eclipse/che:latest - where to find the dockerfile? [\#2917](https://github.com/eclipse/che/issues/2917) - On Mac, Running che command throws error `/usr/local/bin/che: line 165: init\_global\_variables: command not found` [\#2890](https://github.com/eclipse/che/issues/2890) @@ -41,6 +214,7 @@ - Ws-agent has stopped in some case [\#1817](https://github.com/eclipse/che/issues/1817) - Workspace creation/edit view recasting and extending with new item [\#1767](https://github.com/eclipse/che/issues/1767) - Workspace Connection Error eclipse-che-4.2.0 [\#1149](https://github.com/eclipse/che/issues/1149) +- Release and ship Che 5.0.0-M7 [\#3043](https://github.com/eclipse/che/issues/3043) - Windows boot2docker fails starting new che-server under certain conditions [\#3024](https://github.com/eclipse/che/issues/3024) - Wrong behavior of panel 'Processes' after refresh \(regression\) [\#3001](https://github.com/eclipse/che/issues/3001) - A lot of space is used for empty panel [\#2987](https://github.com/eclipse/che/issues/2987) @@ -50,6 +224,7 @@ - Cannot save previewURL into a command \(regression\) [\#2966](https://github.com/eclipse/che/issues/2966) - OAuth protocol from github does not work [\#2944](https://github.com/eclipse/che/issues/2944) - fix usage of CHE\_DATA in Che Server [\#2941](https://github.com/eclipse/che/issues/2941) +- 5.0.0-M7 Milestone Plan [\#2935](https://github.com/eclipse/che/issues/2935) - Detect and stop/remove Machines not counted by API \(regression\) [\#2927](https://github.com/eclipse/che/issues/2927) - Incorrect alignements in Stack screen [\#2893](https://github.com/eclipse/che/issues/2893) - The number of machines is not correctly displayed in the tree if you add workspace using URL [\#2892](https://github.com/eclipse/che/issues/2892) @@ -69,48 +244,12 @@ - Add ability to define stack's components [\#2517](https://github.com/eclipse/che/issues/2517) - Add ability to set stack's category \(advanced, general\) [\#2516](https://github.com/eclipse/che/issues/2516) - Add ability to configure machines inside stack definition [\#2515](https://github.com/eclipse/che/issues/2515) -- Not all editor tabs are closed after stopping workspace \(regression\) [\#2372](https://github.com/eclipse/che/issues/2372) +- User Workspace SSH Improvements [\#2059](https://github.com/eclipse/che/issues/2059) - Simplify names of che.properties to be user friendly [\#2015](https://github.com/eclipse/che/issues/2015) - Remove workspace id from websocket connection path to master [\#1787](https://github.com/eclipse/che/issues/1787) **Pull requests merged:** -- Correct processing reload depth when there is not any resource exists [\#3035](https://github.com/eclipse/che/pull/3035) ([vzhukovskii](https://github.com/vzhukovskii)) -- Allow modifying command attributes [\#3034](https://github.com/eclipse/che/pull/3034) ([vzhukovskii](https://github.com/vzhukovskii)) -- Fix BeforeWorkspaceRemovedEvent publishing [\#3012](https://github.com/eclipse/che/pull/3012) ([akorneta](https://github.com/akorneta)) -- Fix failed test after PR\#3005 [\#3007](https://github.com/eclipse/che/pull/3007) ([vparfonov](https://github.com/vparfonov)) -- fix some issues with restoring state [\#3005](https://github.com/eclipse/che/pull/3005) ([evidolob](https://github.com/evidolob)) -- CHE-2349: Set skip root folder - false by default [\#3003](https://github.com/eclipse/che/pull/3003) ([vparfonov](https://github.com/vparfonov)) -- Update the name, descriptions of agents [\#2994](https://github.com/eclipse/che/pull/2994) ([benoitf](https://github.com/benoitf)) -- Fix load commands [\#2986](https://github.com/eclipse/che/pull/2986) ([vparfonov](https://github.com/vparfonov)) -- CODENVY-1094: Fix git init command [\#2985](https://github.com/eclipse/che/pull/2985) ([vinokurig](https://github.com/vinokurig)) -- Fix git client service branch list and diff methods [\#2982](https://github.com/eclipse/che/pull/2982) ([vinokurig](https://github.com/vinokurig)) -- perform save only if editor has changes [\#2975](https://github.com/eclipse/che/pull/2975) ([evidolob](https://github.com/evidolob)) -- Always respond with an error if trying to start a running workspace [\#2974](https://github.com/eclipse/che/pull/2974) ([evoevodin](https://github.com/evoevodin)) -- Set Log level to warn [\#2961](https://github.com/eclipse/che/pull/2961) ([vparfonov](https://github.com/vparfonov)) -- CHE-2830: Fix php agent [\#2959](https://github.com/eclipse/che/pull/2959) ([tolusha](https://github.com/tolusha)) -- CHE-2689 Improve selected state in textfield for dark theme [\#2958](https://github.com/eclipse/che/pull/2958) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- Follow up fixes after configuration property renaming [\#2955](https://github.com/eclipse/che/pull/2955) ([mkuznyetsov](https://github.com/mkuznyetsov)) -- Rework Tck tests to use TckListener instead of TckModuleFactory [\#2953](https://github.com/eclipse/che/pull/2953) ([sleshchenko](https://github.com/sleshchenko)) -- CHE-2927: Add logs for active containers checked by DockerContainerCleaner. [\#2950](https://github.com/eclipse/che/pull/2950) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) -- CHE-2883 Git importer - convertToTopLevelProject feature [\#2946](https://github.com/eclipse/che/pull/2946) ([skabashnyuk](https://github.com/skabashnyuk)) -- CHE-2832: Fix tests [\#2939](https://github.com/eclipse/che/pull/2939) ([tolusha](https://github.com/tolusha)) -- CHE-2888: Fix pull requests-build due to git tests. [\#2932](https://github.com/eclipse/che/pull/2932) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) -- CHE-2564: Fix build [\#2929](https://github.com/eclipse/che/pull/2929) ([tolusha](https://github.com/tolusha)) -- CODENVY-932 Stopped IDE should provide clear state and options to the user [\#2914](https://github.com/eclipse/che/pull/2914) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- Small improvement in Zend stack [\#2910](https://github.com/eclipse/che/pull/2910) ([kaloyan-raev](https://github.com/kaloyan-raev)) -- ARTIK-152: Show all machines in the Processes panel [\#2909](https://github.com/eclipse/che/pull/2909) ([svor](https://github.com/svor)) -- CHE-1787: Remove workspace id from websocket connection path to master [\#2907](https://github.com/eclipse/che/pull/2907) ([vinokurig](https://github.com/vinokurig)) -- Fix code after merging eclipse/che\#1571 [\#2906](https://github.com/eclipse/che/pull/2906) ([vparfonov](https://github.com/vparfonov)) -- Introduced PlatformIO stack with couple of samples [\#2887](https://github.com/eclipse/che/pull/2887) ([skabashnyuk](https://github.com/skabashnyuk)) -- \#2459 store and restore IDE state: opened files, opened part and their size [\#2880](https://github.com/eclipse/che/pull/2880) ([evidolob](https://github.com/evidolob)) -- Fix mistake in comment [\#2871](https://github.com/eclipse/che/pull/2871) ([azatsarynnyy](https://github.com/azatsarynnyy)) -- CHE-2832: Add servers to Agent description and propagate them to Workspace Runtime [\#2868](https://github.com/eclipse/che/pull/2868) ([tolusha](https://github.com/tolusha)) -- Get projects after workspace has been already initialized [\#2867](https://github.com/eclipse/che/pull/2867) ([vzhukovskii](https://github.com/vzhukovskii)) -- Support array format for environment in compose file [\#2865](https://github.com/eclipse/che/pull/2865) ([dmytro-ndp](https://github.com/dmytro-ndp)) -- Render hover messages according to LSP specification [\#2856](https://github.com/eclipse/che/pull/2856) ([kaloyan-raev](https://github.com/kaloyan-raev)) -- Fix broken links section in docker-compose recipe [\#2850](https://github.com/eclipse/che/pull/2850) ([mmorhun](https://github.com/mmorhun)) -- Replace Crane with felixfbecker PHP Language Server [\#2830](https://github.com/eclipse/che/pull/2830) ([kaloyan-raev](https://github.com/kaloyan-raev)) - Change ssh text displayed in the IDE [\#3045](https://github.com/eclipse/che/pull/3045) ([benoitf](https://github.com/benoitf)) - CODENVY-804 : Use of userManager to get the userId \(when injecting ssh keys\) [\#3036](https://github.com/eclipse/che/pull/3036) ([benoitf](https://github.com/benoitf)) - cli: che ssh and che mount commands [\#3033](https://github.com/eclipse/che/pull/3033) ([benoitf](https://github.com/benoitf)) @@ -176,14 +315,12 @@ - Docker Store - Common Vulnerabilities and Exposures\(Docker Image\) [\#2534](https://github.com/eclipse/che/issues/2534) - Wrong behavior after delete project on dashboard [\#2527](https://github.com/eclipse/che/issues/2527) - Data type mismatch in JpaUserDao\#getAll\(\) method [\#2524](https://github.com/eclipse/che/issues/2524) -- Add scrollbars to terminal [\#2423](https://github.com/eclipse/che/issues/2423) - Iterative improvements to simplify usage of che in che scenarios [\#2116](https://github.com/eclipse/che/issues/2116) - Study Initial schema generation and how to make changes in model after migration to single database [\#2110](https://github.com/eclipse/che/issues/2110) - Wrong behavior while creating project from maven archetype [\#2098](https://github.com/eclipse/che/issues/2098) - Wrong behavior after rename not java files [\#1821](https://github.com/eclipse/che/issues/1821) - Support for Language Server Protocol [\#1287](https://github.com/eclipse/che/issues/1287) - Release and ship Che 5.0.0-M6 [\#2891](https://github.com/eclipse/che/issues/2891) -- Find in path does not work [\#2816](https://github.com/eclipse/che/issues/2816) - Some commands that have worked through bash shell, can work wrong \(regression\) [\#2811](https://github.com/eclipse/che/issues/2811) - Unexpected error message 'Machine id' not found after refreshing a browser \(regression\) [\#2794](https://github.com/eclipse/che/issues/2794) - Amount of machines is not correctly displayed in process tree \[Regression\] [\#2775](https://github.com/eclipse/che/issues/2775) @@ -191,6 +328,7 @@ - Implement args syntax of build section in compose environment [\#2661](https://github.com/eclipse/che/issues/2661) - Documentation for Workspace Administration - Intro [\#2659](https://github.com/eclipse/che/issues/2659) - Leak of open file descriptors [\#2633](https://github.com/eclipse/che/issues/2633) +- Docker Store - Common Vulnerabilities and Exposures\(Che's Binary\) [\#2533](https://github.com/eclipse/che/issues/2533) - Do not try to connect to terminal if terminal agent not found in machine config [\#2472](https://github.com/eclipse/che/issues/2472) - Send schema associations to JSON language server [\#2471](https://github.com/eclipse/che/issues/2471) - Dev agent is not deployed to all machines [\#2467](https://github.com/eclipse/che/issues/2467) @@ -207,38 +345,6 @@ **Pull requests merged:** -- Revert "CHE-2775 Amount of machines is not correctly displayed in process tree" [\#2886](https://github.com/eclipse/che/pull/2886) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- CHE-2775 Amount of machines is not correctly displayed in process tree [\#2885](https://github.com/eclipse/che/pull/2885) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- \#2695 add checks for null value for some LS capabuilities [\#2884](https://github.com/eclipse/che/pull/2884) ([evidolob](https://github.com/evidolob)) -- Enable 'keepVcs' property when importing with sparse checkout [\#2882](https://github.com/eclipse/che/pull/2882) ([vinokurig](https://github.com/vinokurig)) -- \#2729 do not send file operation messages if LS doesn't exist [\#2881](https://github.com/eclipse/che/pull/2881) ([evidolob](https://github.com/evidolob)) -- Ability to set visibility state for machine plugin central toolbar items [\#2873](https://github.com/eclipse/che/pull/2873) ([dkuleshov](https://github.com/dkuleshov)) -- CHE-2098: fix generation Project with Maven Archetype [\#2872](https://github.com/eclipse/che/pull/2872) ([vparfonov](https://github.com/vparfonov)) -- CHE-2816. Correctly applying exclude filters at indexing files [\#2857](https://github.com/eclipse/che/pull/2857) ([RomanNikitenko](https://github.com/RomanNikitenko)) -- Add missing dependencies to build all sample plugins [\#2854](https://github.com/eclipse/che/pull/2854) ([slemeur](https://github.com/slemeur)) -- fix CodeMirror version [\#2843](https://github.com/eclipse/che/pull/2843) ([akurinnoy](https://github.com/akurinnoy)) -- Fix test which periodically failed. [\#2835](https://github.com/eclipse/che/pull/2835) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) -- Fix locking in StrippedLocks class [\#2833](https://github.com/eclipse/che/pull/2833) ([garagatyi](https://github.com/garagatyi)) -- Add workspace 'SNAPSHOTTING' status [\#2829](https://github.com/eclipse/che/pull/2829) ([evoevodin](https://github.com/evoevodin)) -- CHE-2633: Fix leak of file descriptors [\#2826](https://github.com/eclipse/che/pull/2826) ([mmorhun](https://github.com/mmorhun)) -- CHE-2794. Provide machine node to run new terminal [\#2823](https://github.com/eclipse/che/pull/2823) ([RomanNikitenko](https://github.com/RomanNikitenko)) -- Fix policies hashCode [\#2812](https://github.com/eclipse/che/pull/2812) ([akorneta](https://github.com/akorneta)) -- Add toolbar buttons for the contextual commands [\#2809](https://github.com/eclipse/che/pull/2809) ([azatsarynnyy](https://github.com/azatsarynnyy)) -- Add toolbar buttons for the contextual commands [\#2808](https://github.com/eclipse/che/pull/2808) ([azatsarynnyy](https://github.com/azatsarynnyy)) -- Provide instructions about to build each of the plugin samples includ… [\#2803](https://github.com/eclipse/che/pull/2803) ([slemeur](https://github.com/slemeur)) -- Remove returning of optional by getNextPageRef and getPreviousPageRef methods [\#2801](https://github.com/eclipse/che/pull/2801) ([sleshchenko](https://github.com/sleshchenko)) -- Fix ws agent msg [\#2798](https://github.com/eclipse/che/pull/2798) ([svor](https://github.com/svor)) -- Fix failing Closure Compiling in case GWT JavaScript compiler output style set to DETAILED mode [\#2796](https://github.com/eclipse/che/pull/2796) ([azatsarynnyy](https://github.com/azatsarynnyy)) -- Fix NPE in ServerImpl constructor [\#2793](https://github.com/eclipse/che/pull/2793) ([evoevodin](https://github.com/evoevodin)) -- Make arduino files looks like C++ files [\#2772](https://github.com/eclipse/che/pull/2772) ([skabashnyuk](https://github.com/skabashnyuk)) -- Add flushing to save order of object on persisting [\#2770](https://github.com/eclipse/che/pull/2770) ([sleshchenko](https://github.com/sleshchenko)) -- CHE-1622:Update JsonExampleEditorProvider Code Example [\#2766](https://github.com/eclipse/che/pull/2766) ([vparfonov](https://github.com/vparfonov)) -- Apply non-strict rules for PT appliance on project import to avoid wo… [\#2765](https://github.com/eclipse/che/pull/2765) ([gazarenkov](https://github.com/gazarenkov)) -- CHE-2456: Svn switch action [\#2758](https://github.com/eclipse/che/pull/2758) ([tolusha](https://github.com/tolusha)) -- Setup wildcard mime-type in content-type header if null body occurred [\#2746](https://github.com/eclipse/che/pull/2746) ([vzhukovskii](https://github.com/vzhukovskii)) -- CHE-2472 Do not try to connect to terminal if terminal agent not found in machine config [\#2744](https://github.com/eclipse/che/pull/2744) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- CHE-2524: Change parameter type in JpaUserDao [\#2743](https://github.com/eclipse/che/pull/2743) ([vinokurig](https://github.com/vinokurig)) -- \[WIP\]CHE-2438: Add handler for workspace remove event [\#2566](https://github.com/eclipse/che/pull/2566) ([akorneta](https://github.com/akorneta)) - CHE-2848: Removing "skip-validate-sources" from "fast" maven profile [\#2853](https://github.com/eclipse/che/pull/2853) ([ibuziuk](https://github.com/ibuziuk)) - CHE-2811 Launch all user commands by using bash if shell is not defined. [\#2838](https://github.com/eclipse/che/pull/2838) ([benoitf](https://github.com/benoitf)) - Fix git config test failure [\#2836](https://github.com/eclipse/che/pull/2836) ([amisevsk](https://github.com/amisevsk)) @@ -317,30 +423,6 @@ **Pull requests merged:** -- Synchronize project attributes before storing workspace [\#2726](https://github.com/eclipse/che/pull/2726) ([evoevodin](https://github.com/evoevodin)) -- Add recipe persisted event [\#2725](https://github.com/eclipse/che/pull/2725) ([akorneta](https://github.com/akorneta)) -- Update machine node when we have all info about machine [\#2723](https://github.com/eclipse/che/pull/2723) ([RomanNikitenko](https://github.com/RomanNikitenko)) -- Remove --no-bin-links as it conflicts with the latest node and npm version [\#2722](https://github.com/eclipse/che/pull/2722) ([eivantsov](https://github.com/eivantsov)) -- Fixes \#2437: Apply multi-edit formatting without messing up the document [\#2719](https://github.com/eclipse/che/pull/2719) ([kaloyan-raev](https://github.com/kaloyan-raev)) -- CHE-2702. Fix displaying of terminal and ws agent logs at starting/re… [\#2715](https://github.com/eclipse/che/pull/2715) ([RomanNikitenko](https://github.com/RomanNikitenko)) -- Backport contextual commands from 5.0 to 4.8.x in order to use it in Artik IDE [\#2714](https://github.com/eclipse/che/pull/2714) ([azatsarynnyy](https://github.com/azatsarynnyy)) -- CHE-2608: added vfs exlude filters, small vfs watcher fix, improved project tree changes detection algorithm [\#2713](https://github.com/eclipse/che/pull/2713) ([vparfonov](https://github.com/vparfonov)) -- Check if workspace exists before saving snapshot [\#2712](https://github.com/eclipse/che/pull/2712) ([evoevodin](https://github.com/evoevodin)) -- Use eager fetch type for workspace entities [\#2709](https://github.com/eclipse/che/pull/2709) ([evoevodin](https://github.com/evoevodin)) -- CHE-2477 Move Git and Subversion menus to the left [\#2708](https://github.com/eclipse/che/pull/2708) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- Add some files generated by m2e to .gitignore [\#2705](https://github.com/eclipse/che/pull/2705) ([kaloyan-raev](https://github.com/kaloyan-raev)) -- Exclude type-zend.svg from license header check [\#2703](https://github.com/eclipse/che/pull/2703) ([kaloyan-raev](https://github.com/kaloyan-raev)) -- CHE-642 When browser is resized, the content of the IDE terminal is missing partly [\#2697](https://github.com/eclipse/che/pull/2697) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- change deprecated package manager to a new one [\#2694](https://github.com/eclipse/che/pull/2694) ([olexii4](https://github.com/olexii4)) -- CHE-1756 Add ability to download workspace starting outputs from IDE loader [\#2686](https://github.com/eclipse/che/pull/2686) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- Change the configuration of the root folder for the che db [\#2685](https://github.com/eclipse/che/pull/2685) ([akorneta](https://github.com/akorneta)) -- CHE-2552: Language server module refactoring [\#2677](https://github.com/eclipse/che/pull/2677) ([tolusha](https://github.com/tolusha)) -- CODENVY-687: Сache svn credentials instead of storing them in credentials provider [\#2672](https://github.com/eclipse/che/pull/2672) ([vinokurig](https://github.com/vinokurig)) -- CHE-2214: Fix compilation error [\#2665](https://github.com/eclipse/che/pull/2665) ([tolusha](https://github.com/tolusha)) -- Fixes \#2592: Filter code completion proposals from language server [\#2658](https://github.com/eclipse/che/pull/2658) ([kaloyan-raev](https://github.com/kaloyan-raev)) -- Remove workspace name from model [\#2652](https://github.com/eclipse/che/pull/2652) ([evoevodin](https://github.com/evoevodin)) -- Fix JGitConnection test [\#2651](https://github.com/eclipse/che/pull/2651) ([vinokurig](https://github.com/vinokurig)) -- CHE-2214 NodeJs Debugger [\#2625](https://github.com/eclipse/che/pull/2625) ([tolusha](https://github.com/tolusha)) - Fix default PHP content [\#2721](https://github.com/eclipse/che/pull/2721) ([kaloyan-raev](https://github.com/kaloyan-raev)) - Fix integration tests when uid/gid already exists in docker image for maven typescript generator [\#2711](https://github.com/eclipse/che/pull/2711) ([benoitf](https://github.com/benoitf)) - Add default content for PHP project [\#2710](https://github.com/eclipse/che/pull/2710) ([vparfonov](https://github.com/vparfonov)) @@ -384,18 +466,6 @@ - Release and ship Che 5.0.0-M4 [\#2588](https://github.com/eclipse/che/issues/2588) - CLI Environment Variables [\#2560](https://github.com/eclipse/che/issues/2560) -**Pull requests merged:** - -- CODENVY-773: change machine expand/collapse icon on runtime page [\#2646](https://github.com/eclipse/che/pull/2646) ([akurinnoy](https://github.com/akurinnoy)) -- \#1801 implement 'Signature Help' LS feature [\#2645](https://github.com/eclipse/che/pull/2645) ([evidolob](https://github.com/evidolob)) -- Fix initialization of user related components [\#2644](https://github.com/eclipse/che/pull/2644) ([akorneta](https://github.com/akorneta)) -- CHE-2609: Fix JPA mapping for TEXT fields [\#2616](https://github.com/eclipse/che/pull/2616) ([akorneta](https://github.com/akorneta)) -- Set 5.0.0-M4-SNAPSHOT version for PHP plugin [\#2607](https://github.com/eclipse/che/pull/2607) ([vparfonov](https://github.com/vparfonov)) -- Publish appropriate event before user is persisted. [\#2606](https://github.com/eclipse/che/pull/2606) ([mshaposhnik](https://github.com/mshaposhnik)) -- CHE-2540 Console doesn't want to be maximized when IDE is opened in frame [\#2604](https://github.com/eclipse/che/pull/2604) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- Auto create files with hello world content when creating C, C++, and P… [\#2600](https://github.com/eclipse/che/pull/2600) ([eivantsov](https://github.com/eivantsov)) -- CHE-2470: Fix usage of machine servers in environemnt configuration [\#2599](https://github.com/eclipse/che/pull/2599) ([garagatyi](https://github.com/garagatyi)) - ## [5.0.0-M3](https://github.com/eclipse/che/tree/5.0.0-M3) (2016-09-26) [Full Changelog](https://github.com/eclipse/che/compare/5.0.0-M2...5.0.0-M3) @@ -472,19 +542,6 @@ **Pull requests merged:** -- \#2574 do not send file type to the client if LS cannot be run [\#2591](https://github.com/eclipse/che/pull/2591) ([evidolob](https://github.com/evidolob)) -- \#2509 create project.json file in C\# project [\#2587](https://github.com/eclipse/che/pull/2587) ([evidolob](https://github.com/evidolob)) -- Fix the parent pom version [\#2564](https://github.com/eclipse/che/pull/2564) ([benoitf](https://github.com/benoitf)) -- Restore PR \#1528 fix that has been lost with TypeScript changes [\#2554](https://github.com/eclipse/che/pull/2554) ([benoitf](https://github.com/benoitf)) -- Add dependencie [\#2553](https://github.com/eclipse/che/pull/2553) ([vinokurig](https://github.com/vinokurig)) -- CHE-2547: Remove duplicated dependency [\#2548](https://github.com/eclipse/che/pull/2548) ([tolusha](https://github.com/tolusha)) -- CHE-2424: Fix agents scripts to work with codenvy/alphine\_jdk image [\#2546](https://github.com/eclipse/che/pull/2546) ([tolusha](https://github.com/tolusha)) -- Remove duplicated dependency [\#2545](https://github.com/eclipse/che/pull/2545) ([vzhukovskii](https://github.com/vzhukovskii)) -- Fix environment addition. [\#2543](https://github.com/eclipse/che/pull/2543) ([garagatyi](https://github.com/garagatyi)) -- CHE-1761 Improve wizard to restart workspace [\#2542](https://github.com/eclipse/che/pull/2542) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) -- Use depends\_on instead of links [\#2526](https://github.com/eclipse/che/pull/2526) ([eivantsov](https://github.com/eivantsov)) -- CHE-2506: Use tag instead of snapshot of the io.typefox.lsapi project [\#2507](https://github.com/eclipse/che/pull/2507) ([tolusha](https://github.com/tolusha)) -- CHE-2366: Fix volumes\_from usage in compose environment [\#2487](https://github.com/eclipse/che/pull/2487) ([garagatyi](https://github.com/garagatyi)) - Publish StackPersistedEvent after stack is persisted [\#2582](https://github.com/eclipse/che/pull/2582) ([evoevodin](https://github.com/evoevodin)) - CHE-1774: Adding "Agents" section to the "Runtime" tab [\#2577](https://github.com/eclipse/che/pull/2577) ([ibuziuk](https://github.com/ibuziuk)) - Fixes space issue with profile variables [\#2575](https://github.com/eclipse/che/pull/2575) ([TylerJewell](https://github.com/TylerJewell)) @@ -515,7 +572,6 @@ **Issues with no labels:** -- iPad issue [\#2481](https://github.com/eclipse/che/issues/2481) - RAM widget disappers when select Java-MySQL stack [\#2480](https://github.com/eclipse/che/issues/2480) - CLI: Run Che specify CHE\_HOST\_IP [\#2476](https://github.com/eclipse/che/issues/2476) - consume eclipse che api from jquery/c\# [\#2475](https://github.com/eclipse/che/issues/2475) @@ -555,22 +611,11 @@ - GitHub plugin [\#738](https://github.com/eclipse/che/issues/738) - how to use content assist automatically [\#725](https://github.com/eclipse/che/issues/725) - Is it possible to use Sonarqube with Eclipse Che? [\#673](https://github.com/eclipse/che/issues/673) -- 404 /admin [\#490](https://github.com/eclipse/che/issues/490) - 5.0.0-M2 Milestone Overview [\#2640](https://github.com/eclipse/che/issues/2640) - Java Refactoring Rename feature broken after merging VFS Events and Split Editor features [\#2168](https://github.com/eclipse/che/issues/2168) **Pull requests merged:** -- CODENVY-779: fix workaround with dockerfiles secured by login filter [\#2503](https://github.com/eclipse/che/pull/2503) ([garagatyi](https://github.com/garagatyi)) -- CHE-2500: Use provider to prevent circular dependncy [\#2502](https://github.com/eclipse/che/pull/2502) ([tolusha](https://github.com/tolusha)) -- Add workspace validator to stack validator [\#2501](https://github.com/eclipse/che/pull/2501) ([akorneta](https://github.com/akorneta)) -- CHE-2484 Remove autostart LS agents [\#2485](https://github.com/eclipse/che/pull/2485) ([tolusha](https://github.com/tolusha)) -- CHE-2353: fix broken terminal [\#2483](https://github.com/eclipse/che/pull/2483) ([svor](https://github.com/svor)) -- Remove duplicated lines in pom.xml [\#2479](https://github.com/eclipse/che/pull/2479) ([benoitf](https://github.com/benoitf)) -- CHE-2286: disable menu items until the workspace is not running [\#2473](https://github.com/eclipse/che/pull/2473) ([olexii4](https://github.com/olexii4)) -- CHE-2468: ch.sh wrong permissions [\#2469](https://github.com/eclipse/che/pull/2469) ([tolusha](https://github.com/tolusha)) -- InitializeParams should include an empty ClientCapabilities [\#2466](https://github.com/eclipse/che/pull/2466) ([kaloyan-raev](https://github.com/kaloyan-raev)) -- Consolidate databases [\#2453](https://github.com/eclipse/che/pull/2453) ([akorneta](https://github.com/akorneta)) - Fix LanguageServerException message for CSharp LS [\#2532](https://github.com/eclipse/che/pull/2532) ([xcoulon](https://github.com/xcoulon)) - CHE-781: use 1Gb RAM for db machine and remove ssh agent from it [\#2505](https://github.com/eclipse/che/pull/2505) ([ashumilova](https://github.com/ashumilova)) @@ -600,6 +645,7 @@ - Workspaces that have been created before merge of the agents feature do not start [\#2385](https://github.com/eclipse/che/issues/2385) - Download project as Zip does not work [\#2377](https://github.com/eclipse/che/issues/2377) - There is no content of recipe into 'Operation Perspective' [\#2373](https://github.com/eclipse/che/issues/2373) +- Document model changes introduced in \#1818 [\#2363](https://github.com/eclipse/che/issues/2363) - Snapshoting of machines failed if snapshot made second time for given machine [\#2344](https://github.com/eclipse/che/issues/2344) - Cannot launch a workspace after creation [\#2331](https://github.com/eclipse/che/issues/2331) - che.sh root script is not sh compliant [\#2303](https://github.com/eclipse/che/issues/2303) @@ -774,8 +820,6 @@ - Eclipse Xtend [\#785](https://github.com/eclipse/che/issues/785) - workspace not restored from snapshot when che server is restarted [\#691](https://github.com/eclipse/che/issues/691) - Using authentication to access dashboard / IDE [\#690](https://github.com/eclipse/che/issues/690) -- Che image for armhf [\#531](https://github.com/eclipse/che/issues/531) -- using che with nginx-proxy [\#238](https://github.com/eclipse/che/issues/238) - Release and ship Che 4.7.0 [\#2265](https://github.com/eclipse/che/issues/2265) - Sometimes the IDE view may be broken [\#2260](https://github.com/eclipse/che/issues/2260) - che.sh trying to run 'docker.exe' on OSX [\#2248](https://github.com/eclipse/che/issues/2248) @@ -1071,12 +1115,6 @@ - Add more support for docker-machine drivers [\#655](https://github.com/eclipse/che/issues/655) - Is there an easy way to change the log level of the tomcat in the che docker container? [\#613](https://github.com/eclipse/che/issues/613) - how sould I do to build a che-samples/che-ide-extension plugin [\#610](https://github.com/eclipse/che/issues/610) -- MVN clean install fails on Mac [\#529](https://github.com/eclipse/che/issues/529) -- Rearrange Assembly Module [\#425](https://github.com/eclipse/che/issues/425) -- che project maven install error [\#366](https://github.com/eclipse/che/issues/366) -- Java open type action \(like Eclipse Ctrl Shift T\) [\#332](https://github.com/eclipse/che/issues/332) -- Some issues with keyboard bindings [\#277](https://github.com/eclipse/che/issues/277) -- Creating a Project for a different runtime within a Workspace fails to create a project that will compile/run [\#267](https://github.com/eclipse/che/issues/267) ## [4.4.2](https://github.com/eclipse/che/tree/4.4.2) (2016-07-06) [Full Changelog](https://github.com/eclipse/che/compare/4.4.1...4.4.2) @@ -1101,8 +1139,6 @@ - Create Workspace Dialog [\#1517](https://github.com/eclipse/che/issues/1517) - I cannot create a fully functional CHE workspace using Docker beta for mac [\#1482](https://github.com/eclipse/che/issues/1482) - Simplify Docker Execution [\#1230](https://github.com/eclipse/che/issues/1230) -- Add ability to disable editor file preview mode [\#278](https://github.com/eclipse/che/issues/278) -- How can I know if a file is in git index or not, from IDE? [\#173](https://github.com/eclipse/che/issues/173) ## [4.4.0](https://github.com/eclipse/che/tree/4.4.0) (2016-06-28) [Full Changelog](https://github.com/eclipse/che/compare/4.3.5...4.4.0) @@ -1214,7 +1250,6 @@ - .Generated Files [\#812](https://github.com/eclipse/che/issues/812) - .SymbolMap Files [\#811](https://github.com/eclipse/che/issues/811) - Authenticating my GitHub Account with Eclipse Che Won't Work [\#700](https://github.com/eclipse/che/issues/700) -- Error creating a project in eclipse che on desktop [\#261](https://github.com/eclipse/che/issues/261) ## [4.2.3](https://github.com/eclipse/che/tree/4.2.3) (2016-05-25) [Full Changelog](https://github.com/eclipse/che/compare/4.2.2...4.2.3) @@ -1242,7 +1277,6 @@ - Change the state of che editor programmatically [\#1209](https://github.com/eclipse/che/issues/1209) - Arm7 terminal websocket error. [\#1205](https://github.com/eclipse/che/issues/1205) - Beaglebone Che - Stuck on Finishing Editor Initialization [\#1100](https://github.com/eclipse/che/issues/1100) -- Does che supporting single step debugging now? [\#626](https://github.com/eclipse/che/issues/626) ## [4.2.2](https://github.com/eclipse/che/tree/4.2.2) (2016-05-12) [Full Changelog](https://github.com/eclipse/che/compare/4.2.1...4.2.2) @@ -1258,10 +1292,13 @@ - Not able to create new project using any stack [\#1138](https://github.com/eclipse/che/issues/1138) - cant access WSagent [\#1087](https://github.com/eclipse/che/issues/1087) - Impossible the update the copyright header [\#1059](https://github.com/eclipse/che/issues/1059) -- Creating workspace with che running inside a docker container fails with certificates https error [\#300](https://github.com/eclipse/che/issues/300) -- Exception during deployment when RVM is in the PATH [\#271](https://github.com/eclipse/che/issues/271) -- Execute commands on auxiliary machines [\#250](https://github.com/eclipse/che/issues/250) -- Linux: environment variables cause startup to fail [\#229](https://github.com/eclipse/che/issues/229) + +**Pull requests merged:** + +- CHE-362. Add different display modes for StatusNotification [\#1064](https://github.com/eclipse/che/pull/1064) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- Fixing 'StaticAccessedFromInstance' warnings [\#1062](https://github.com/eclipse/che/pull/1062) ([Wajihulhassan](https://github.com/Wajihulhassan)) +- Extracting superclass [\#1038](https://github.com/eclipse/che/pull/1038) ([alexVengrovsk](https://github.com/alexVengrovsk)) +- CHE-253: Refactor Che docker client [\#952](https://github.com/eclipse/che/pull/952) ([mmorhun](https://github.com/mmorhun)) ## [4.2.1](https://github.com/eclipse/che/tree/4.2.1) (2016-04-27) [Full Changelog](https://github.com/eclipse/che/compare/4.2.0...4.2.1) @@ -1273,6 +1310,19 @@ - How to add python stacks to the predefined-stack.json [\#1129](https://github.com/eclipse/che/issues/1129) - Watching for project files external changes [\#803](https://github.com/eclipse/che/issues/803) +**Pull requests merged:** + +- CHE-743: make scrollbar wider [\#1097](https://github.com/eclipse/che/pull/1097) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-945: \[dashboard\] improve workspaces removal message [\#1074](https://github.com/eclipse/che/pull/1074) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-946: \[dashboard\] improve workspace details page with error status [\#1073](https://github.com/eclipse/che/pull/1073) ([akurinnoy](https://github.com/akurinnoy)) +- CODENVY-349 Rename workspace agent packaged war name [\#1065](https://github.com/eclipse/che/pull/1065) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- The Workspace validator should allow the 'ssh' machine type [\#1055](https://github.com/eclipse/che/pull/1055) ([kaloyan-raev](https://github.com/kaloyan-raev)) +- CHE-996: \[dashboard\] Workspace menu changes [\#1053](https://github.com/eclipse/che/pull/1053) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-433: add smarter text on "create project" button [\#1048](https://github.com/eclipse/che/pull/1048) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-215: do not call the same resource multiple time on loading [\#1047](https://github.com/eclipse/che/pull/1047) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-467 Allow to configure Orion editor setting from IDE [\#1033](https://github.com/eclipse/che/pull/1033) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- fixed off by one error [\#1032](https://github.com/eclipse/che/pull/1032) ([svenefftinge](https://github.com/svenefftinge)) + ## [4.2.0](https://github.com/eclipse/che/tree/4.2.0) (2016-04-25) [Full Changelog](https://github.com/eclipse/che/compare/4.1.1...4.2.0) @@ -1297,7 +1347,37 @@ - Running 'docker' succeeded, but 'docker ps' failed. This usually means that docker cannot reach its daemon. [\#795](https://github.com/eclipse/che/issues/795) - Save Option [\#789](https://github.com/eclipse/che/issues/789) - Button icons disorder in `Git Show History` panel [\#771](https://github.com/eclipse/che/issues/771) -- Newly created workspace is stopped and gives 503 [\#497](https://github.com/eclipse/che/issues/497) + +**Pull requests merged:** + +- CHE-1048: Open terminal just after workspace starting [\#1102](https://github.com/eclipse/che/pull/1102) ([dimasnurenko](https://github.com/dimasnurenko)) +- Move proxy settings to top of che-properties file [\#1101](https://github.com/eclipse/che/pull/1101) ([mmorhun](https://github.com/mmorhun)) +- CODENVY-401: move a product info provider to the plugin-product-info [\#1098](https://github.com/eclipse/che/pull/1098) ([olexii4](https://github.com/olexii4)) +- Revert "CHE-243: Add paging support" [\#1096](https://github.com/eclipse/che/pull/1096) ([evoevodin](https://github.com/evoevodin)) +- CHE-999 SSH machines: handle exceptions on connections: properly subscribe to events [\#1095](https://github.com/eclipse/che/pull/1095) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-1004: Improve experience on Debugger configuration selection [\#1094](https://github.com/eclipse/che/pull/1094) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- Set corectly projects root [\#1093](https://github.com/eclipse/che/pull/1093) ([vparfonov](https://github.com/vparfonov)) +- Return back rewrite ruls [\#1092](https://github.com/eclipse/che/pull/1092) ([vparfonov](https://github.com/vparfonov)) +- Add missing license [\#1091](https://github.com/eclipse/che/pull/1091) ([mmorhun](https://github.com/mmorhun)) +- Return back rewrite rulls [\#1090](https://github.com/eclipse/che/pull/1090) ([vparfonov](https://github.com/vparfonov)) +- CODENVY-350: Set up workspaces to work behind the proxy [\#1089](https://github.com/eclipse/che/pull/1089) ([mmorhun](https://github.com/mmorhun)) +- Add new stacks and samples [\#1086](https://github.com/eclipse/che/pull/1086) ([ddementieva](https://github.com/ddementieva)) +- CHE-243: Add paging support [\#1085](https://github.com/eclipse/che/pull/1085) ([evoevodin](https://github.com/evoevodin)) +- CHE-990: Change MachineDto type to model type [\#1084](https://github.com/eclipse/che/pull/1084) ([dimasnurenko](https://github.com/dimasnurenko)) +- CODENVY-350: Set up workspaces to work behind the proxy [\#1083](https://github.com/eclipse/che/pull/1083) ([mmorhun](https://github.com/mmorhun)) +- CHE-995: discover ssh machines architecture automatically [\#1082](https://github.com/eclipse/che/pull/1082) ([garagatyi](https://github.com/garagatyi)) +- CHE-1024: make sure stacks are properly sorted [\#1080](https://github.com/eclipse/che/pull/1080) ([akurinnoy](https://github.com/akurinnoy)) +- Remove rewrite ruls. Use FQN in module bindings [\#1077](https://github.com/eclipse/che/pull/1077) ([vparfonov](https://github.com/vparfonov)) +- CHE-1023: temp fix for wsagent context path usage [\#1076](https://github.com/eclipse/che/pull/1076) ([ashumilova](https://github.com/ashumilova)) +- Remove unused classes [\#1075](https://github.com/eclipse/che/pull/1075) ([skabashnyuk](https://github.com/skabashnyuk)) +- Fixing wildcard import [\#1072](https://github.com/eclipse/che/pull/1072) ([Wajihulhassan](https://github.com/Wajihulhassan)) +- Fix websocket terminal launching in ssh machine [\#1071](https://github.com/eclipse/che/pull/1071) ([garagatyi](https://github.com/garagatyi)) +- Add Trailing slash [\#1070](https://github.com/eclipse/che/pull/1070) ([vparfonov](https://github.com/vparfonov)) +- CHE-999 SSH machines: handle exceptions on connections: properly subscribe to events [\#1068](https://github.com/eclipse/che/pull/1068) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CODENVY-282 check permissions before trying to start any workspace [\#1067](https://github.com/eclipse/che/pull/1067) ([mshaposhnik](https://github.com/mshaposhnik)) +- CODENVY-384: improve machine type labels [\#1066](https://github.com/eclipse/che/pull/1066) ([olexii4](https://github.com/olexii4)) +- Improving collection elements processing [\#1060](https://github.com/eclipse/che/pull/1060) ([alexVengrovsk](https://github.com/alexVengrovsk)) +- \[WIP\] Remove usage of MachineExtensionProxyServlet [\#1052](https://github.com/eclipse/che/pull/1052) ([vparfonov](https://github.com/vparfonov)) ## [4.1.1](https://github.com/eclipse/che/tree/4.1.1) (2016-04-15) [Full Changelog](https://github.com/eclipse/che/compare/4.1.0...4.1.1) @@ -1308,7 +1388,57 @@ - Make internal API accessible [\#1018](https://github.com/eclipse/che/issues/1018) - trying to create WS fails [\#1017](https://github.com/eclipse/che/issues/1017) - Can't copy from or paste to the che terminal [\#640](https://github.com/eclipse/che/issues/640) -- Workspace state Error removes Run button [\#504](https://github.com/eclipse/che/issues/504) + +**Pull requests merged:** + +- CHE-994 Update the list of machines on toolbar and console panel [\#1057](https://github.com/eclipse/che/pull/1057) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- Allow factory to contain projects with keepDir function [\#1056](https://github.com/eclipse/che/pull/1056) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- CHE-1010: properly align first childs in the tree root node [\#1054](https://github.com/eclipse/che/pull/1054) ([ashumilova](https://github.com/ashumilova)) +- CHE-995: mark architecture field as beta [\#1046](https://github.com/eclipse/che/pull/1046) ([garagatyi](https://github.com/garagatyi)) +- CHE-728 [\#1045](https://github.com/eclipse/che/pull/1045) ([mmorhun](https://github.com/mmorhun)) +- CODENVY-363: add error messages when user reach the limits [\#1044](https://github.com/eclipse/che/pull/1044) ([olexii4](https://github.com/olexii4)) +- CODENVY-256 Plugin Artik [\#1043](https://github.com/eclipse/che/pull/1043) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-748: use colors and fonts from CheColorsConfig and index.styl for… [\#1042](https://github.com/eclipse/che/pull/1042) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-961: \[dashboard\] Fix workspace item selection [\#1041](https://github.com/eclipse/che/pull/1041) ([akurinnoy](https://github.com/akurinnoy)) +- fix backward compatibility of machine recipe [\#1039](https://github.com/eclipse/che/pull/1039) ([garagatyi](https://github.com/garagatyi)) +- CODENY-367 fix openWelcomePage required parameter name [\#1037](https://github.com/eclipse/che/pull/1037) ([mshaposhnik](https://github.com/mshaposhnik)) +- CODENVY-363: add error messages when user reach the limits [\#1036](https://github.com/eclipse/che/pull/1036) ([olexii4](https://github.com/olexii4)) +- CHE-896 Fixing test errors due to status colors static block [\#1035](https://github.com/eclipse/che/pull/1035) ([stour](https://github.com/stour)) +- CHE-889: add ssh machine implementation [\#1034](https://github.com/eclipse/che/pull/1034) ([garagatyi](https://github.com/garagatyi)) +- CHE-930: fix terminal usage [\#1030](https://github.com/eclipse/che/pull/1030) ([garagatyi](https://github.com/garagatyi)) +- CHE-721: Fix docker authentication error log on create workspace [\#1029](https://github.com/eclipse/che/pull/1029) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- CODENVY-365: base project initializer should change only detected pro… [\#1028](https://github.com/eclipse/che/pull/1028) ([vparfonov](https://github.com/vparfonov)) +- CHE-896 cleaning custom colors in SVN plugin [\#1027](https://github.com/eclipse/che/pull/1027) ([stour](https://github.com/stour)) +- Optimizing "if" checks [\#1026](https://github.com/eclipse/che/pull/1026) ([alexVengrovsk](https://github.com/alexVengrovsk)) +- CHE-605: Use auto\_snapshot/auto\_restore attributes instead of params [\#1024](https://github.com/eclipse/che/pull/1024) ([evoevodin](https://github.com/evoevodin)) +- CHE-975: remove che-event-logger [\#1023](https://github.com/eclipse/che/pull/1023) ([ashumilova](https://github.com/ashumilova)) +- CHE-601: show Run button on ERROR state; hide 'Show more' link after … [\#1022](https://github.com/eclipse/che/pull/1022) ([akurinnoy](https://github.com/akurinnoy)) +- Add new stacks and sample apps [\#1021](https://github.com/eclipse/che/pull/1021) ([ddementieva](https://github.com/ddementieva)) +- fixup! CHE-942 temporarily disable move to path [\#1020](https://github.com/eclipse/che/pull/1020) ([stour](https://github.com/stour)) +- CODENVY-276: add white logo for Che [\#1019](https://github.com/eclipse/che/pull/1019) ([akurinnoy](https://github.com/akurinnoy)) +- GDB [\#1016](https://github.com/eclipse/che/pull/1016) ([tolusha](https://github.com/tolusha)) +- CHE-750 Remove snapshots on workspace removal [\#1015](https://github.com/eclipse/che/pull/1015) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- CHE-930: Adapt terminal binary name [\#1014](https://github.com/eclipse/che/pull/1014) ([evoevodin](https://github.com/evoevodin)) +- CODENVY-211: Provide configuration parameter to enable docker privileged mode [\#1013](https://github.com/eclipse/che/pull/1013) ([mmorhun](https://github.com/mmorhun)) +- CHE-964 empty credentials at wizard opening and avoid storing empty credentials [\#1012](https://github.com/eclipse/che/pull/1012) ([stour](https://github.com/stour)) +- CHE-941 temporarily disable copy to local path [\#1011](https://github.com/eclipse/che/pull/1011) ([stour](https://github.com/stour)) +- Fixing usage of DataOutputStream and ObjectOutputStream [\#1005](https://github.com/eclipse/che/pull/1005) ([Wajihulhassan](https://github.com/Wajihulhassan)) +- CHE-942 temporarily disable move to path [\#1003](https://github.com/eclipse/che/pull/1003) ([stour](https://github.com/stour)) +- CHE-472: Add show hint with existing methods params feature [\#1002](https://github.com/eclipse/che/pull/1002) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-961: fix workspace item selection [\#1000](https://github.com/eclipse/che/pull/1000) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-723 Add "Quick fix" entry to the Assistant menu [\#998](https://github.com/eclipse/che/pull/998) ([vinokurig](https://github.com/vinokurig)) +- CHE-732 SVN working with factories [\#997](https://github.com/eclipse/che/pull/997) ([stour](https://github.com/stour)) +- CHE-960: fix reset project creation flow state [\#995](https://github.com/eclipse/che/pull/995) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-685: reduce the height of Github projects list [\#991](https://github.com/eclipse/che/pull/991) ([akurinnoy](https://github.com/akurinnoy)) +- CODENVY-209: Change title of loading page of IDE. [\#990](https://github.com/eclipse/che/pull/990) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- CHE-925 Handle right project events to fetch conflicts and clean only resolved conflicts [\#988](https://github.com/eclipse/che/pull/988) ([stour](https://github.com/stour)) +- CODENVY-281: make it possible to manage debug configurations [\#987](https://github.com/eclipse/che/pull/987) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- CHE-940: show a spinner to indicate when a workspace is stopping [\#983](https://github.com/eclipse/che/pull/983) ([akurinnoy](https://github.com/akurinnoy)) +- IDEX-2721 Verify revision exists before to SVN Export [\#974](https://github.com/eclipse/che/pull/974) ([stour](https://github.com/stour)) +- CHE-98: Restyle check-boxes position in 'git commit' view [\#971](https://github.com/eclipse/che/pull/971) ([vinokurig](https://github.com/vinokurig)) +- CHE-66: Add spaces to 'git reset to commit' view radiobuttons description [\#970](https://github.com/eclipse/che/pull/970) ([vinokurig](https://github.com/vinokurig)) +- CHE-815. Remove project folder if import of project is failed [\#955](https://github.com/eclipse/che/pull/955) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-260 Rename some factory parameters [\#764](https://github.com/eclipse/che/pull/764) ([mkuznyetsov](https://github.com/mkuznyetsov)) ## [4.1.0](https://github.com/eclipse/che/tree/4.1.0) (2016-04-08) [Full Changelog](https://github.com/eclipse/che/compare/4.0.1...4.1.0) @@ -1404,49 +1534,58 @@ - Che Server | Ping Ws Agent IllegalArgumentException [\#736](https://github.com/eclipse/che/issues/736) - Running che and docker daemon in 2 separate VMs [\#664](https://github.com/eclipse/che/issues/664) - Create project error: Client has aborted connection [\#643](https://github.com/eclipse/che/issues/643) -- CHE-670 Make IDE startup components pluggable [\#598](https://github.com/eclipse/che/issues/598) -- CHE-667 Make ability to group by directory list of files when performing git diff [\#594](https://github.com/eclipse/che/issues/594) -- CHE-664 che.sh script with root access [\#591](https://github.com/eclipse/che/issues/591) -- CHE-662 Create docker compatibility tests to avoid manual testing on docker version migration or fixing bugs later [\#589](https://github.com/eclipse/che/issues/589) -- CHE-658 'Close all tabs' feature works wrong [\#584](https://github.com/eclipse/che/issues/584) - CHE-657 Cannot create a machine with specified names [\#583](https://github.com/eclipse/che/issues/583) -- CHE-648 Che loses connection with WS agent after the several hours of inactivity [\#569](https://github.com/eclipse/che/issues/569) -- CHE-645 It is possible to add debugger breakpoint into non-java file [\#566](https://github.com/eclipse/che/issues/566) -- CHE-637 When stopping WS in the IDE, take user back into the dashboard main page. [\#556](https://github.com/eclipse/che/issues/556) -- CHE-630 User management list - scroll bar too small on windows [\#549](https://github.com/eclipse/che/issues/549) -- CHE-631 drawing issue in user management list [\#548](https://github.com/eclipse/che/issues/548) -- CHE-616 Add ability validate name of files and folders which user creates on file system [\#524](https://github.com/eclipse/che/issues/524) -- CHE-609 All projects created from Dashboard have project-type Java attribute [\#517](https://github.com/eclipse/che/issues/517) -- CHE-607 It is impossible to stop or remove workspace in starting state [\#512](https://github.com/eclipse/che/issues/512) -- CHE-605 Default workspace behaviours [\#509](https://github.com/eclipse/che/issues/509) -- Workspace project storage created with insecure permissions [\#501](https://github.com/eclipse/che/issues/501) -- Workspace undefined successfully created [\#500](https://github.com/eclipse/che/issues/500) -- CHE-586 Provide horizontal navigation for 'Go to line' feature [\#487](https://github.com/eclipse/che/issues/487) -- CHE-582 Logs of machine start are unreachable for user if workspace start failed [\#479](https://github.com/eclipse/che/issues/479) -- CHE-578 Old value in refactor dialog [\#474](https://github.com/eclipse/che/issues/474) -- Cannot crate workspace [\#471](https://github.com/eclipse/che/issues/471) -- The swagger api is not displayed correct in the nightly build [\#459](https://github.com/eclipse/che/issues/459) -- Show error message when update deps timeout is reached [\#453](https://github.com/eclipse/che/issues/453) -- CHE-556 Support packages for Che [\#440](https://github.com/eclipse/che/issues/440) -- CHE-553 Add ability to view logs on start workspace [\#435](https://github.com/eclipse/che/issues/435) -- CHE-552 Adopt OpenShift Plugin to RC5 [\#432](https://github.com/eclipse/che/issues/432) -- CHE-534 The action 'Download as Zip' is dublicated [\#406](https://github.com/eclipse/che/issues/406) -- CHE-533 Don't repeat preparing of codenvy properties at the each step of installation [\#405](https://github.com/eclipse/che/issues/405) -- CHE-531 Apply git committer prefernces for console git [\#402](https://github.com/eclipse/che/issues/402) -- CHE-529 Wrong scroll position into the Console panel [\#399](https://github.com/eclipse/che/issues/399) -- CHE-526 Clean up spacing on command + preview in consoles panel [\#391](https://github.com/eclipse/che/issues/391) -- CHE-525 Unexpected error messages after refactoring for item selected in Project explore tree [\#390](https://github.com/eclipse/che/issues/390) -- CHE-524 The warning message is not displayed when invoke the 'Find usage' [\#389](https://github.com/eclipse/che/issues/389) -- CHE-517 When a container is shut down due to no or corrupted CMD a weird error is displayed [\#380](https://github.com/eclipse/che/issues/380) -- CHE-515 Chrome displays wrong icon for requests to workspace master and workspace agent [\#378](https://github.com/eclipse/che/issues/378) -- CHE-509 Refactoring for methods feature does not work properly in some cases [\#371](https://github.com/eclipse/che/issues/371) -- CHE-504 Project configuration should be updated during move project folder via project api [\#367](https://github.com/eclipse/che/issues/367) -- Exceptions creating a Java Project or Workspace [\#319](https://github.com/eclipse/che/issues/319) -- Can't restart workspace after stopping it [\#286](https://github.com/eclipse/che/issues/286) -- Consider improving UX for adding new projects to an existing workspace [\#275](https://github.com/eclipse/che/issues/275) -- In Windows 10, sometimes workspaces hang when being stopped, and then when you start them again, they malfunction [\#264](https://github.com/eclipse/che/issues/264) -- MVN Clean Install Fails on windows 8.1 [\#245](https://github.com/eclipse/che/issues/245) -- Custom image fails on workspace build, stuck in "Starting" [\#202](https://github.com/eclipse/che/issues/202) + +**Pull requests merged:** + +- CODENVY-351: add start workspace error message to workspace runtime o… [\#1001](https://github.com/eclipse/che/pull/1001) ([olexii4](https://github.com/olexii4)) +- CHE-959: Fix clone projects [\#999](https://github.com/eclipse/che/pull/999) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-667: Fix wrong view of git changed files tree [\#996](https://github.com/eclipse/che/pull/996) ([vinokurig](https://github.com/vinokurig)) +- CODENVY-351: fix workspace runtime output for dashboard [\#994](https://github.com/eclipse/che/pull/994) ([olexii4](https://github.com/olexii4)) +- Remove duplicate dependency [\#993](https://github.com/eclipse/che/pull/993) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- CHE-936 correct behavior when user token not found [\#992](https://github.com/eclipse/che/pull/992) ([mshaposhnik](https://github.com/mshaposhnik)) +- Fix import from Git location project type [\#989](https://github.com/eclipse/che/pull/989) ([ashumilova](https://github.com/ashumilova)) +- Fix path in Project DTO [\#986](https://github.com/eclipse/che/pull/986) ([vparfonov](https://github.com/vparfonov)) +- CHE-922: Improve sub-projects \(modules\) related UX on IDE [\#985](https://github.com/eclipse/che/pull/985) ([dimasnurenko](https://github.com/dimasnurenko)) +- CODENVY-257: Fix tests. Add gdb-tests profile to run tests [\#984](https://github.com/eclipse/che/pull/984) ([tolusha](https://github.com/tolusha)) +- CHE-933: Fix NPE when workspace is stopped by system [\#981](https://github.com/eclipse/che/pull/981) ([evoevodin](https://github.com/evoevodin)) +- CHE-793: replace button style to open in IDE [\#980](https://github.com/eclipse/che/pull/980) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-605: Extend Workspace API with new post/pre operations [\#978](https://github.com/eclipse/che/pull/978) ([evoevodin](https://github.com/evoevodin)) +- CHE-478: add new project type for simple java projects [\#977](https://github.com/eclipse/che/pull/977) ([svor](https://github.com/svor)) +- CHE-928: fix bug with project creation from project wizard with prese… [\#976](https://github.com/eclipse/che/pull/976) ([olexii4](https://github.com/olexii4)) +- Change default machine name to che [\#972](https://github.com/eclipse/che/pull/972) ([TylerJewell](https://github.com/TylerJewell)) +- CHE-897: Do not log error when sending a pull request to own project [\#969](https://github.com/eclipse/che/pull/969) ([vinokurig](https://github.com/vinokurig)) +- Consider project type from template [\#968](https://github.com/eclipse/che/pull/968) ([ashumilova](https://github.com/ashumilova)) +- CODENVY-257: Decouple DebuggerPresenter and Java Debugger [\#967](https://github.com/eclipse/che/pull/967) ([tolusha](https://github.com/tolusha)) +- Separate logic of showing dialog on workspace stop [\#964](https://github.com/eclipse/che/pull/964) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- CHE-903: Runtime links to workspace [\#963](https://github.com/eclipse/che/pull/963) ([mmorhun](https://github.com/mmorhun)) +- CHE-864 Adapt Subversion project importer UI to 4.x [\#961](https://github.com/eclipse/che/pull/961) ([stour](https://github.com/stour)) +- CHE-929 allow to reuse github source components in dashboard [\#960](https://github.com/eclipse/che/pull/960) ([benoitf](https://github.com/benoitf)) +- CHE-926 Hidding not implemented SVN actions from menu [\#957](https://github.com/eclipse/che/pull/957) ([stour](https://github.com/stour)) +- CHE-768: add ability to delete multiple workspaces from workspace list [\#956](https://github.com/eclipse/che/pull/956) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-718: Simplify workspace model & API [\#954](https://github.com/eclipse/che/pull/954) ([evoevodin](https://github.com/evoevodin)) +- CHE-848 Refactoring Subversion console to output in 'Consoles' tab [\#950](https://github.com/eclipse/che/pull/950) ([stour](https://github.com/stour)) +- CHE-261: Remove UserDao from machine in che. [\#948](https://github.com/eclipse/che/pull/948) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-781 Code restructuration. [\#947](https://github.com/eclipse/che/pull/947) ([skabashnyuk](https://github.com/skabashnyuk)) +- fixing che-core-api-dto-maven-plugin version [\#946](https://github.com/eclipse/che/pull/946) ([stour](https://github.com/stour)) +- CHE-912 returning no value instead of throwing an exception when project is not a SVN repository [\#944](https://github.com/eclipse/che/pull/944) ([stour](https://github.com/stour)) +- Remove unused docker version property [\#941](https://github.com/eclipse/che/pull/941) ([eivantsov](https://github.com/eivantsov)) +- CHE-553: add ability to view logs on start workspace [\#939](https://github.com/eclipse/che/pull/939) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-716 fix links generation [\#938](https://github.com/eclipse/che/pull/938) ([mshaposhnik](https://github.com/mshaposhnik)) +- fix style for select stack widget [\#931](https://github.com/eclipse/che/pull/931) ([olexii4](https://github.com/olexii4)) +- CHE-884: Add Node.js plugin [\#930](https://github.com/eclipse/che/pull/930) ([dimasnurenko](https://github.com/dimasnurenko)) +- Che 749 [\#928](https://github.com/eclipse/che/pull/928) ([vparfonov](https://github.com/vparfonov)) +- CHE-890: add stack icon link as icon image to stack widget [\#927](https://github.com/eclipse/che/pull/927) ([olexii4](https://github.com/olexii4)) +- CHE-904: update loading steps language [\#925](https://github.com/eclipse/che/pull/925) ([ashumilova](https://github.com/ashumilova)) +- CHE-783: add Python plugin [\#882](https://github.com/eclipse/che/pull/882) ([svor](https://github.com/svor)) +- CHE-156 Need to add a scroll bar to editor opened file list \(popup\) [\#861](https://github.com/eclipse/che/pull/861) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-746. Split github plugin to several modules client/server/shared [\#831](https://github.com/eclipse/che/pull/831) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-106 Padding in the minimap is not enough [\#818](https://github.com/eclipse/che/pull/818) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- Che 716 getting workspaces via composite key [\#813](https://github.com/eclipse/che/pull/813) ([mshaposhnik](https://github.com/mshaposhnik)) +- CHE-492: JavaDebugger refactoring [\#807](https://github.com/eclipse/che/pull/807) ([tolusha](https://github.com/tolusha)) +- CHE-667: Group by directory list of files when performing git diff [\#766](https://github.com/eclipse/che/pull/766) ([vinokurig](https://github.com/vinokurig)) +- CHE-745 Make plugin-svn build & run in Che [\#758](https://github.com/eclipse/che/pull/758) ([stour](https://github.com/stour)) +- Che 756: make the loading view fit the height of the screen to avoid scrolling [\#739](https://github.com/eclipse/che/pull/739) ([akurinnoy](https://github.com/akurinnoy)) ## [4.0.1](https://github.com/eclipse/che/tree/4.0.1) (2016-03-29) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0...4.0.1) @@ -1456,6 +1595,10 @@ - Cannot launch a workspace after stopping tomcat with Che [\#913](https://github.com/eclipse/che/issues/913) - Provide horizontal navigation for 'Go to line' feature [\#910](https://github.com/eclipse/che/issues/910) +**Pull requests merged:** + +- CHE-901: use ConcurrentHashMap for projects in ProjectRegistry [\#914](https://github.com/eclipse/che/pull/914) ([vparfonov](https://github.com/vparfonov)) + ## [4.0.0](https://github.com/eclipse/che/tree/4.0.0) (2016-03-29) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC14...4.0.0) @@ -1487,8 +1630,32 @@ - Che Workspace Port Configuration [\#808](https://github.com/eclipse/che/issues/808) - Running 'docker' succeeded, but 'docker ps' failed. This usually means that docker cannot reach its daemon. [\#794](https://github.com/eclipse/che/issues/794) - how can I get the same workspace which I was working on when I restart Che server. [\#779](https://github.com/eclipse/che/issues/779) -- Missing java quick fix [\#299](https://github.com/eclipse/che/issues/299) -- dashboard in docker [\#96](https://github.com/eclipse/che/issues/96) + +**Pull requests merged:** + +- Fixing wrong merge: [\#892](https://github.com/eclipse/che/pull/892) ([vparfonov](https://github.com/vparfonov)) +- Revert "CHE-553: add ability to view logs on start workspace" [\#888](https://github.com/eclipse/che/pull/888) ([ashumilova](https://github.com/ashumilova)) +- Hide terminal URL [\#876](https://github.com/eclipse/che/pull/876) ([vparfonov](https://github.com/vparfonov)) +- CHE-894: fix creating custom stack from Dashboard [\#875](https://github.com/eclipse/che/pull/875) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-891: Initialize projects from unconfigured folders on starting WS… [\#869](https://github.com/eclipse/che/pull/869) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- CHE-883: cleanup websocket channels when ide is opened [\#851](https://github.com/eclipse/che/pull/851) ([ashumilova](https://github.com/ashumilova)) +- CHE-553: add ability to view logs on start workspace [\#829](https://github.com/eclipse/che/pull/829) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-867: Do not overwrite whole workspace's configuration when saving… [\#819](https://github.com/eclipse/che/pull/819) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- Remove GA label [\#809](https://github.com/eclipse/che/pull/809) ([riuvshin](https://github.com/riuvshin)) +- CHE-157: show attached documentation in the method hierarchy [\#805](https://github.com/eclipse/che/pull/805) ([svor](https://github.com/svor)) +- Remove added by mistake setenv.sh [\#804](https://github.com/eclipse/che/pull/804) ([vparfonov](https://github.com/vparfonov)) +- CHE-525: Fix unexpected error message after refactoring [\#801](https://github.com/eclipse/che/pull/801) ([dimasnurenko](https://github.com/dimasnurenko)) +- fix logs output on workspace start [\#800](https://github.com/eclipse/che/pull/800) ([akurinnoy](https://github.com/akurinnoy)) +- Revert "CHE-708: Add CORS Filter" [\#799](https://github.com/eclipse/che/pull/799) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-872: Fix keep directory when importing a project [\#798](https://github.com/eclipse/che/pull/798) ([vinokurig](https://github.com/vinokurig)) +- Initialize projects from unconfigured folders while getting projects [\#793](https://github.com/eclipse/che/pull/793) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- CHE-15 'Close' button on find/replace panel should be square [\#791](https://github.com/eclipse/che/pull/791) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- Schedule annotation documentation [\#788](https://github.com/eclipse/che/pull/788) ([skabashnyuk](https://github.com/skabashnyuk)) +- Exclude tests [\#787](https://github.com/eclipse/che/pull/787) ([vparfonov](https://github.com/vparfonov)) +- Remove 'Create Maven module' feature [\#784](https://github.com/eclipse/che/pull/784) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- CHE-766. Correct handling of pressing 'enter' on some dialogs [\#782](https://github.com/eclipse/che/pull/782) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-434: improve experience to create a new project in an existing wo… [\#772](https://github.com/eclipse/che/pull/772) ([olexii4](https://github.com/olexii4)) +- CHE-708: Add CORS Filter [\#767](https://github.com/eclipse/che/pull/767) ([dimasnurenko](https://github.com/dimasnurenko)) ## [4.0.0-RC14](https://github.com/eclipse/che/tree/4.0.0-RC14) (2016-03-23) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC13...4.0.0-RC14) @@ -1516,27 +1683,84 @@ - Error while use super dev mode debug [\#675](https://github.com/eclipse/che/issues/675) - Trying to connect my github account produces a 404 page \(from Github\) [\#670](https://github.com/eclipse/che/issues/670) - Error "unable to find user user" [\#669](https://github.com/eclipse/che/issues/669) -- CHE-676 Dialogs lose focus when we use tab button [\#606](https://github.com/eclipse/che/issues/606) -- CHE-673 Unexpected behavior "Commands" dialog [\#602](https://github.com/eclipse/che/issues/602) -- CHE-672 Adapt Cloud assembly in according to the reworked Project API [\#600](https://github.com/eclipse/che/issues/600) -- CHE-665 Refine icons in git menu [\#593](https://github.com/eclipse/che/issues/593) -- CHE-666 Refine icons in project configuration wizard [\#592](https://github.com/eclipse/che/issues/592) - CHE-656 Switching between editor tabs by hotKeys works incorrect after rename opened file [\#582](https://github.com/eclipse/che/issues/582) -- CHE-655 Dashboard view changes [\#581](https://github.com/eclipse/che/issues/581) -- CHE-647 Fix integration tests of IM CLI to use Codenvy 4 of hosted version instead of nightly.codenvy-stg.com [\#567](https://github.com/eclipse/che/issues/567) -- CHE-642 Incorrect behavior dialogs when user uses "Enter" button to confirm his choice [\#562](https://github.com/eclipse/che/issues/562) -- CHE-639 Investigate how to add new file formats in editor [\#558](https://github.com/eclipse/che/issues/558) -- Does CHE Keep the editing histories of a file? [\#552](https://github.com/eclipse/che/issues/552) -- CHE-629 Remove Help menu from left sidebar [\#547](https://github.com/eclipse/che/issues/547) -- Very long startup due to entropy gathering [\#498](https://github.com/eclipse/che/issues/498) -- CHE-560 Swagger page is broken if no trailing slash in url [\#448](https://github.com/eclipse/che/issues/448) -- CHE-557 Maven command doesn't work [\#441](https://github.com/eclipse/che/issues/441) -- CHE-544 unexpected duplication of 'Warning operation' widget after refactoring of annotation [\#421](https://github.com/eclipse/che/issues/421) -- CHE-530 Add a tooltip for the SSH button [\#401](https://github.com/eclipse/che/issues/401) -- CHE-528 Icons and items in git merge window are not fit in line [\#394](https://github.com/eclipse/che/issues/394) -- CHE-518 InvInvestigate and resolve problems in the selenium tests after first launching on CI [\#383](https://github.com/eclipse/che/issues/383) -- CHE-516 Java error "Target Java VM is not suspended" in time of debugging [\#379](https://github.com/eclipse/che/issues/379) -- CHE-503 Add ability to edit and save file content in compare widget [\#365](https://github.com/eclipse/che/issues/365) + +**Pull requests merged:** + +- CHE-875 rename master -\> wsmaster, agent - wsagent. [\#786](https://github.com/eclipse/che/pull/786) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-796: browser die when creating a project with a new ws [\#783](https://github.com/eclipse/che/pull/783) ([akurinnoy](https://github.com/akurinnoy)) +- Add timeout on verify. Shoud fix test o Jenkins CI [\#781](https://github.com/eclipse/che/pull/781) ([vparfonov](https://github.com/vparfonov)) +- Fix failed build [\#780](https://github.com/eclipse/che/pull/780) ([vparfonov](https://github.com/vparfonov)) +- Fix imports [\#777](https://github.com/eclipse/che/pull/777) ([vparfonov](https://github.com/vparfonov)) +- Move test according to https://github.com/eclipse/che/pull/775 [\#776](https://github.com/eclipse/che/pull/776) ([vparfonov](https://github.com/vparfonov)) +- CHE-774:fix perspective id & move Action to the better code base [\#775](https://github.com/eclipse/che/pull/775) ([vparfonov](https://github.com/vparfonov)) +- CHE-781 remove analytics [\#774](https://github.com/eclipse/che/pull/774) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-866: wrap fileWatcher.startup\(\) with try..catch. [\#773](https://github.com/eclipse/che/pull/773) ([vparfonov](https://github.com/vparfonov)) +- Delete project from workspace's configuration in case project doesn't… [\#769](https://github.com/eclipse/che/pull/769) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- CHE-339 Review and rework the popups that do not extend Window [\#768](https://github.com/eclipse/che/pull/768) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-657: fix generation on docker container name [\#763](https://github.com/eclipse/che/pull/763) ([garagatyi](https://github.com/garagatyi)) +- CHE-755: show a spinner to indicate when a workspace is starting [\#762](https://github.com/eclipse/che/pull/762) ([akurinnoy](https://github.com/akurinnoy)) +- Support exposed port with tcp suffix [\#759](https://github.com/eclipse/che/pull/759) ([vzhukovskii](https://github.com/vzhukovskii)) +- CHE-233:Rework Project API with new VFS [\#757](https://github.com/eclipse/che/pull/757) ([vparfonov](https://github.com/vparfonov)) +- CHE-764: improve layout for workspace list [\#756](https://github.com/eclipse/che/pull/756) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-730. Fix problems related to refusing WebSocket connection when machine is restarted. [\#755](https://github.com/eclipse/che/pull/755) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- Add chown to projects dir to make sure a current container user has write access to it [\#754](https://github.com/eclipse/che/pull/754) ([eivantsov](https://github.com/eivantsov)) +- CODENVY-252 fix wrong groupid [\#753](https://github.com/eclipse/che/pull/753) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-781 Decouple parts of platform-api for master and agent [\#752](https://github.com/eclipse/che/pull/752) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-715 change some workspace service paths [\#748](https://github.com/eclipse/che/pull/748) ([mshaposhnik](https://github.com/mshaposhnik)) +- Fix increasing war size [\#746](https://github.com/eclipse/che/pull/746) ([ashumilova](https://github.com/ashumilova)) +- CHE-781 Che structural refactoring [\#743](https://github.com/eclipse/che/pull/743) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-754: typo changes in project details when workspace stopped [\#742](https://github.com/eclipse/che/pull/742) ([akurinnoy](https://github.com/akurinnoy)) +- improve secret key error notification [\#741](https://github.com/eclipse/che/pull/741) ([olexii4](https://github.com/olexii4)) +- Fix year in header of DTO genereted classes and in some project classes [\#740](https://github.com/eclipse/che/pull/740) ([mshaposhnik](https://github.com/mshaposhnik)) +- improve footer style [\#735](https://github.com/eclipse/che/pull/735) ([olexii4](https://github.com/olexii4)) +- Fix url encoding in DefaultHttpJsonRequest [\#734](https://github.com/eclipse/che/pull/734) ([akorneta](https://github.com/akorneta)) +- CODENVY-262: Delete containers which left after build with fail [\#733](https://github.com/eclipse/che/pull/733) ([mmorhun](https://github.com/mmorhun)) +- CHE-741: change model of machine server conf and runtime server [\#729](https://github.com/eclipse/che/pull/729) ([garagatyi](https://github.com/garagatyi)) +- eclipse che [\#728](https://github.com/eclipse/che/pull/728) ([agrimgrover](https://github.com/agrimgrover)) +- Replace codenvy to che in classes' names [\#724](https://github.com/eclipse/che/pull/724) ([sleshchenko](https://github.com/sleshchenko)) +- Add an ability to get pull requests by repo, owner and head [\#723](https://github.com/eclipse/che/pull/723) ([evoevodin](https://github.com/evoevodin)) +- Fix call setInterval\(\) avoid RangeError: Maximum call stack size exce… [\#722](https://github.com/eclipse/che/pull/722) ([vparfonov](https://github.com/vparfonov)) +- CHE-731. Close all opened files when workspace is stopped [\#721](https://github.com/eclipse/che/pull/721) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- Fix NPE at cleaning selections in processes panel [\#720](https://github.com/eclipse/che/pull/720) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-437: create loader while opening a stopped workspace [\#717](https://github.com/eclipse/che/pull/717) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-119. Set focus on OK button of message dialog when dialog is displaying [\#716](https://github.com/eclipse/che/pull/716) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- Che 312: Remove existing docker snapshot when creating new one [\#714](https://github.com/eclipse/che/pull/714) ([mmorhun](https://github.com/mmorhun)) +- CHE-691: Fix launching factory into inactive browser tab. [\#713](https://github.com/eclipse/che/pull/713) ([dimasnurenko](https://github.com/dimasnurenko)) +- Add :Z suffix when mounting workspace project sources [\#712](https://github.com/eclipse/che/pull/712) ([eivantsov](https://github.com/eivantsov)) +- Fix DocuementChange event for Orion editor [\#711](https://github.com/eclipse/che/pull/711) ([sunix](https://github.com/sunix)) +- CODENVY-232: add element injector service by parent id [\#710](https://github.com/eclipse/che/pull/710) ([olexii4](https://github.com/olexii4)) +- CHE-351. Move Preferences from Help menu to Profile menu [\#709](https://github.com/eclipse/che/pull/709) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-740 Connect via SSH button in Consoles has no tooltip [\#708](https://github.com/eclipse/che/pull/708) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- Fix styles for buttons on some dialogs [\#707](https://github.com/eclipse/che/pull/707) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-656: Refactor getOpenEditors method from Map to List [\#706](https://github.com/eclipse/che/pull/706) ([vinokurig](https://github.com/vinokurig)) +- CHE-139: add 'Organize Imports' functionality [\#705](https://github.com/eclipse/che/pull/705) ([svor](https://github.com/svor)) +- CHE-665: crop and optimize git menu icons [\#704](https://github.com/eclipse/che/pull/704) ([ashumilova](https://github.com/ashumilova)) +- CHE-678: Rework loading view to component [\#703](https://github.com/eclipse/che/pull/703) ([akurinnoy](https://github.com/akurinnoy)) +- add VMware Fusion support [\#702](https://github.com/eclipse/che/pull/702) ([zaps](https://github.com/zaps)) +- CODENVY-43. Create Profile menu for Che [\#692](https://github.com/eclipse/che/pull/692) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-639: add typescript, ecmascript 6 and jsx file formats [\#689](https://github.com/eclipse/che/pull/689) ([ashumilova](https://github.com/ashumilova)) +- Fix using estimation attributes [\#688](https://github.com/eclipse/che/pull/688) ([ashumilova](https://github.com/ashumilova)) +- CHE-457: add servers conf and env vars to model of machine config. [\#687](https://github.com/eclipse/che/pull/687) ([garagatyi](https://github.com/garagatyi)) +- CODENVY-26: Fix stream closing before it is direct use [\#685](https://github.com/eclipse/che/pull/685) ([akorneta](https://github.com/akorneta)) +- Added fix for a problem that made OSX-based builds fail [\#682](https://github.com/eclipse/che/pull/682) ([MitchK](https://github.com/MitchK)) +- CHE-396 Rename perspective and Workspace agent [\#679](https://github.com/eclipse/che/pull/679) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CODENVY-191: Add update factory client impl [\#677](https://github.com/eclipse/che/pull/677) ([akorneta](https://github.com/akorneta)) +- Remove unused properties. Rename project\_template.location.dir [\#676](https://github.com/eclipse/che/pull/676) ([eivantsov](https://github.com/eivantsov)) +- CHE-694: change border radius property [\#674](https://github.com/eclipse/che/pull/674) ([ashumilova](https://github.com/ashumilova)) +- Changeslog for 4.0.0RC12-RC13 [\#672](https://github.com/eclipse/che/pull/672) ([skabashnyuk](https://github.com/skabashnyuk)) +- CODENVY-193: Add jenkins build badge [\#668](https://github.com/eclipse/che/pull/668) ([riuvshin](https://github.com/riuvshin)) +- Upgrade Apache Commons Collections to v3.2.2 [\#667](https://github.com/eclipse/che/pull/667) ([ProgramMax](https://github.com/ProgramMax)) +- Avoid NPE if event don't has EventOrigin annotation [\#666](https://github.com/eclipse/che/pull/666) ([vparfonov](https://github.com/vparfonov)) +- Codenvy 167: improve the che-footer widget [\#665](https://github.com/eclipse/che/pull/665) ([olexii4](https://github.com/olexii4)) +- CHE-673. Correct handling buttons of Commands dialog when Enter is clicked [\#663](https://github.com/eclipse/che/pull/663) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-686: add oauth providers service and check GitHub one to notify user [\#661](https://github.com/eclipse/che/pull/661) ([ashumilova](https://github.com/ashumilova)) +- CHE-176. Set 'accept' button in the focus for Choice dialog and Confirm dialog [\#659](https://github.com/eclipse/che/pull/659) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-682: Enable debug buttons when debugger open file without source [\#657](https://github.com/eclipse/che/pull/657) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- CHE-642. Correct handling buttons on dialogs when Enter is pushed [\#630](https://github.com/eclipse/che/pull/630) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-676. Keep focus on dialog when user uses tab button [\#611](https://github.com/eclipse/che/pull/611) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-52. Improve styles for focused button on dialogs [\#563](https://github.com/eclipse/che/pull/563) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-379: Merge Setting to the Preferences widget [\#393](https://github.com/eclipse/che/pull/393) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) ## [4.0.0-RC13](https://github.com/eclipse/che/tree/4.0.0-RC13) (2016-03-09) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC12...4.0.0-RC13) @@ -1547,8 +1771,20 @@ - Question about templates folder [\#649](https://github.com/eclipse/che/issues/649) - Che can't authorise to github [\#639](https://github.com/eclipse/che/issues/639) - Can't create project [\#631](https://github.com/eclipse/che/issues/631) -- CHE-669 Make terminal easier to find [\#597](https://github.com/eclipse/che/issues/597) -- CHE-640 Password strength meter is broken on account view [\#559](https://github.com/eclipse/che/issues/559) + +**Pull requests merged:** + +- Remove unused components [\#662](https://github.com/eclipse/che/pull/662) ([ashumilova](https://github.com/ashumilova)) +- CHE-698: improve the boxes styles on dashboard page [\#660](https://github.com/eclipse/che/pull/660) ([olexii4](https://github.com/olexii4)) +- CHE-528: Resize git Merge and History icons to fit them in line [\#658](https://github.com/eclipse/che/pull/658) ([vinokurig](https://github.com/vinokurig)) +- CHE-655: add recent workspaces box on the dashboard [\#653](https://github.com/eclipse/che/pull/653) ([olexii4](https://github.com/olexii4)) +- CHE-666 Refine icons in project configuration wizard [\#652](https://github.com/eclipse/che/pull/652) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- Move workspaces menu above projects one [\#651](https://github.com/eclipse/che/pull/651) ([ashumilova](https://github.com/ashumilova)) +- CHE-503: Add ability to save edited changes from compare widget [\#650](https://github.com/eclipse/che/pull/650) ([vinokurig](https://github.com/vinokurig)) +- CHE-701: Extend debugger views from Window [\#647](https://github.com/eclipse/che/pull/647) ([vinokurig](https://github.com/vinokurig)) +- Che 684 improve import from SSH error notification [\#646](https://github.com/eclipse/che/pull/646) ([olexii4](https://github.com/olexii4)) +- CHE-367: Return websocket URL of extension server when a workspace is launched [\#635](https://github.com/eclipse/che/pull/635) ([mmorhun](https://github.com/mmorhun)) +- CHE-516: Fix unstable debbuger behavior [\#580](https://github.com/eclipse/che/pull/580) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) ## [4.0.0-RC12](https://github.com/eclipse/che/tree/4.0.0-RC12) (2016-03-06) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC11...4.0.0-RC12) @@ -1558,225 +1794,394 @@ - Eclispse CHE doesn't load in browser\(Chrome/Firefox\) [\#641](https://github.com/eclipse/che/issues/641) - How to define another environment and switch between environments? [\#634](https://github.com/eclipse/che/issues/634) - What's the difference between the two concepts "recipe" and "stack" [\#633](https://github.com/eclipse/che/issues/633) -- CHE-653 Change value fails with NullPointerException [\#576](https://github.com/eclipse/che/issues/576) -- CHE-651 Notification loose their shadow [\#573](https://github.com/eclipse/che/issues/573) + +**Pull requests merged:** + +- CHE-669 Make terminal easier to find [\#645](https://github.com/eclipse/che/pull/645) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-383: Move FqnProvider to che-core-ide-api [\#644](https://github.com/eclipse/che/pull/644) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-383: Add ability to show and copy fqn and path of files [\#637](https://github.com/eclipse/che/pull/637) ([dimasnurenko](https://github.com/dimasnurenko)) +- Added changeslog for 4.0.0-RC9 - 4.0.0-RC11 [\#636](https://github.com/eclipse/che/pull/636) ([skabashnyuk](https://github.com/skabashnyuk)) +- CODENVY-174 pre-select correct branch when start point is set [\#629](https://github.com/eclipse/che/pull/629) ([mshaposhnik](https://github.com/mshaposhnik)) ## [4.0.0-RC11](https://github.com/eclipse/che/tree/4.0.0-RC11) (2016-03-03) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC10...4.0.0-RC11) **Issues with no labels:** -- What does the asterisk on the left of the editor panel mean? [\#625](https://github.com/eclipse/che/issues/625) -- Nightly docker image issue: can't open the created project [\#624](https://github.com/eclipse/che/issues/624) - Errors in nightly che [\#609](https://github.com/eclipse/che/issues/609) - CHE-614 Max size of message queue exceeded during starting workspace in Che [\#522](https://github.com/eclipse/che/issues/522) -- Can't create a new workspace [\#431](https://github.com/eclipse/che/issues/431) -- how to configure che to pull private images from docker hub [\#237](https://github.com/eclipse/che/issues/237) -- Che cannot create projects with SELinux enabled [\#232](https://github.com/eclipse/che/issues/232) -- 连接过多 [\#140](https://github.com/eclipse/che/issues/140) -- How to pass config when starting a machine? [\#130](https://github.com/eclipse/che/issues/130) + +**Pull requests merged:** + +- CHE-214 \[dashboard\] use real project path for commands [\#632](https://github.com/eclipse/che/pull/632) ([benoitf](https://github.com/benoitf)) +- CHE-651 \[dashboard\] Add missing shadow on popup [\#628](https://github.com/eclipse/che/pull/628) ([benoitf](https://github.com/benoitf)) +- CHE-700 Add subversion to blank stack [\#627](https://github.com/eclipse/che/pull/627) ([benoitf](https://github.com/benoitf)) +- Add Z suffix to fix mounting issues on Fedora with SELinux enabled [\#623](https://github.com/eclipse/che/pull/623) ([eivantsov](https://github.com/eivantsov)) +- CHE-653: Change value fails with NullPointerException [\#622](https://github.com/eclipse/che/pull/622) ([mmorhun](https://github.com/mmorhun)) +- CHE-695 : \[dashboard\] use fixed versions [\#621](https://github.com/eclipse/che/pull/621) ([benoitf](https://github.com/benoitf)) +- Add promise-based methods for GitHub client service [\#618](https://github.com/eclipse/che/pull/618) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- Che 212 disable field auto completion after its adjustments [\#617](https://github.com/eclipse/che/pull/617) ([olexii4](https://github.com/olexii4)) +- CHE-201: remove breakpoints in case of absence of linked file [\#607](https://github.com/eclipse/che/pull/607) ([dmytro-ndp](https://github.com/dmytro-ndp)) +- Add TomEE 1.7.3 stack and sample application [\#570](https://github.com/eclipse/che/pull/570) ([jgallimore](https://github.com/jgallimore)) ## [4.0.0-RC10](https://github.com/eclipse/che/tree/4.0.0-RC10) (2016-03-02) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC9...4.0.0-RC10) **Issues with no labels:** -- How to use che.sh to run a custom docker image? [\#608](https://github.com/eclipse/che/issues/608) - CHE-671 Investigate the reason of failing parser [\#599](https://github.com/eclipse/che/issues/599) - CHE-661 unzip ws-agent in quiet mode [\#588](https://github.com/eclipse/che/issues/588) -- CHE-660 Connection timeout when updating a sizable project [\#586](https://github.com/eclipse/che/issues/586) -- CHE-654 Unclosed zip archive when building che [\#577](https://github.com/eclipse/che/issues/577) -- CHE-652 Display Codenvy logo while display in the striped loader [\#574](https://github.com/eclipse/che/issues/574) -- CHE-650 Cannot export a workspace [\#571](https://github.com/eclipse/che/issues/571) -- CHE-641 Add default blank stack [\#561](https://github.com/eclipse/che/issues/561) -- CHE-624 readme file should provide more information to get started with Che [\#537](https://github.com/eclipse/che/issues/537) - CHE-622 Commands are added to custom stacks [\#533](https://github.com/eclipse/che/issues/533) -- CHE-611 Cannot run a workspace from Dashboard [\#519](https://github.com/eclipse/che/issues/519) -- CHE-610 Restarting a workspace with a project results in an attempt to recreate a project [\#516](https://github.com/eclipse/che/issues/516) -- CHE-603 \[dashboard\] allow to add new routes on route history [\#507](https://github.com/eclipse/che/issues/507) -- CHE-602 \[dashboard\] Allow to send to IDE some loading parameters [\#506](https://github.com/eclipse/che/issues/506) -- CHE-596 Make non-blocking entropy the default for Che startup [\#499](https://github.com/eclipse/che/issues/499) -- CHE-591 Clean up plugin installer [\#494](https://github.com/eclipse/che/issues/494) -- CHE-589 Broken project tree [\#492](https://github.com/eclipse/che/issues/492) -- CHE-581 New workspace from 'Import an existing workspace configuration' is created wrong [\#478](https://github.com/eclipse/che/issues/478) -- CHE-574 After using a factory the just cloned project is not configured [\#464](https://github.com/eclipse/che/issues/464) -- CHE-573 Factory configuration feature in the IDE works incorrect [\#463](https://github.com/eclipse/che/issues/463) -- CHE-571 Cannot create a factory after cloning the Java- Web-Spring tempate [\#461](https://github.com/eclipse/che/issues/461) -- CHE-566 Prototype transitions on the right side of the loader [\#458](https://github.com/eclipse/che/issues/458) -- CHE-567 Display the outputs with syntax coloration on the right side of the loader [\#457](https://github.com/eclipse/che/issues/457) -- CHE-565 Improvements on the crane design [\#455](https://github.com/eclipse/che/issues/455) -- CHE-559 After creation a new machine in existed workspace output is empty [\#444](https://github.com/eclipse/che/issues/444) -- CHE-555 Preview URL for application is wrong [\#436](https://github.com/eclipse/che/issues/436) -- CHE-550 Adapt projects in dashboard to 4.0 changes [\#430](https://github.com/eclipse/che/issues/430) -- CHE-549 \[dashboard\] increase timeout delays in unit tests [\#429](https://github.com/eclipse/che/issues/429) -- CHE-547 \[dashboard\] Adapt project-type to 4.0 project-type [\#423](https://github.com/eclipse/che/issues/423) -- CHE-546 Workspace Agent should consider to return transitional state while initializing projects [\#422](https://github.com/eclipse/che/issues/422) -- CHE-545 Add estimate and resolve method calls from project API [\#420](https://github.com/eclipse/che/issues/420) -- CHE-542 Unify how to get workspace runtime config [\#419](https://github.com/eclipse/che/issues/419) -- CHE-541 Use a common way to get ws agen websocket URL [\#417](https://github.com/eclipse/che/issues/417) -- CHE-537 Adopt maven plugin according to CHE-258 [\#409](https://github.com/eclipse/che/issues/409) -- CHE-536 Differentiate explicitly created and detected projects on Workspace Agent. Do not save detected to Master ProjectConfig. [\#408](https://github.com/eclipse/che/issues/408) -- CHE-535 Java bare type could be only available if there are java files [\#407](https://github.com/eclipse/che/issues/407) -- CHE-532 Add the debug id on the 'Loader' widget [\#403](https://github.com/eclipse/che/issues/403) -- CHE-522 Unexpected the 'Failed to commit' message in the 'Events' after git commit [\#387](https://github.com/eclipse/che/issues/387) -- CHE-521 Git status output is different if 'Committer' has a name or has not. [\#386](https://github.com/eclipse/che/issues/386) -- CHE-520 Project Explorer doesn't display just created project [\#385](https://github.com/eclipse/che/issues/385) -- CHE-514 Fix jdt tests [\#375](https://github.com/eclipse/che/issues/375) -- CHE-512 Investigate ability to get content from Orion compare widget [\#374](https://github.com/eclipse/che/issues/374) -- CHE-510 Style improvements for dashboard [\#373](https://github.com/eclipse/che/issues/373) -- CHE-507 Error appears when creating a new sample project [\#370](https://github.com/eclipse/che/issues/370) + +**Pull requests merged:** + +- CHE-435 \[dashboard\] Introduce meaningful warning if browser is not being able ping ws agent [\#620](https://github.com/eclipse/che/pull/620) ([benoitf](https://github.com/benoitf)) +- CHE-495 Used simple entropy source. [\#619](https://github.com/eclipse/che/pull/619) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-209: fix recipes [\#616](https://github.com/eclipse/che/pull/616) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-439: fix referencing attributes due to model changes [\#615](https://github.com/eclipse/che/pull/615) ([ashumilova](https://github.com/ashumilova)) +- CHE-689 \[dashboard\] report error when starting agent [\#614](https://github.com/eclipse/che/pull/614) ([benoitf](https://github.com/benoitf)) +- CHE-522: Correct message when user tries to commit clean directory [\#612](https://github.com/eclipse/che/pull/612) ([dimasnurenko](https://github.com/dimasnurenko)) +- Che 217 improve creating project flow [\#604](https://github.com/eclipse/che/pull/604) ([olexii4](https://github.com/olexii4)) +- Autogenerated changes log. [\#603](https://github.com/eclipse/che/pull/603) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-414: Display staged changes in green when status called [\#560](https://github.com/eclipse/che/pull/560) ([vinokurig](https://github.com/vinokurig)) ## [4.0.0-RC9](https://github.com/eclipse/che/tree/4.0.0-RC9) (2016-03-01) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC8...4.0.0-RC9) +**Pull requests merged:** + +- Fetch module config directly from item reference [\#605](https://github.com/eclipse/che/pull/605) ([vzhukovskii](https://github.com/vzhukovskii)) +- CHE-131: Fix losing focus in editor after closing 'File structure' dialog [\#601](https://github.com/eclipse/che/pull/601) ([dimasnurenko](https://github.com/dimasnurenko)) +- Added description for toggle breakpoint action [\#596](https://github.com/eclipse/che/pull/596) ([mmorhun](https://github.com/mmorhun)) +- CHE-388 Don't use ugly browser prompt box to display 'Go to line' dialog window [\#595](https://github.com/eclipse/che/pull/595) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- fix NPE because of incorrect usage of firstNonNull [\#590](https://github.com/eclipse/che/pull/590) ([garagatyi](https://github.com/garagatyi)) +- CHE-661 unzip in quiet mode [\#587](https://github.com/eclipse/che/pull/587) ([benoitf](https://github.com/benoitf)) +- CODENVY-170 add promise-based authorization method to OAUth authenticators; prevent project synchronizing when factory used [\#585](https://github.com/eclipse/che/pull/585) ([mshaposhnik](https://github.com/mshaposhnik)) +- CHE-275: rename DOCKER\_MACHINE\_HOST to CHE\_DOCKER\_MACHINE\_HOST [\#579](https://github.com/eclipse/che/pull/579) ([garagatyi](https://github.com/garagatyi)) +- CHE-641 Add blank example project with a blank ready to go stack [\#578](https://github.com/eclipse/che/pull/578) ([benoitf](https://github.com/benoitf)) +- CHE-581 \[dashboard\] Code refactoring not applied on workspace import [\#575](https://github.com/eclipse/che/pull/575) ([benoitf](https://github.com/benoitf)) +- CHE-650 \[dashboard\] Fix export of a workspace following workspace model change [\#572](https://github.com/eclipse/che/pull/572) ([benoitf](https://github.com/benoitf)) +- Add dependency on Guava [\#568](https://github.com/eclipse/che/pull/568) ([vparfonov](https://github.com/vparfonov)) +- CODENVY-104: add new font awesome icons [\#565](https://github.com/eclipse/che/pull/565) ([olexii4](https://github.com/olexii4)) +- CHE-75: Cut long names in editor tab [\#564](https://github.com/eclipse/che/pull/564) ([dimasnurenko](https://github.com/dimasnurenko)) +- Fix use of the wrong gson adapter [\#557](https://github.com/eclipse/che/pull/557) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- Corrected old reference [\#553](https://github.com/eclipse/che/pull/553) ([anton-johansson](https://github.com/anton-johansson)) +- CHE-124 Create/Import wizards are displaying errors while nothing is entered [\#545](https://github.com/eclipse/che/pull/545) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-359: Guide the user while connecting the remote debugger [\#534](https://github.com/eclipse/che/pull/534) ([tolusha](https://github.com/tolusha)) +- CHE-22: check environment parameter on workspace start [\#518](https://github.com/eclipse/che/pull/518) ([garagatyi](https://github.com/garagatyi)) +- CHE-521: Perform git init command without initial commit [\#473](https://github.com/eclipse/che/pull/473) ([vinokurig](https://github.com/vinokurig)) + ## [4.0.0-RC8](https://github.com/eclipse/che/tree/4.0.0-RC8) (2016-02-28) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC7...4.0.0-RC8) -**Issues with no labels:** +**Pull requests merged:** -- Callback URL different from GitHub callback and che.properties [\#542](https://github.com/eclipse/che/issues/542) -- Creating workspace after starting up registry fails [\#532](https://github.com/eclipse/che/issues/532) -- Workspace cannot resolve Che server? [\#530](https://github.com/eclipse/che/issues/530) +- Fix build [\#555](https://github.com/eclipse/che/pull/555) ([benoitf](https://github.com/benoitf)) +- Option for blocking entropy flag [\#551](https://github.com/eclipse/che/pull/551) ([TylerJewell](https://github.com/TylerJewell)) +- CHE-622 \[dashboard\] Do not import templates commands if user is providing its own location [\#546](https://github.com/eclipse/che/pull/546) ([benoitf](https://github.com/benoitf)) +- Disappear JsOauthWindow after action is performed [\#544](https://github.com/eclipse/che/pull/544) ([evoevodin](https://github.com/evoevodin)) +- CHE-610 \[dashboard\] Restarting a workspace with a project results in an attempt to recreate a project [\#543](https://github.com/eclipse/che/pull/543) ([benoitf](https://github.com/benoitf)) +- Improve handling of ws agent started event [\#541](https://github.com/eclipse/che/pull/541) ([vparfonov](https://github.com/vparfonov)) +- Add promise based getRepository method to the GithubServiceClient [\#540](https://github.com/eclipse/che/pull/540) ([evoevodin](https://github.com/evoevodin)) +- CHE-559: Fix output of creating new machine in existed workspace [\#539](https://github.com/eclipse/che/pull/539) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-514: fix jdt tests [\#538](https://github.com/eclipse/che/pull/538) ([svor](https://github.com/svor)) +- \[dashboard\] CHE-611 fix links to get channels due to model change on machine config [\#535](https://github.com/eclipse/che/pull/535) ([benoitf](https://github.com/benoitf)) +- CODENVY-88 Setup new jvm defaults [\#528](https://github.com/eclipse/che/pull/528) ([skabashnyuk](https://github.com/skabashnyuk)) +- CHE-12: Fix NPE when there is no template [\#527](https://github.com/eclipse/che/pull/527) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-81: fix ws agent pinging [\#526](https://github.com/eclipse/che/pull/526) ([garagatyi](https://github.com/garagatyi)) +- CODENVY-122: Fix appearing create ws pop-up after start or open last used workspace [\#525](https://github.com/eclipse/che/pull/525) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-567: add directive for formating output [\#491](https://github.com/eclipse/che/pull/491) ([ashumilova](https://github.com/ashumilova)) +- adding setAuthorizationHeader method [\#489](https://github.com/eclipse/che/pull/489) ([stour](https://github.com/stour)) ## [4.0.0-RC7](https://github.com/eclipse/che/tree/4.0.0-RC7) (2016-02-25) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC6...4.0.0-RC7) -**Issues with no labels:** +**Pull requests merged:** -- Workspaces can't be created \<1gb [\#503](https://github.com/eclipse/che/issues/503) -- No feedback from ui when starting workspace [\#496](https://github.com/eclipse/che/issues/496) -- Che does not respond [\#484](https://github.com/eclipse/che/issues/484) -- What's the "temporary workspace"? [\#475](https://github.com/eclipse/che/issues/475) -- GitHub oAuth callback "http://${che\_localhost}:8080/che/api/oauth/callback" not working [\#472](https://github.com/eclipse/che/issues/472) -- Bug: equals called on same variable [\#462](https://github.com/eclipse/che/issues/462) -- Che upgrade from beta to RC3 release fails to detect my existing workspace [\#400](https://github.com/eclipse/che/issues/400) -- How to work with meteor projects? [\#392](https://github.com/eclipse/che/issues/392) -- How to customise project properties and preferences in Che? [\#303](https://github.com/eclipse/che/issues/303) -- Che will not start when JAVA\_HOME does not match "java -version" on Windows [\#295](https://github.com/eclipse/che/issues/295) -- How to finish an inline-rename of a field with vi-mode enabled? [\#288](https://github.com/eclipse/che/issues/288) -- Autocomplete not working no idea why, not sure how to debug [\#283](https://github.com/eclipse/che/issues/283) -- How can we setup environments with multiple machines? [\#281](https://github.com/eclipse/che/issues/281) -- Don't use Docker-in-Docker when running as a Docker Container [\#244](https://github.com/eclipse/che/issues/244) -- Unable to create workspaces [\#240](https://github.com/eclipse/che/issues/240) -- Passing argument to docker image [\#170](https://github.com/eclipse/che/issues/170) -- Too many open files with `codenvy/che:nightly` [\#143](https://github.com/eclipse/che/issues/143) +- Silky smooth factory workflow [\#536](https://github.com/eclipse/che/pull/536) ([benoitf](https://github.com/benoitf)) +- Exclude non-source directories from java project [\#523](https://github.com/eclipse/che/pull/523) ([vzhukovskii](https://github.com/vzhukovskii)) +- Fix of websocket closed errors [\#521](https://github.com/eclipse/che/pull/521) ([mshaposhnik](https://github.com/mshaposhnik)) +- Poject & Factory & GitServiceClient improvements [\#520](https://github.com/eclipse/che/pull/520) ([evoevodin](https://github.com/evoevodin)) +- CHE-395 Add visual feedback to clarify whether machine process is finished or still running [\#514](https://github.com/eclipse/che/pull/514) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-141: Add client side validation for packages' and class' names [\#513](https://github.com/eclipse/che/pull/513) ([dimasnurenko](https://github.com/dimasnurenko)) +- Remove usage of wrong Strings class [\#511](https://github.com/eclipse/che/pull/511) ([sleshchenko](https://github.com/sleshchenko)) +- Fix generic type for subscribe method of EventService [\#510](https://github.com/eclipse/che/pull/510) ([sleshchenko](https://github.com/sleshchenko)) +- Fix finding of git remote branches [\#508](https://github.com/eclipse/che/pull/508) ([akorneta](https://github.com/akorneta)) +- CHE-10: Set memory limits in build phase of Dockerfile [\#505](https://github.com/eclipse/che/pull/505) ([vinokurig](https://github.com/vinokurig)) +- Updates per issue [\#495](https://github.com/eclipse/che/pull/495) ([TylerJewell](https://github.com/TylerJewell)) +- Fix equality bug in paste action [\#493](https://github.com/eclipse/che/pull/493) ([vzhukovskii](https://github.com/vzhukovskii)) +- CHE-270: Change "Help \> Support" to "Help \> Community" [\#488](https://github.com/eclipse/che/pull/488) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-147: Fix updating editor tab after file renaming [\#486](https://github.com/eclipse/che/pull/486) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-550: fix projects views [\#483](https://github.com/eclipse/che/pull/483) ([olexii4](https://github.com/olexii4)) +- CHE-127: Load repo button on import from Github takes too much time [\#482](https://github.com/eclipse/che/pull/482) ([tolusha](https://github.com/tolusha)) +- CHE-127: Load repo button on import from Github takes too much time [\#481](https://github.com/eclipse/che/pull/481) ([tolusha](https://github.com/tolusha)) +- Add debug id for the testing purpose [\#480](https://github.com/eclipse/che/pull/480) ([vzhukovskii](https://github.com/vzhukovskii)) +- CODENVY-31: Replaced messages from git importer on error codes [\#470](https://github.com/eclipse/che/pull/470) ([akorneta](https://github.com/akorneta)) +- CHE-494: fix websocket machine channels [\#469](https://github.com/eclipse/che/pull/469) ([olexii4](https://github.com/olexii4)) +- CHE-314. Exclude che-core-api-analytics from packaging into assembly-machine-war [\#468](https://github.com/eclipse/che/pull/468) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- Adopt tree widget according to changes in project service [\#467](https://github.com/eclipse/che/pull/467) ([vzhukovskii](https://github.com/vzhukovskii)) +- CHE-165: show move wizard after performing 'Cut' operation in project… [\#466](https://github.com/eclipse/che/pull/466) ([svor](https://github.com/svor)) +- CHE-555: Fix wrong preview URL [\#465](https://github.com/eclipse/che/pull/465) ([dimasnurenko](https://github.com/dimasnurenko)) +- UD-941: connect to stacks API [\#460](https://github.com/eclipse/che/pull/460) ([akurinnoy](https://github.com/akurinnoy)) +- Fixed tests [\#456](https://github.com/eclipse/che/pull/456) ([eivantsov](https://github.com/eivantsov)) +- Fall back to unix socket on Linux if DOCKER\_HOST is malformed [\#454](https://github.com/eclipse/che/pull/454) ([eivantsov](https://github.com/eivantsov)) +- CHE-494: fix machine and workspace models [\#449](https://github.com/eclipse/che/pull/449) ([olexii4](https://github.com/olexii4)) +- CHE-439: add stackId to workspace and respect it on project creation [\#439](https://github.com/eclipse/che/pull/439) ([ashumilova](https://github.com/ashumilova)) +- Show auth window when performing import project from private repo or use factory with private repo [\#434](https://github.com/eclipse/che/pull/434) ([mshaposhnik](https://github.com/mshaposhnik)) +- CHE-165: add an ability to apply completion proposal automatically [\#433](https://github.com/eclipse/che/pull/433) ([svor](https://github.com/svor)) +- CHE-2: Add shortcuts and menu items to work with debugger [\#414](https://github.com/eclipse/che/pull/414) ([mmorhun](https://github.com/mmorhun)) +- Fix lowercase first letter of the RenameRefactoringAction description [\#412](https://github.com/eclipse/che/pull/412) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- CHE-127: Load repo button on import from Github takes too much time [\#404](https://github.com/eclipse/che/pull/404) ([tolusha](https://github.com/tolusha)) +- IDEX-4222: Change model of machine & workspace [\#350](https://github.com/eclipse/che/pull/350) ([garagatyi](https://github.com/garagatyi)) ## [4.0.0-RC6](https://github.com/eclipse/che/tree/4.0.0-RC6) (2016-02-20) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC5...4.0.0-RC6) -**Issues with no labels:** +**Pull requests merged:** -- CHE-562 Test dev label on github issues [\#451](https://github.com/eclipse/che/issues/451) -- Cannot Create Node Project: Endless exceptions in 'Injecting and starting workspace agent' [\#450](https://github.com/eclipse/che/issues/450) -- Workspace startup freezes on Catalina startup [\#411](https://github.com/eclipse/che/issues/411) -- How to deploy on PaaS [\#372](https://github.com/eclipse/che/issues/372) +- CHE-498: fix bulk edit in dashboard [\#477](https://github.com/eclipse/che/pull/477) ([akurinnoy](https://github.com/akurinnoy)) +- \[dashboard\] CHE\_510 Adopt new style [\#452](https://github.com/eclipse/che/pull/452) ([benoitf](https://github.com/benoitf)) +- CHE-555: Fix wrong preview URL for application [\#447](https://github.com/eclipse/che/pull/447) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-50: Fix NPE when loading GitHub repositories list [\#446](https://github.com/eclipse/che/pull/446) ([vinokurig](https://github.com/vinokurig)) +- CODENVY-128. Fix configure multimodular project with module without java files. [\#445](https://github.com/eclipse/che/pull/445) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- improve exception messages in MachineManager [\#443](https://github.com/eclipse/che/pull/443) ([garagatyi](https://github.com/garagatyi)) +- CHE-346 It's hard to click to close editor tab button [\#438](https://github.com/eclipse/che/pull/438) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-346 It's hard to click to close editor tab button [\#437](https://github.com/eclipse/che/pull/437) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- CHE-549 \[dashboard\] Increase timeout values for CI/jenkins [\#428](https://github.com/eclipse/che/pull/428) ([benoitf](https://github.com/benoitf)) +- CHE-120. Should not set default size for parts when user has sized the panel [\#427](https://github.com/eclipse/che/pull/427) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- \[dashboard\] Add auto-detecting project-type feature when importing project [\#426](https://github.com/eclipse/che/pull/426) ([benoitf](https://github.com/benoitf)) +- CHE-371: improve ws-agent connection timeout message [\#424](https://github.com/eclipse/che/pull/424) ([garagatyi](https://github.com/garagatyi)) +- CHE-283 Display machine status next to the dev-machine [\#416](https://github.com/eclipse/che/pull/416) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- Get user by name instead of alias [\#415](https://github.com/eclipse/che/pull/415) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- CHE-9: improve error messages from Docker API [\#410](https://github.com/eclipse/che/pull/410) ([garagatyi](https://github.com/garagatyi)) +- CHE-490: add footer with product logo and support stuff [\#377](https://github.com/eclipse/che/pull/377) ([ashumilova](https://github.com/ashumilova)) ## [4.0.0-RC5](https://github.com/eclipse/che/tree/4.0.0-RC5) (2016-02-18) [Full Changelog](https://github.com/eclipse/che/compare/4.0.0-RC4...4.0.0-RC5) -**Issues with no labels:** +**Pull requests merged:** -- @media Print CSS for eclipse-che.readme.io [\#382](https://github.com/eclipse/che/issues/382) -- CHE-513 Better handle exceptions when ws agent pings Che server [\#376](https://github.com/eclipse/che/issues/376) -- Create project in IDE got HTTP 409 conflict code [\#369](https://github.com/eclipse/che/issues/369) -- When specify the port, the ws-agent will still request to che-host:8080 [\#362](https://github.com/eclipse/che/issues/362) -- CHE-499 Make Dashboard compatible with CHE-306 [\#361](https://github.com/eclipse/che/issues/361) -- Test github to jira integration [\#360](https://github.com/eclipse/che/issues/360) -- CHE-500 Test github-jira integration with zapier [\#359](https://github.com/eclipse/che/issues/359) -- CHE-499Make Dashboard compatible with CHE-306 [\#358](https://github.com/eclipse/che/issues/358) -- Autocomplete not working on nodejs [\#348](https://github.com/eclipse/che/issues/348) -- workspace rename not working when stopped. [\#346](https://github.com/eclipse/che/issues/346) -- Question about the "Using che.sh Script" way to start che [\#336](https://github.com/eclipse/che/issues/336) -- Error pulling docker image of my workspace [\#325](https://github.com/eclipse/che/issues/325) -- Launching Che with docker as explained in documentation doesn't work [\#297](https://github.com/eclipse/che/issues/297) -- What is the right way to stop che? [\#287](https://github.com/eclipse/che/issues/287) -- Eclipse Che che.sh script not compatible with bash [\#262](https://github.com/eclipse/che/issues/262) -- New auxiliary machine displayed with name "docker" [\#249](https://github.com/eclipse/che/issues/249) -- Can't connect to ws://che-host:8080 when creating new project [\#148](https://github.com/eclipse/che/issues/148) +- Codenvy-123: fix machine snapshot creation after changes in swarm API [\#418](https://github.com/eclipse/che/pull/418) ([garagatyi](https://github.com/garagatyi)) +- CHE-535 Java bare type can be only applied if project has .java files [\#413](https://github.com/eclipse/che/pull/413) ([benoitf](https://github.com/benoitf)) +- CHE-436: replace "Open in IDE" to "Open project in IDE" [\#396](https://github.com/eclipse/che/pull/396) ([akurinnoy](https://github.com/akurinnoy)) +- CHE-142: reindex project after the refactoring operation [\#395](https://github.com/eclipse/che/pull/395) ([svor](https://github.com/svor)) +- Remove OAuth 1.0 api [\#388](https://github.com/eclipse/che/pull/388) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- CHE-345: allow offline machine creation [\#384](https://github.com/eclipse/che/pull/384) ([garagatyi](https://github.com/garagatyi)) +- CODENVY-35 code clean up [\#381](https://github.com/eclipse/che/pull/381) ([olexii4](https://github.com/olexii4)) +- Change the way how exceptions are handled when a ws-agent pings Che s… [\#368](https://github.com/eclipse/che/pull/368) ([eivantsov](https://github.com/eivantsov)) +- CHE-362: fix ignoring custom port of Che by ws agent [\#364](https://github.com/eclipse/che/pull/364) ([garagatyi](https://github.com/garagatyi)) +- CHE-95. Fix wrong scrolling in editor at using code assistant [\#363](https://github.com/eclipse/che/pull/363) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CHE-85: Fix machines names on machine panel. [\#357](https://github.com/eclipse/che/pull/357) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-297 Track not seen outputs in a process [\#356](https://github.com/eclipse/che/pull/356) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- fix Dockerfile: chown /home/user before operates [\#355](https://github.com/eclipse/che/pull/355) ([hongweiyi](https://github.com/hongweiyi)) +- CHE-70: Fix wrong behaviour during rename packages. [\#354](https://github.com/eclipse/che/pull/354) ([dimasnurenko](https://github.com/dimasnurenko)) +- Display configured project in project explorer after importing project [\#352](https://github.com/eclipse/che/pull/352) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- IDEX-3913: Implement stack api [\#351](https://github.com/eclipse/che/pull/351) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- UD-1028: rework main header and its components [\#349](https://github.com/eclipse/che/pull/349) ([ashumilova](https://github.com/ashumilova)) +- Moved win short directory conversion into bash [\#347](https://github.com/eclipse/che/pull/347) ([TylerJewell](https://github.com/TylerJewell)) +- Rework IDE start-up components [\#343](https://github.com/eclipse/che/pull/343) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- Add swagger module on ws-agent [\#342](https://github.com/eclipse/che/pull/342) ([akorneta](https://github.com/akorneta)) +- IDEX-4296: Move Setting compare windows size to show method [\#328](https://github.com/eclipse/che/pull/328) ([vinokurig](https://github.com/vinokurig)) +- IDEX-3566: Forbid commit if user name and email aren't set [\#326](https://github.com/eclipse/che/pull/326) ([vinokurig](https://github.com/vinokurig)) +- IDEX-4228: Fix import project from ssh url [\#318](https://github.com/eclipse/che/pull/318) ([vinokurig](https://github.com/vinokurig)) ## [4.0.0-RC4](https://github.com/eclipse/che/tree/4.0.0-RC4) (2016-02-15) -**Issues with no labels:** +**Pull requests merged:** -- Where is "che-tomcat8-slf4j-logback"? [\#337](https://github.com/eclipse/che/issues/337) -- "Could not find Che's application server." when trying to start it [\#335](https://github.com/eclipse/che/issues/335) -- readme "Run Che as a Server" section links to non-existent documentation [\#331](https://github.com/eclipse/che/issues/331) -- Scala support [\#301](https://github.com/eclipse/che/issues/301) -- Windows 10 - Eclipse che fails to create 'projects' folder [\#296](https://github.com/eclipse/che/issues/296) -- Che With Windows 64-bit? Not finding Java [\#290](https://github.com/eclipse/che/issues/290) -- Error in importing existing workspace [\#289](https://github.com/eclipse/che/issues/289) -- Node project only shows Blank and Maven project as configuration options [\#285](https://github.com/eclipse/che/issues/285) -- Create new workspace then you can create projects from the IDE [\#284](https://github.com/eclipse/che/issues/284) -- Update dependencies not using ~/.m2/repository in by custom stack [\#282](https://github.com/eclipse/che/issues/282) -- Consider combining preferences and settings and moving to Workspace menu [\#276](https://github.com/eclipse/che/issues/276) -- Document that custom stacks need to have a CMD that does not terminate [\#273](https://github.com/eclipse/che/issues/273) -- Unable to access eclipseche from host system [\#272](https://github.com/eclipse/che/issues/272) -- Documentation for running Che using docker-compose + potentially nginx-proxy & on carina [\#269](https://github.com/eclipse/che/issues/269) -- Cannot checkout private GitHub repository [\#266](https://github.com/eclipse/che/issues/266) -- Update dependency failed [\#263](https://github.com/eclipse/che/issues/263) -- Documentation not clear enough [\#260](https://github.com/eclipse/che/issues/260) -- Cannot uninstall che in mac? [\#259](https://github.com/eclipse/che/issues/259) -- Che wont start because of Java but i have the right version. [\#258](https://github.com/eclipse/che/issues/258) -- Can not open project in IDE [\#256](https://github.com/eclipse/che/issues/256) -- Unable to Create Workspace [\#253](https://github.com/eclipse/che/issues/253) -- Eclipse Che Space in filepath error [\#252](https://github.com/eclipse/che/issues/252) -- Is there a demo server available? [\#251](https://github.com/eclipse/che/issues/251) -- Cannot create additional machine [\#248](https://github.com/eclipse/che/issues/248) -- Compiling GWT Application FAILURE [\#247](https://github.com/eclipse/che/issues/247) -- import project from local file system [\#246](https://github.com/eclipse/che/issues/246) -- che.sh -p doesn't publish port 8080 to the specified port [\#243](https://github.com/eclipse/che/issues/243) -- Che force closes [\#239](https://github.com/eclipse/che/issues/239) -- Need guide for Maven Usage [\#236](https://github.com/eclipse/che/issues/236) -- How to enable User Account Control [\#235](https://github.com/eclipse/che/issues/235) -- Che won't start on Windows7 [\#231](https://github.com/eclipse/che/issues/231) -- any documentation for backup workspaces before upgrade/rebuild new github updates? [\#230](https://github.com/eclipse/che/issues/230) -- 'conditional binary operator expected' error [\#227](https://github.com/eclipse/che/issues/227) -- "Error while creating the project - Internal Server Error: Unable get private ssh key" [\#225](https://github.com/eclipse/che/issues/225) -- Unable to create project [\#224](https://github.com/eclipse/che/issues/224) -- failing to create new project [\#222](https://github.com/eclipse/che/issues/222) -- debian jessie JAVA\_HOME issue [\#221](https://github.com/eclipse/che/issues/221) -- Che can't make workspace or project [\#220](https://github.com/eclipse/che/issues/220) -- Cannot create new workspace [\#219](https://github.com/eclipse/che/issues/219) -- Che server does not start [\#217](https://github.com/eclipse/che/issues/217) -- Folders that only contain one subfolder break the UI [\#214](https://github.com/eclipse/che/issues/214) -- Require password [\#213](https://github.com/eclipse/che/issues/213) -- 127.0.0.1:8080 always redirects to /che/default for Chrome [\#196](https://github.com/eclipse/che/issues/196) -- About the feature of "remote machine" [\#188](https://github.com/eclipse/che/issues/188) -- Docs may out of date [\#185](https://github.com/eclipse/che/issues/185) -- Start Che Error [\#182](https://github.com/eclipse/che/issues/182) -- Eclipse Che start error [\#180](https://github.com/eclipse/che/issues/180) -- Build error [\#177](https://github.com/eclipse/che/issues/177) -- My che container starts very slow [\#176](https://github.com/eclipse/che/issues/176) -- What does "Project git url" be used? [\#174](https://github.com/eclipse/che/issues/174) -- Can't create maven command with the name "newMaven" [\#172](https://github.com/eclipse/che/issues/172) -- `docker ps` checking fails randomly [\#171](https://github.com/eclipse/che/issues/171) -- Can't start machine dev-machine. Connection timed out [\#169](https://github.com/eclipse/che/issues/169) -- API for updating project files [\#166](https://github.com/eclipse/che/issues/166) -- Why will `che.sh` be invoked when the docker container is started? [\#165](https://github.com/eclipse/che/issues/165) -- Why the exposed port range is 32768-65535, which is not the same as the range in che.properties? [\#164](https://github.com/eclipse/che/issues/164) -- README.md - Link to Write Che IDE Plug-Ins broken [\#163](https://github.com/eclipse/che/issues/163) -- Where can I find the git hash from a che docker image? [\#161](https://github.com/eclipse/che/issues/161) -- How to use the provided tomcat8 in workspace image "codenvy/ubuntu\_jdk8"? [\#156](https://github.com/eclipse/che/issues/156) -- Incorrect error message che.sh [\#153](https://github.com/eclipse/che/issues/153) -- compile error [\#142](https://github.com/eclipse/che/issues/142) -- Build docker image failed [\#137](https://github.com/eclipse/che/issues/137) -- Where is the docker image for che 4.x? [\#136](https://github.com/eclipse/che/issues/136) -- How to delete a running workspace? [\#133](https://github.com/eclipse/che/issues/133) -- Can't find which port is using by tomcat for `codenvy/ubuntu\_jdk8` \(che 4.x\) [\#132](https://github.com/eclipse/che/issues/132) -- How to create a html+js project in 4.x [\#131](https://github.com/eclipse/che/issues/131) -- Incorrect buld & run instructions on http://eclipse.org/che [\#125](https://github.com/eclipse/che/issues/125) -- https required [\#120](https://github.com/eclipse/che/issues/120) -- depency problem [\#119](https://github.com/eclipse/che/issues/119) -- How to hide the projects belong to other workspaces? [\#116](https://github.com/eclipse/che/issues/116) -- Is it possible to start many che instances on a server? [\#115](https://github.com/eclipse/che/issues/115) -- User management [\#114](https://github.com/eclipse/che/issues/114) -- Compiling GWT Application Failed [\#113](https://github.com/eclipse/che/issues/113) -- 404 after install [\#110](https://github.com/eclipse/che/issues/110) -- How can I provide custom che properties outside the docker? [\#109](https://github.com/eclipse/che/issues/109) -- Data is lost when I restart my che in docker, how to prevent it? [\#108](https://github.com/eclipse/che/issues/108) -- Is it possible to run a single Java file or a Java test from the UI? [\#105](https://github.com/eclipse/che/issues/105) -- Can't access web interface for docker image [\#104](https://github.com/eclipse/che/issues/104) -- How to uninstall? [\#101](https://github.com/eclipse/che/issues/101) -- Debuggin in che [\#100](https://github.com/eclipse/che/issues/100) +- IDEX-3756: fix NPE for rename refactoring when the linked editor is a… [\#341](https://github.com/eclipse/che/pull/341) ([svor](https://github.com/svor)) +- Add setup user email during the creation [\#338](https://github.com/eclipse/che/pull/338) ([akorneta](https://github.com/akorneta)) +- IDEX-3849: Add information about project to git output panel. [\#334](https://github.com/eclipse/che/pull/334) ([dimasnurenko](https://github.com/dimasnurenko)) +- CHE-1 Fixed swagger service deployment [\#333](https://github.com/eclipse/che/pull/333) ([skabashnyuk](https://github.com/skabashnyuk)) +- IDEX-3737. Fix errors after Git checkout operation [\#330](https://github.com/eclipse/che/pull/330) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CLDIDE-2715 Add export workspace portability flow [\#329](https://github.com/eclipse/che/pull/329) ([benoitf](https://github.com/benoitf)) +- UD-1051 Allow to connect to remote API [\#327](https://github.com/eclipse/che/pull/327) ([benoitf](https://github.com/benoitf)) +- UD-1050 Fix notification link to controller by removing the use of the scope [\#323](https://github.com/eclipse/che/pull/323) ([benoitf](https://github.com/benoitf)) +- Improved JavaDoc of @DynaModule [\#322](https://github.com/eclipse/che/pull/322) ([anton-johansson](https://github.com/anton-johansson)) +- IDEX-4129: scroll document to execution point [\#320](https://github.com/eclipse/che/pull/320) ([dmytro-ndp](https://github.com/dmytro-ndp)) +- UD-1049 : do not change files after build [\#317](https://github.com/eclipse/che/pull/317) ([benoitf](https://github.com/benoitf)) +- IDEX-3353: Fix cursor appearing after select item in autocomplete [\#316](https://github.com/eclipse/che/pull/316) ([dimasnurenko](https://github.com/dimasnurenko)) +- adopted Dockerfile to new Che repo structure [\#315](https://github.com/eclipse/che/pull/315) ([eivantsov](https://github.com/eivantsov)) +- Set correct dependency scope [\#314](https://github.com/eclipse/che/pull/314) ([vparfonov](https://github.com/vparfonov)) +- User AtomicInteher for debug session id [\#313](https://github.com/eclipse/che/pull/313) ([vparfonov](https://github.com/vparfonov)) +- IDEX-4180: Fix copy command-fragment in commands dialog [\#312](https://github.com/eclipse/che/pull/312) ([dimasnurenko](https://github.com/dimasnurenko)) +- Remove the usage of license years property and use inceptionYear [\#311](https://github.com/eclipse/che/pull/311) ([benoitf](https://github.com/benoitf)) +- Now that dashboard is part of common che project, use the same layout [\#310](https://github.com/eclipse/che/pull/310) ([benoitf](https://github.com/benoitf)) +- UD-1048 Avoid to get error This is not a JSON Array [\#309](https://github.com/eclipse/che/pull/309) ([benoitf](https://github.com/benoitf)) +- Add phantomjs module [\#308](https://github.com/eclipse/che/pull/308) ([ashumilova](https://github.com/ashumilova)) +- Add error codes and attributes to server exceptions [\#307](https://github.com/eclipse/che/pull/307) ([mshaposhnik](https://github.com/mshaposhnik)) +- IDEX-3819 Add auto-csroll to command's output. [\#306](https://github.com/eclipse/che/pull/306) ([dimasnurenko](https://github.com/dimasnurenko)) +- IDEX-3409: Reconfigure ports for JMX/RMI server [\#305](https://github.com/eclipse/che/pull/305) ([akorneta](https://github.com/akorneta)) +- Fixed launching Che with -i on Linux [\#304](https://github.com/eclipse/che/pull/304) ([eivantsov](https://github.com/eivantsov)) +- Fix terminal assembly [\#298](https://github.com/eclipse/che/pull/298) ([skabashnyuk](https://github.com/skabashnyuk)) +- Adopting to new grouid and artifactid [\#294](https://github.com/eclipse/che/pull/294) ([skabashnyuk](https://github.com/skabashnyuk)) +- CLDIDE-2692: Bind correct validator implementation [\#293](https://github.com/eclipse/che/pull/293) ([evoevodin](https://github.com/evoevodin)) +- Revert "IDEX-4137: fix "Internal Server Error" error message in "Evaluate Expression" popup" [\#292](https://github.com/eclipse/che/pull/292) ([vparfonov](https://github.com/vparfonov)) +- IDEX-4137: fix "Internal Server Error" error message in "Evaluate Expression" popup [\#291](https://github.com/eclipse/che/pull/291) ([mmorhun](https://github.com/mmorhun)) +- IDEX-4293 enable CORS on Che workspace master allowing to import remote WS [\#270](https://github.com/eclipse/che/pull/270) ([benoitf](https://github.com/benoitf)) +- CLDIDE-2659 Move user resolving for git operations into separate class [\#268](https://github.com/eclipse/che/pull/268) ([mshaposhnik](https://github.com/mshaposhnik)) +- Excluded gwt libraries from packaging [\#265](https://github.com/eclipse/che/pull/265) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- Improvements to remove docker-in-docker for che running as image [\#257](https://github.com/eclipse/che/pull/257) ([TylerJewell](https://github.com/TylerJewell)) +- Fix typos in properties descriptions [\#255](https://github.com/eclipse/che/pull/255) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- IDEX-4054: Update plugin openshift [\#254](https://github.com/eclipse/che/pull/254) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- IDEX-4235 provide minimal JVM config to build che [\#242](https://github.com/eclipse/che/pull/242) ([skabashnyuk](https://github.com/skabashnyuk)) +- IDEX-4232: Support windows directories with spaces [\#241](https://github.com/eclipse/che/pull/241) ([TylerJewell](https://github.com/TylerJewell)) +- Add signed commits requirement to contributing.md [\#234](https://github.com/eclipse/che/pull/234) ([eivantsov](https://github.com/eivantsov)) +- Fixed incorrect link to the repository. [\#233](https://github.com/eclipse/che/pull/233) ([anton-johansson](https://github.com/anton-johansson)) +- fix check of docker accessability on old bash versions [\#228](https://github.com/eclipse/che/pull/228) ([garagatyi](https://github.com/garagatyi)) +- IDEX-4219 avoid duplication of templates across the packagings [\#226](https://github.com/eclipse/che/pull/226) ([riuvshin](https://github.com/riuvshin)) +- Remove set -o pipefail fron che script [\#223](https://github.com/eclipse/che/pull/223) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3967: add support of https [\#215](https://github.com/eclipse/che/pull/215) ([garagatyi](https://github.com/garagatyi)) +- IDEX-4174: Add ability to start registry [\#212](https://github.com/eclipse/che/pull/212) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-3989: do not start ws agent if api is unreachable [\#211](https://github.com/eclipse/che/pull/211) ([garagatyi](https://github.com/garagatyi)) +- Configure path to rest services on machine for swagger specification [\#209](https://github.com/eclipse/che/pull/209) ([skabashnyuk](https://github.com/skabashnyuk)) +- add possibility to inject api endpoint as uri [\#208](https://github.com/eclipse/che/pull/208) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3836 remove rewrite.config [\#207](https://github.com/eclipse/che/pull/207) ([vparfonov](https://github.com/vparfonov)) +- Fix problems with installing npm packages on Windows [\#206](https://github.com/eclipse/che/pull/206) ([vparfonov](https://github.com/vparfonov)) +- IDEX-4075 Update favicon : now with transparent background [\#205](https://github.com/eclipse/che/pull/205) ([benoitf](https://github.com/benoitf)) +- IDEX-4103: Preview URLs on windows / mac give wrong URL [\#204](https://github.com/eclipse/che/pull/204) ([vzhukovskii](https://github.com/vzhukovskii)) +- /bin/catalina.sh run -\> /bin/catalina.sh stop [\#203](https://github.com/eclipse/che/pull/203) ([vparfonov](https://github.com/vparfonov)) +- IDEX-4075 Update to a new favicon [\#201](https://github.com/eclipse/che/pull/201) ([benoitf](https://github.com/benoitf)) +- Remove unused property org.apache.tomcat.version in pom.xml [\#200](https://github.com/eclipse/che/pull/200) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- Added back missing /plugins directories [\#199](https://github.com/eclipse/che/pull/199) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-4097: Document che.properties [\#198](https://github.com/eclipse/che/pull/198) ([TylerJewell](https://github.com/TylerJewell)) +- Add mandatory check for JAVA\_HOME [\#197](https://github.com/eclipse/che/pull/197) ([TylerJewell](https://github.com/TylerJewell)) +- Rename properties [\#195](https://github.com/eclipse/che/pull/195) ([vparfonov](https://github.com/vparfonov)) +- IDEX-4065 Fix the templates directory name [\#194](https://github.com/eclipse/che/pull/194) ([benoitf](https://github.com/benoitf)) +- IDEX-4075 update che logo [\#193](https://github.com/eclipse/che/pull/193) ([benoitf](https://github.com/benoitf)) +- CDEC-503 Add user.self.creation.allowed property [\#192](https://github.com/eclipse/che/pull/192) ([sleshchenko](https://github.com/sleshchenko)) +- Update names of template references [\#191](https://github.com/eclipse/che/pull/191) ([TylerJewell](https://github.com/TylerJewell)) +- Idex 3812 Introduce swagger ui for che [\#190](https://github.com/eclipse/che/pull/190) ([skabashnyuk](https://github.com/skabashnyuk)) +- IDEX-4053: Add attributes \ field to CommandDTO and re… [\#189](https://github.com/eclipse/che/pull/189) ([vzhukovskii](https://github.com/vzhukovskii)) +- IDEX-4047 - Add ability to skip checks to startup script [\#187](https://github.com/eclipse/che/pull/187) ([TylerJewell](https://github.com/TylerJewell)) +- Idex 4048 - che-install-plugin + SDK tools ported to 4.0 [\#186](https://github.com/eclipse/che/pull/186) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-4019 Enable filter [\#184](https://github.com/eclipse/che/pull/184) ([benoitf](https://github.com/benoitf)) +- IDEX-3295 Added default project importer property [\#183](https://github.com/eclipse/che/pull/183) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-4037: Add previewURL to the samples bundle with beta [\#181](https://github.com/eclipse/che/pull/181) ([vzhukovskii](https://github.com/vzhukovskii)) +- IDEX-3840: add ssh plugin [\#178](https://github.com/eclipse/che/pull/178) ([ashumilova](https://github.com/ashumilova)) +- Added plugin extension examples for users [\#175](https://github.com/eclipse/che/pull/175) ([TylerJewell](https://github.com/TylerJewell)) +- Add check for Java, Java Version, Linux UID, Linux Docker Group [\#168](https://github.com/eclipse/che/pull/168) ([TylerJewell](https://github.com/TylerJewell)) +- Update project-templates.json to add templates for 4.0-beta [\#167](https://github.com/eclipse/che/pull/167) ([slemeur](https://github.com/slemeur)) +- Make it possible to find by tag recipe which is appropriate for launching GWT SuperDev mode [\#162](https://github.com/eclipse/che/pull/162) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- IDEX-3919 [\#160](https://github.com/eclipse/che/pull/160) ([mmorhun](https://github.com/mmorhun)) +- Added back in missing CHE\_PORT variable setting. [\#159](https://github.com/eclipse/che/pull/159) ([TylerJewell](https://github.com/TylerJewell)) +- Rename che.war to ide.war, fix redirect rules and remove not need files [\#158](https://github.com/eclipse/che/pull/158) ([vparfonov](https://github.com/vparfonov)) +- Created CODE\_OF\_CONDUCT.md [\#157](https://github.com/eclipse/che/pull/157) ([bmicklea](https://github.com/bmicklea)) +- IDEX-4005 - add definable machine name property [\#155](https://github.com/eclipse/che/pull/155) ([TylerJewell](https://github.com/TylerJewell)) +- Fixed typos in usage & error\_exit [\#154](https://github.com/eclipse/che/pull/154) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-3920 [\#152](https://github.com/eclipse/che/pull/152) ([sleshchenko](https://github.com/sleshchenko)) +- IDEX-3994, IDEX-3995: add fixes to Che start script [\#151](https://github.com/eclipse/che/pull/151) ([garagatyi](https://github.com/garagatyi)) +- Bash command; docker container logic [\#150](https://github.com/eclipse/che/pull/150) ([TylerJewell](https://github.com/TylerJewell)) +- Travis icon should be removed from README as well [\#149](https://github.com/eclipse/che/pull/149) ([freewind](https://github.com/freewind)) +- IDEX-3871: Update name of Che modules [\#147](https://github.com/eclipse/che/pull/147) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-2726: move start of ws agent to che-core [\#145](https://github.com/eclipse/che/pull/145) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3912: Move project template service to workspace master [\#144](https://github.com/eclipse/che/pull/144) ([dimasnurenko](https://github.com/dimasnurenko)) +- IDEX-3726: adopt ws agent to run it as common machine process [\#141](https://github.com/eclipse/che/pull/141) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3760: Avoid using deprecated methods from org.eclipse.che.ide.util.Config [\#139](https://github.com/eclipse/che/pull/139) ([dimasnurenko](https://github.com/dimasnurenko)) +- Update to auto-add DOCKER\_ variables [\#138](https://github.com/eclipse/che/pull/138) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-3759: include 'che-plugin-sdk-ext-plugins' to Che assembly [\#135](https://github.com/eclipse/che/pull/135) ([azatsarynnyy](https://github.com/azatsarynnyy)) +- IDEX-3681: Show logs of dependency updater to the output console [\#134](https://github.com/eclipse/che/pull/134) ([dimasnurenko](https://github.com/dimasnurenko)) +- Set CHE\_HOME blank if set & invalid directory [\#129](https://github.com/eclipse/che/pull/129) ([TylerJewell](https://github.com/TylerJewell)) +- Sync changes from 3.x branch [\#128](https://github.com/eclipse/che/pull/128) ([benoitf](https://github.com/benoitf)) +- fix che.sh on linux if user starts it not from current directory [\#127](https://github.com/eclipse/che/pull/127) ([garagatyi](https://github.com/garagatyi)) +- Fix variables in assembly [\#126](https://github.com/eclipse/che/pull/126) ([skabashnyuk](https://github.com/skabashnyuk)) +- IDEX-3736: add null value for new nullable property [\#124](https://github.com/eclipse/che/pull/124) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3797: add the Dashboard plugin [\#123](https://github.com/eclipse/che/pull/123) ([olexii4](https://github.com/olexii4)) +- IDEX-3437: fix binding of named variables [\#122](https://github.com/eclipse/che/pull/122) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3837: Che directory structure, environment variables, and dependency checks [\#121](https://github.com/eclipse/che/pull/121) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-2982. Change Che pom.xml parent values [\#117](https://github.com/eclipse/che/pull/117) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- Add default configuration for openshift services [\#112](https://github.com/eclipse/che/pull/112) ([sleshchenko](https://github.com/sleshchenko)) +- UD-838 URL redirect in Che [\#111](https://github.com/eclipse/che/pull/111) ([benoitf](https://github.com/benoitf)) +- IDEX-3761 Add redirect for che /ext server calls [\#107](https://github.com/eclipse/che/pull/107) ([benoitf](https://github.com/benoitf)) +- IDEX-3670: Bind RemotePreferenceDao [\#106](https://github.com/eclipse/che/pull/106) ([evoevodin](https://github.com/evoevodin)) +- Update README.md [\#102](https://github.com/eclipse/che/pull/102) ([smiller171](https://github.com/smiller171)) +- IDEX-3396: Add ability to save workspace's snapshot [\#99](https://github.com/eclipse/che/pull/99) ([evoevodin](https://github.com/evoevodin)) +- IDEX-3590: Fix bug related to launch Che after stopping [\#98](https://github.com/eclipse/che/pull/98) ([dimasnurenko](https://github.com/dimasnurenko)) +- IDEX-2929: Change creator id in docker recipe from "codenvy" to "che" for Che [\#97](https://github.com/eclipse/che/pull/97) ([vinokurig](https://github.com/vinokurig)) +- IDEX-3512: Add provider and binding for user token on machine [\#95](https://github.com/eclipse/che/pull/95) ([akorneta](https://github.com/akorneta)) +- IDEX-3463 updating archetype README with remote catalog alternative [\#94](https://github.com/eclipse/che/pull/94) ([stour](https://github.com/stour)) +- IDEX-3467: Include MIT license [\#93](https://github.com/eclipse/che/pull/93) ([akorneta](https://github.com/akorneta)) +- IDEX-3273: exclude unnecessary client jars [\#92](https://github.com/eclipse/che/pull/92) ([svor](https://github.com/svor)) +- IDEX-3428: Change license to EPL [\#91](https://github.com/eclipse/che/pull/91) ([akorneta](https://github.com/akorneta)) +- IDEX-3080 Manage the indicators for warning/errors/quickfix [\#90](https://github.com/eclipse/che/pull/90) ([vitaliy-guliy](https://github.com/vitaliy-guliy)) +- Use GuiceEverrestServlet instead of CheGuiceEverrestServlet [\#89](https://github.com/eclipse/che/pull/89) ([vparfonov](https://github.com/vparfonov)) +- IDEX-3393: increase tcp connection timeouts from 1 minute to 10 minutes [\#88](https://github.com/eclipse/che/pull/88) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3356: Add missing bindings [\#87](https://github.com/eclipse/che/pull/87) ([akorneta](https://github.com/akorneta)) +- CLDIDE-2552 Enable dependency convergence [\#86](https://github.com/eclipse/che/pull/86) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-3463 Creating archetypes that let users quickly generate workable Che plug-in [\#85](https://github.com/eclipse/che/pull/85) ([stour](https://github.com/stour)) +- IDEX-3360: Rebuild dev machine images and add them to the list of pre-defined recipes [\#83](https://github.com/eclipse/che/pull/83) ([eivantsov](https://github.com/eivantsov)) +- IDEX-3261 Add UD in Che [\#82](https://github.com/eclipse/che/pull/82) ([benoitf](https://github.com/benoitf)) +- IDEX-3243 Use the che-host property defined when starting the docker container [\#81](https://github.com/eclipse/che/pull/81) ([benoitf](https://github.com/benoitf)) +- IDEX-3190: Use che.properties.root variable instead of hardcoded path [\#80](https://github.com/eclipse/che/pull/80) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- IDEX-3352 Fix invalid data about revision [\#79](https://github.com/eclipse/che/pull/79) ([benoitf](https://github.com/benoitf)) +- IDEX-3347 Cleanup New Project wizard [\#78](https://github.com/eclipse/che/pull/78) ([stour](https://github.com/stour)) +- IDEX-3131: move listener binding from machine dynamodule to che module [\#77](https://github.com/eclipse/che/pull/77) ([garagatyi](https://github.com/garagatyi)) +- IDEX-3123: Change behaviour during starting workspace. Add some fixes. [\#76](https://github.com/eclipse/che/pull/76) ([dimasnurenko](https://github.com/dimasnurenko)) +- UD-806 Allow to handle drag and drop local files to the Che instance [\#75](https://github.com/eclipse/che/pull/75) ([benoitf](https://github.com/benoitf)) +- INFRA-868 used gwt compiler configuration from parent pom [\#74](https://github.com/eclipse/che/pull/74) ([skabashnyuk](https://github.com/skabashnyuk)) +- MaxPermSize is not required/supported with Java8 [\#73](https://github.com/eclipse/che/pull/73) ([benoitf](https://github.com/benoitf)) +- IDEX-3281: Increase session timeout [\#72](https://github.com/eclipse/che/pull/72) ([evoevodin](https://github.com/evoevodin)) +- IDEX-3138. Fill samples from maven.json of assembly-machine-server on che. [\#70](https://github.com/eclipse/che/pull/70) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- IDEX-3261 UD in Eclipse Che [\#69](https://github.com/eclipse/che/pull/69) ([benoitf](https://github.com/benoitf)) +- IDEX-3240 Maven Mojo allowing to create Che plugins [\#68](https://github.com/eclipse/che/pull/68) ([benoitf](https://github.com/benoitf)) +- IDEX-3288 [\#67](https://github.com/eclipse/che/pull/67) ([stour](https://github.com/stour)) +- bunch of fixes for ext scripts [\#66](https://github.com/eclipse/che/pull/66) ([benoitf](https://github.com/benoitf)) +- IDEX-3241 Add che admin war [\#65](https://github.com/eclipse/che/pull/65) ([benoitf](https://github.com/benoitf)) +- IDEX-3260 Remove factory API from Eclipse Che [\#64](https://github.com/eclipse/che/pull/64) ([benoitf](https://github.com/benoitf)) +- Fix Che on OSX [\#63](https://github.com/eclipse/che/pull/63) ([skabashnyuk](https://github.com/skabashnyuk)) +- CLDIDE-2537 Set property machine.docker.machine\_extra\_hosts=NULL [\#62](https://github.com/eclipse/che/pull/62) ([skabashnyuk](https://github.com/skabashnyuk)) +- IDEX-2982. Change Che pom.xml parent values [\#61](https://github.com/eclipse/che/pull/61) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- CLDIDE-2566: Change configuration for predefined recipe loader [\#60](https://github.com/eclipse/che/pull/60) ([akorneta](https://github.com/akorneta)) +- CLDIDE-2537 Set defaults fro machine extra hosts [\#59](https://github.com/eclipse/che/pull/59) ([skabashnyuk](https://github.com/skabashnyuk)) +- updating new-project-type-wizard artifactId and che-templates related data [\#58](https://github.com/eclipse/che/pull/58) ([stour](https://github.com/stour)) +- client-new-project-wizard + server-new-project-type -\> new-project-type-wizard [\#57](https://github.com/eclipse/che/pull/57) ([stour](https://github.com/stour)) +- IDEX-3138. Remove TutorialProjectType. Change project type for samples. [\#56](https://github.com/eclipse/che/pull/56) ([RomanNikitenko](https://github.com/RomanNikitenko)) +- IDEX-3139: Removed Subversion from standart Che distribution [\#55](https://github.com/eclipse/che/pull/55) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- IDEX-3133 Upgrade Guice to 4.0 version \(4.0\) [\#54](https://github.com/eclipse/che/pull/54) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-3169 Allow redirect from /api to /che/api [\#53](https://github.com/eclipse/che/pull/53) ([benoitf](https://github.com/benoitf)) +- Upgrade Guice to 4.0 version [\#52](https://github.com/eclipse/che/pull/52) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-2861 Enable dependency convergence [\#51](https://github.com/eclipse/che/pull/51) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-3087: added predefined recipes [\#50](https://github.com/eclipse/che/pull/50) ([akorneta](https://github.com/akorneta)) +- Adds Eclipse Che to command prompt [\#49](https://github.com/eclipse/che/pull/49) ([TylerJewell](https://github.com/TylerJewell)) +- Changed \ from Codenvy to Eclipse Che [\#48](https://github.com/eclipse/che/pull/48) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-3052 Allow to find Java in Windows Registry if not defined [\#47](https://github.com/eclipse/che/pull/47) ([benoitf](https://github.com/benoitf)) +- IDEX-3051 allow to use spaces in folders [\#46](https://github.com/eclipse/che/pull/46) ([benoitf](https://github.com/benoitf)) +- IDEX-2938 remove findbugs jsr305 annotations \(4.0\) [\#45](https://github.com/eclipse/che/pull/45) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- CLDIDE-2535: added property for mount projects root [\#44](https://github.com/eclipse/che/pull/44) ([akorneta](https://github.com/akorneta)) +- IDEX-3032 Remove java:web runner as we have this runners from Docker [\#43](https://github.com/eclipse/che/pull/43) ([benoitf](https://github.com/benoitf)) +- IDEX-2938 removed findbugs jsr305 annotation [\#42](https://github.com/eclipse/che/pull/42) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-3036 Exclude unused resources [\#41](https://github.com/eclipse/che/pull/41) ([skabashnyuk](https://github.com/skabashnyuk)) +- Idex 2909 [\#40](https://github.com/eclipse/che/pull/40) ([mshaposhnik](https://github.com/mshaposhnik)) +- IDEX-2180: added che-plugin-git-provider dependency [\#39](https://github.com/eclipse/che/pull/39) ([svor](https://github.com/svor)) +- IDEX-2970 Use recipes from plugin-docker [\#38](https://github.com/eclipse/che/pull/38) ([benoitf](https://github.com/benoitf)) +- IDEX-2966; remove plugin-datasource dependencies; [\#37](https://github.com/eclipse/che/pull/37) ([mshaposhnik](https://github.com/mshaposhnik)) +- Make more consistent assembly [\#36](https://github.com/eclipse/che/pull/36) ([benoitf](https://github.com/benoitf)) +- correcting parent in examples root pom + sortpom formatting [\#35](https://github.com/eclipse/che/pull/35) ([stour](https://github.com/stour)) +- setting correct snapshot version in examples [\#34](https://github.com/eclipse/che/pull/34) ([stour](https://github.com/stour)) +- Updated README with latest positioning. [\#33](https://github.com/eclipse/che/pull/33) ([TylerJewell](https://github.com/TylerJewell)) +- IDEX-2923 Add Docker recipes + examples in Che [\#32](https://github.com/eclipse/che/pull/32) ([benoitf](https://github.com/benoitf)) +- New che/examples folder [\#31](https://github.com/eclipse/che/pull/31) ([stour](https://github.com/stour)) +- IDEX-2910: changed path of the local storage folder [\#30](https://github.com/eclipse/che/pull/30) ([svor](https://github.com/svor)) +- IDEX-2956 Remove internal script [\#29](https://github.com/eclipse/che/pull/29) ([benoitf](https://github.com/benoitf)) +- MaxPermSize is not used anymore with Java8 \(4.0 branch\) [\#26](https://github.com/eclipse/che/pull/26) ([benoitf](https://github.com/benoitf)) +- IDEX-2932 Add support for Docker 1.8.1 \(4.0 branch\) [\#24](https://github.com/eclipse/che/pull/24) ([benoitf](https://github.com/benoitf)) +- IDEX-2801 Changed CODENVY\_LOGS\_DIR to CHE\_LOGS\_DIR [\#23](https://github.com/eclipse/che/pull/23) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-2856: eliminated dependency unpacking [\#22](https://github.com/eclipse/che/pull/22) ([akorneta](https://github.com/akorneta)) +- IDEX-2892 Include Docker plugin in the SDK [\#21](https://github.com/eclipse/che/pull/21) ([benoitf](https://github.com/benoitf)) +- IDEX-2800 Changed CODENVY\_LOCAL\_CONF\_DIR to CHE\_LOCAL\_CONF\_DIR [\#20](https://github.com/eclipse/che/pull/20) ([mkuznyetsov](https://github.com/mkuznyetsov)) +- IDEX-2618: plugin git refactoring [\#19](https://github.com/eclipse/che/pull/19) ([akorneta](https://github.com/akorneta)) +- IDEX-2888 Update for Java8 [\#17](https://github.com/eclipse/che/pull/17) ([benoitf](https://github.com/benoitf)) +- added binding for DockerVersionVerifier [\#16](https://github.com/eclipse/che/pull/16) ([akorneta](https://github.com/akorneta)) +- IDEX-2831: Fixed extInstall.sh and extInstall.bat for integration 3rd… [\#15](https://github.com/eclipse/che/pull/15) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- Fixed install extenstions on Windows os by extInstall.bat [\#14](https://github.com/eclipse/che/pull/14) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- Adds mobile-web-app-capable meta tag. Enables fullscreen for mobile [\#13](https://github.com/eclipse/che/pull/13) ([surfacelevel](https://github.com/surfacelevel)) +- IDEX-2831: Fixed extInstall.sh for integration 3rd-party extensions t… [\#12](https://github.com/eclipse/che/pull/12) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- IDEX-2163: Fixed null pointer exception when viewing javadoc of class default constructor [\#10](https://github.com/eclipse/che/pull/10) ([dimasnurenko](https://github.com/dimasnurenko)) +- Fixed launch SDK on Windows [\#9](https://github.com/eclipse/che/pull/9) ([AndrienkoAleksandr](https://github.com/AndrienkoAleksandr)) +- Fixed typo in README.md [\#7](https://github.com/eclipse/che/pull/7) ([spoenemann](https://github.com/spoenemann)) +- IDEX-1038: removed unusable properties [\#6](https://github.com/eclipse/che/pull/6) ([svor](https://github.com/svor)) +- IDEX-2457: added the browser dialog box with error message [\#5](https://github.com/eclipse/che/pull/5) ([svor](https://github.com/svor)) +- Update README.md [\#3](https://github.com/eclipse/che/pull/3) ([jamesrcounts](https://github.com/jamesrcounts)) +- Update DTD for GWT-module descriptors [\#1](https://github.com/eclipse/che/pull/1) ([azatsarynnyy](https://github.com/azatsarynnyy)) From 70c3f663739f3827ff3ac0395a12c5913bcbe438 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskii Date: Tue, 6 Dec 2016 16:18:46 +0200 Subject: [PATCH 61/74] Remove redundant info log call --- .../org/eclipse/che/ide/statepersistance/AppStateManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/AppStateManager.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/AppStateManager.java index ced40ea5878..4c102e0d5cf 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/AppStateManager.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/statepersistance/AppStateManager.java @@ -112,7 +112,6 @@ public Promise persistWorkspaceState(String wsId) { private Promise writeStateToPreferences(JsonObject state) { final String json = state.toJson(); - Log.info(getClass(), "write: " + json); preferencesManager.setValue(PREFERENCE_PROPERTY_NAME, json); return preferencesManager.flushPreferences().catchError(new Operation() { @Override From fd519f7e2eabc181e309368c871e76fd39519533 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskyi Date: Wed, 7 Dec 2016 17:13:42 +0200 Subject: [PATCH 62/74] Add ability to reveal resource via native js api call (#3263) --- .../explorer/project/ProjectExplorerPresenter.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 696072011cf..53ac311303a 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 @@ -45,6 +45,7 @@ import org.eclipse.che.ide.project.node.SyntheticNode; import org.eclipse.che.ide.project.node.SyntheticNodeUpdateEvent; import org.eclipse.che.ide.resource.Path; +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; @@ -79,6 +80,7 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel MarkerChangedHandler, SyntheticNodeUpdateEvent.SyntheticNodeUpdateHandler { private final ProjectExplorerView view; + private final EventBus eventBus; private final ResourceNode.NodeFactory nodeFactory; private final SettingsProvider settingsProvider; private final CoreLocalizationConstant locale; @@ -102,6 +104,7 @@ public ProjectExplorerPresenter(final ProjectExplorerView view, final AppContext appContext, final WorkspaceAgent workspaceAgent) { this.view = view; + this.eventBus = eventBus; this.nodeFactory = nodeFactory; this.settingsProvider = settingsProvider; this.locale = locale; @@ -181,6 +184,10 @@ private native void registerNative() /*-{ that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doCollapse()(); }) + ProjectExplorer.reveal = $entry(function (path) { + that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doReveal(*)(path); + }) + $wnd.IDE.ProjectExplorer = ProjectExplorer; }-*/; @@ -196,6 +203,10 @@ private void doCollapse() { } } + private void doReveal(String path) { + eventBus.fireEvent(new RevealResourceEvent(Path.valueOf(path))); + } + @Override @SuppressWarnings("unchecked") public void onResourceChanged(ResourceChangedEvent event) { From 6dd0c1245e86668ec8008fecae0871def0412133 Mon Sep 17 00:00:00 2001 From: Mykola Morhun Date: Wed, 7 Dec 2016 17:15:18 +0200 Subject: [PATCH 63/74] CODENVY-1106: Add ability to prevent window closing in IDE. Handle closing of preferences window correctly. (#3203) CODENVY-1106: Add ability to prevent window closing in IDE. Handle closing of preferences window correctly. --- .../che/ide/preferences/PreferencesPresenter.java | 14 ++++++++++++-- .../che/ide/preferences/PreferencesView.java | 7 ++++++- .../che/ide/preferences/PreferencesViewImpl.java | 2 +- .../ide/resources/selector/SelectPathViewImpl.java | 1 + .../che/ide/upload/file/UploadFileViewImpl.java | 1 + .../upload/folder/UploadFolderFromZipViewImpl.java | 1 + .../ui/dialogs/message/MessageDialogViewImpl.java | 5 ----- .../java/org/eclipse/che/ide/ui/window/Window.java | 4 +--- .../EditDebugConfigurationsViewImpl.java | 1 + .../ide/ext/git/client/add/AddToIndexViewImpl.java | 4 ---- .../revisionsList/RevisionListViewImpl.java | 2 +- .../ide/ext/git/client/fetch/FetchViewImpl.java | 4 ---- .../ext/git/client/push/PushToRemoteViewImpl.java | 4 ---- .../ide/ext/git/client/remote/RemoteViewImpl.java | 1 + .../git/client/remove/RemoveFromIndexViewImpl.java | 4 ---- .../git/client/reset/files/ResetFilesViewImpl.java | 4 ---- .../newsourcefile/NewJavaSourceFileViewImpl.java | 4 ---- .../classpath/ProjectClasspathViewImpl.java | 1 + .../common/threechoices/ChoiceDialogViewImpl.java | 4 ---- .../che/plugin/svn/ide/log/ShowLogsViewImpl.java | 4 ---- .../plugin/svn/ide/resolve/ResolveViewImpl.java | 1 + .../che/plugin/svn/ide/sw/SwitchViewImpl.java | 3 --- .../svn/ide/update/UpdateToRevisionViewImpl.java | 3 --- .../sample/wizard/ide/file/NewXFileViewImpl.java | 4 ---- 24 files changed, 28 insertions(+), 55 deletions(-) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesPresenter.java index c5c823a9210..fc5574170d2 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesPresenter.java @@ -207,14 +207,16 @@ public void onCloseClicked() { for (PreferencePagePresenter preference : preferences) { if (preference.isDirty()) { haveUnsavedData = true; + break; } } if (haveUnsavedData) { - dialogFactory.createConfirmDialog("", locale.messagesPromptSaveChanges(), getConfirmCallback(), getCancelCallback()).show(); + dialogFactory.createConfirmDialog("", locale.messagesPromptSaveChanges(), + locale.yesButtonTitle(), locale.noButtonTitle(), + getConfirmCallback(), getCancelCallback()).show(); } else { view.close(); } - view.enableSaveButton(false); } private ConfirmCallback getConfirmCallback() { @@ -226,6 +228,7 @@ public void accepted() { preference.storeChanges(); } } + view.enableSaveButton(false); view.close(); } }; @@ -244,4 +247,11 @@ public void cancelled() { } }; } + + /** {@inheritDoc} */ + @Override + public void onCloseWindow() { + onCloseClicked(); + } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesView.java index e8d80b958cf..33eeb18120f 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesView.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesView.java @@ -25,7 +25,7 @@ */ public interface PreferencesView extends View { /** Needs for delegate some function into preferences view. */ - public interface ActionDelegate { + interface ActionDelegate { /** * Performs actions when user click Save button. * Actually when button is pressed, preferences must be stored on the server. @@ -51,6 +51,11 @@ public interface ActionDelegate { */ void onPreferenceSelected(PreferencePagePresenter preference); + /** + * Performs any actions on the preferences window closing. + */ + void onCloseWindow(); + } /** diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesViewImpl.java index 6dd25c19261..a1526400f02 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/PreferencesViewImpl.java @@ -189,9 +189,9 @@ public void setPreferences(Map> preferences list.render(categoriesList, true); } - /** {@inheritDoc} */ @Override protected void onClose() { + delegate.onCloseWindow(); } /** {@inheritDoc} */ diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/selector/SelectPathViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/selector/SelectPathViewImpl.java index 4f6ca210938..ad860e7436b 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/selector/SelectPathViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/selector/SelectPathViewImpl.java @@ -208,6 +208,7 @@ public void show() { @Override protected void onClose() { delegate.onCancel(); + super.onClose(); } public interface Styles extends ClientBundle { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFileViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFileViewImpl.java index e68bf56e34c..0a897193a72 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFileViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFileViewImpl.java @@ -168,6 +168,7 @@ public boolean isOverwriteFileSelected() { @Override protected void onClose() { uploadPanel.remove(file); + super.onClose(); } private void addFile() { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/folder/UploadFolderFromZipViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/folder/UploadFolderFromZipViewImpl.java index 6adbf486417..9700cc3e6a7 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/folder/UploadFolderFromZipViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/folder/UploadFolderFromZipViewImpl.java @@ -185,6 +185,7 @@ public boolean isOverwriteFileSelected() { @Override protected void onClose() { uploadPanel.remove(file); + super.onClose(); } private void addFileUploadForm() { diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.java index 8c7aba082a0..330943de4ed 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.java @@ -54,11 +54,6 @@ public void setDelegate(@NotNull ActionDelegate delegate) { this.footer.setDelegate(this.delegate); } - /** {@inheritDoc} */ - @Override - protected void onClose() { - } - /** {@inheritDoc} */ @Override public void showDialog() { diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/window/Window.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/window/Window.java index f62496600d7..418a7f66503 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/window/Window.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/window/Window.java @@ -260,7 +260,6 @@ private void handleViewEvents() { @Override public void onEscapeKey() { if (hideOnEscapeEnabled && !blocked) { - hide(); Window.this.onClose(); } } @@ -268,7 +267,6 @@ public void onEscapeKey() { @Override public void onClose() { if (!blocked) { - hide(); Window.this.onClose(); } } @@ -282,9 +280,9 @@ public void onEnterKey() { /** * Is called when user closes the Window. - * The method was marked as deprecated until an empty implementation is added. */ protected void onClose() { + hide(); } @Override diff --git a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/configuration/EditDebugConfigurationsViewImpl.java b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/configuration/EditDebugConfigurationsViewImpl.java index b24843fe286..fcda7d2f589 100644 --- a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/configuration/EditDebugConfigurationsViewImpl.java +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/configuration/EditDebugConfigurationsViewImpl.java @@ -487,6 +487,7 @@ protected void onEnterClicked() { @Override protected void onClose() { + super.onClose(); setSelectedConfiguration(selectedConfiguration); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexViewImpl.java index 71b6fd68e3c..51cdc61a27c 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/add/AddToIndexViewImpl.java @@ -149,8 +149,4 @@ public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } - /** {@inheritDoc} */ - @Override - protected void onClose() { - } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionsList/RevisionListViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionsList/RevisionListViewImpl.java index f667da6602b..a5af7256e32 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionsList/RevisionListViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/revisionsList/RevisionListViewImpl.java @@ -121,13 +121,13 @@ public void setDescription(String description) { /** {@inheritDoc} */ @Override public void close() { - this.hide(); onClose(); } @Override protected void onClose() { selectionModel.clear(); + super.onClose(); } /** {@inheritDoc} */ diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchViewImpl.java index e7e8d24e25a..2f0c9a4598e 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchViewImpl.java @@ -276,8 +276,4 @@ public void selectRemoteBranch(String branch) { } } - /** {@inheritDoc} */ - @Override - protected void onClose() { - } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemoteViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemoteViewImpl.java index 5fd95303f65..ee02a26f431 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemoteViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemoteViewImpl.java @@ -228,8 +228,4 @@ public void selectRemoteBranch(@NotNull String branch) { } } - /** {@inheritDoc} */ - @Override - protected void onClose() { - } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemoteViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemoteViewImpl.java index 1e97ce34395..81688a55d84 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemoteViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remote/RemoteViewImpl.java @@ -231,5 +231,6 @@ public void setDelegate(ActionDelegate delegate) { @Override protected void onClose() { this.isShown = false; + super.onClose(); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexViewImpl.java index 77b44a1eca5..560a1b86439 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/remove/RemoveFromIndexViewImpl.java @@ -135,8 +135,4 @@ public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } - /** {@inheritDoc} */ - @Override - protected void onClose() { - } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesViewImpl.java index aea82b5970b..8397a555734 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/reset/files/ResetFilesViewImpl.java @@ -179,8 +179,4 @@ public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } - /** {@inheritDoc} */ - @Override - protected void onClose() { - } } diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFileViewImpl.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFileViewImpl.java index 07d02ade6d3..d20c7019065 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFileViewImpl.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFileViewImpl.java @@ -139,10 +139,6 @@ public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } - @Override - protected void onClose() { - } - interface AddToIndexViewImplUiBinder extends UiBinder { } } diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/project/classpath/ProjectClasspathViewImpl.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/project/classpath/ProjectClasspathViewImpl.java index b66d2f330da..85e89ec6ecc 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/project/classpath/ProjectClasspathViewImpl.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/project/classpath/ProjectClasspathViewImpl.java @@ -139,6 +139,7 @@ protected void onEnterClicked() { @Override protected void onClose() { delegate.onCloseClicked(); + super.onClose(); } @Override diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/common/threechoices/ChoiceDialogViewImpl.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/common/threechoices/ChoiceDialogViewImpl.java index a6d9d62974a..27e1cbbfcc6 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/common/threechoices/ChoiceDialogViewImpl.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/common/threechoices/ChoiceDialogViewImpl.java @@ -54,10 +54,6 @@ public void setDelegate(final ActionDelegate delegate) { this.footer.setDelegate(this.delegate); } - @Override - protected void onClose() { - } - @Override public void showDialog() { this.show(); diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/log/ShowLogsViewImpl.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/log/ShowLogsViewImpl.java index deeade2ac9d..5f7030b601d 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/log/ShowLogsViewImpl.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/log/ShowLogsViewImpl.java @@ -98,8 +98,4 @@ public HasValue rangeField() { return revisionField; } - @Override - protected void onClose() { - } - } diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/resolve/ResolveViewImpl.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/resolve/ResolveViewImpl.java index 7267fe18d11..2ceaa2f3e6b 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/resolve/ResolveViewImpl.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/resolve/ResolveViewImpl.java @@ -136,5 +136,6 @@ public void showDialog() { @Override protected void onClose() { mainPanel.getElement().removeAllChildren(); + super.onClose(); } } diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/sw/SwitchViewImpl.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/sw/SwitchViewImpl.java index e24effdfc03..dd736633821 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/sw/SwitchViewImpl.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/sw/SwitchViewImpl.java @@ -274,9 +274,6 @@ public void setWorkingCopyDepthEnabled(boolean enabled) { workingCopyDepth.setEnabled(enabled); } - @Override - protected void onClose() { } - @UiHandler("switchToBranch") public void onSwitchToBranchClicked(final ClickEvent event) { delegate.onSwitchToBranchChanged(); diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/update/UpdateToRevisionViewImpl.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/update/UpdateToRevisionViewImpl.java index 5da9b1e58bf..d339c8b759b 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/update/UpdateToRevisionViewImpl.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/update/UpdateToRevisionViewImpl.java @@ -208,7 +208,4 @@ public void onRevisionChanged(final KeyUpEvent event) { delegate.onRevisionChanged(); } - @Override - protected void onClose() { } - } diff --git a/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/src/main/java/org/eclipse/che/plugin/sample/wizard/ide/file/NewXFileViewImpl.java b/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/src/main/java/org/eclipse/che/plugin/sample/wizard/ide/file/NewXFileViewImpl.java index 7781ca01854..eeb1c418fda 100644 --- a/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/src/main/java/org/eclipse/che/plugin/sample/wizard/ide/file/NewXFileViewImpl.java +++ b/samples/sample-plugin-wizard/che-sample-plugin-wizard-ide/src/main/java/org/eclipse/che/plugin/sample/wizard/ide/file/NewXFileViewImpl.java @@ -93,10 +93,6 @@ public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } - @Override - protected void onClose() { - } - interface NewJavaSourceFileViewImplUiBinder extends UiBinder { } } From 2bc205d51d7c80cd071cc7b2b63cec9c7184b98f Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskyi Date: Wed, 7 Dec 2016 17:23:49 +0200 Subject: [PATCH 64/74] Improve message about unreachable workspace (#3156) --- .../eclipse/che/ide/api/machine/WsAgentStateController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java index ca1da3b1500..8f6f9f79d8d 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/WsAgentStateController.java @@ -207,12 +207,12 @@ private void checkStateOfWsAgent(WsAgentHealthStateDto agentHealthStateDto) { if (statusCode == 200) { dialogFactory.createMessageDialog(infoWindowTitle, - "Our workspace agent is no longer responding. To fix the problem, verify you have a" + + "Workspace agent is no longer responding. To fix the problem, verify you have a" + " good network connection and restart the workspace.", stopCallback).show(); } else { dialogFactory.createMessageDialog(infoWindowTitle, - "Our workspace agent is no longer responding. To fix the problem, restart the workspace.", + "Workspace agent is no longer responding. To fix the problem, restart the workspace.", stopCallback).show(); } } From 42272e4bd95c5b9b3c4fc20df5ef60685cac189f Mon Sep 17 00:00:00 2001 From: Alexander Garagatyi Date: Wed, 7 Dec 2016 17:39:59 +0200 Subject: [PATCH 65/74] CHE-3199: add cpu limits configuration (#3278) Signed-off-by: Alexander Garagatyi --- .../WEB-INF/classes/codenvy/che.properties | 25 ++- dockerfiles/init/manifests/che.env | 125 +++++++---- .../docker/client/json/ContainerConfig.java | 24 ++ .../plugin/docker/client/json/HostConfig.java | 30 +++ .../client/params/BuildImageParams.java | 80 ++++++- .../client/params/BuildImageParamsTest.java | 212 +++++------------- .../machine/DockerInstanceRuntimeInfo.java | 2 - .../docker/machine/MachineProviderImpl.java | 40 +++- .../machine/MachineProviderImplTest.java | 109 ++++++++- 9 files changed, 424 insertions(+), 223 deletions(-) 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 a1ec63e456d..a181d8b08ce 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 @@ -133,6 +133,30 @@ che.docker.privilege=false # Limits the number of processes that can be forked inside a cgroup. Set -1 for unlimited. # Since 4.3 kernel. che.docker.pids_limit=-1 + +# Sets parent cgroup for cgroups of containers created by workspaces. +# This allows an admin to set custom cgroup limitations to all containers of workspaces by configuring cgroups. +# Example: +# /my_group +# my_another_group +che.docker.parent_cgroup=NULL + +# Sets set of CPUs that can be used by each container of started workspace. +# Example: +# 0-3 +# 1,4 +che.docker.cpuset_cpus=NULL + +# Next 2 properties set limits on CPU consumption by containers of started workspaces. +# Period sets amount of units per CPU core. +# Quota sets amount of units available for container per whole CPU. +# Max value of quota could be period * number of CPU cores in a system. +# Example: +# che.docker.cpu_period=5000 +# che.docker.cpu_quota=10000 +che.docker.cpu_period=0 +che.docker.cpu_quota=0 + # Adds options when mounting the /projects volume. che.docker.volumes_projects_options=Z @@ -184,7 +208,6 @@ che.docker.tcp_connection_read_timeout_ms=600000 # to determine swap size. To disable swap set to 0. che.docker.swap=-1 - ### INTERNAL # Remove locations where internal message bus events should be propagated to. # For debugging - set to retrieve internal events from external clients. diff --git a/dockerfiles/init/manifests/che.env b/dockerfiles/init/manifests/che.env index bf497fa6f55..2ed14111d30 100644 --- a/dockerfiles/init/manifests/che.env +++ b/dockerfiles/init/manifests/che.env @@ -6,7 +6,7 @@ # Parameters that affect the initial system operation. # -# IP address, hostname, or DNS +# IP address, hostname, or DNS # The IP address or DNS name of where the Che endpoint will service your users. # If you are running this on a local system, we auto-detect this value as the IP # address of your Docker daemon. On many systems, especially those from cloud hosters @@ -15,14 +15,14 @@ #CHE_HOST=localhost # Proxies -# Che's internal system services such as its internal JVMs need to -# have system level properties applied so that they can reach the Internet. Che's -# system uses the Internet to communicate with DockerHub for downloading images that +# Che's internal system services such as its internal JVMs need to +# have system level properties applied so that they can reach the Internet. Che's +# system uses the Internet to communicate with DockerHub for downloading images that # are used to run Che's systems. Note that you must configure proxy access in three -# locations. First, you enabled your system Docker daemon to use proxies. Second, you -# configure proxies for Che's internal system services. Third, if you want your users +# locations. First, you enabled your system Docker daemon to use proxies. Second, you +# configure proxies for Che's internal system services. Third, if you want your users # to access the Internet, then you should also add proxy values for their workspaces. -# +# # Please be mindful of the proxy URL formatting. Proxies are unforgiving if you do not # type the URL properly, including the protocol and whether they allow a trailing /. #CHE_HTTP_PROXY_FOR_CHE=http://myproxy.com:8001/ @@ -44,8 +44,8 @@ # XMX -# Che's core server runs as a Tomcat application on top of a JVM. This sets the -# JVM XMX settings that are loaded by the JVM when the Che container boots. +# Che's core server runs as a Tomcat application on top of a JVM. This sets the +# JVM XMX settings that are loaded by the JVM when the Che container boots. # It should be rare that you would need to change this. #CHE_SERVER_XMX=2048 @@ -56,22 +56,22 @@ # # User workspaces have their own runtimes. Those runtimes are composed of 1..n containers. # We call each container a 'machine' as it is a dedicated runtime. One of the machines for -# a workspace must be designated as the 'development' machine, which installs Che agents to +# a workspace must be designated as the 'development' machine, which installs Che agents to # provide additional services to the user. These parameters configure how Che manages user -# machines and the agents that are deployed within them. +# machines and the agents that are deployed within them. # # Since workspaces have their own runtimes, they have separate proxies that do not inherit # from system proxies that you have configured for your Docker daemon. # # /etc/hosts # This will add entries into the user's /etc/hosts file that is running within their -# workspace. You may need to configure this to give user's access to systems within +# workspace. You may need to configure this to give user's access to systems within # your network or access to the Internet. #CHE_MACHINE_EXTRA_HOSTS=NULL # Idle Timeout # The system will suspend the workspace and snapshot it if the end user is idle for -# this length of time. Idleness is determined by the length of time that a user has +# this length of time. Idleness is determined by the length of time that a user has # not interacted with the workspace, meaning that one of our agents has not received # instructions. Leaving a browser window open counts as idleness time. #CHE_MACHINE_WS_AGENT_INACTIVE_STOP_TIMEOUT_MS=600000 @@ -81,10 +81,10 @@ #CHE_MACHINE_DEFAULT_MEM_SIZE_MB=1024 # Memory Swap -# Adjust machine swap memory by multiplication current machnine memory on provided -# value. Default is 0 which means disabled swap, if set multiplier value equal to 0.5 -# machine swap will be configured with size that equal to half of current machine memory. -# It should be rare that you would configure this. See Docker memory swap online +# Adjust machine swap memory by multiplication current machnine memory on provided +# value. Default is 0 which means disabled swap, if set multiplier value equal to 0.5 +# machine swap will be configured with size that equal to half of current machine memory. +# It should be rare that you would configure this. See Docker memory swap online # for background. #CHE_MACHINE_DOCKER_MEMORY_SWAP_MULTIPLIER=0 @@ -96,16 +96,16 @@ # Privilged Mode # Set to `true` if you would like user workspaces to be started with Docker's -# privileged mode. Please be careful when setting this property. This allows -# user workspaces to gain access to the underly host with root privileges. +# privileged mode. Please be careful when setting this property. This allows +# user workspaces to gain access to the underly host with root privileges. # However, privileged mode is needed if users want to launch their own Docker # containers from within their Docker-powered workspace. #CHE_DOCKER_PRIVILEGE__MODE=false # Agent Start Timeout # The length of time that a workspace will be allowed to boot before the system terminates the -# boot process. If the Che container cannot establish two way communications with the -# agents within the workspace when it boots, then the workspace will not be started. +# boot process. If the Che container cannot establish two way communications with the +# agents within the workspace when it boots, then the workspace will not be started. #CHE_MACHINE_WS_AGENT_MAX_START_TIME_MS=300000 @@ -119,7 +119,7 @@ # workspaces establish connections to one another, and also how remote browser clients # should discover and connect to workspaces. # -# Che goes through a progression algorithm to establish the protocol, IP address and +# Che goes through a progression algorithm to establish the protocol, IP address and # port to establish communications with it is booting or starting a workspace. # # Browser --> Che Server @@ -140,7 +140,7 @@ # Workspace Agent --> Che Server # 1. Default is http://che-host:${SERVER_PORT}/wsmaster/api, where che-host is IP of server. # 2. Else, use value of che.workspace.che_server_endpoint -# 3. Else, if 'docker0' interface is unreachable, then che-host replaced with +# 3. Else, if 'docker0' interface is unreachable, then che-host replaced with # 172.17.42.1 or 192.168.99.1 # 4. Else, print connection exception @@ -151,10 +151,10 @@ ##### ##### # # IP Address -# The IP address of the Docker daemon that is running on your host. We do a -# self-discovery to auto-set this. You can combine this with DOCKER_HOST to change -# communications from socket to TCP. This value will be set to DOCKER_MACHINE_HOST -# env variable for the Che Docker container when it boots - it's how we determine +# The IP address of the Docker daemon that is running on your host. We do a +# self-discovery to auto-set this. You can combine this with DOCKER_HOST to change +# communications from socket to TCP. This value will be set to DOCKER_MACHINE_HOST +# env variable for the Che Docker container when it boots - it's how we determine # what containers will boot. #CHE_DOCKER_IP=172.17.0.1 @@ -170,15 +170,15 @@ # Docker Registry # Docker is the default machine implementation within Che. Workspaces are powered -# by machines that are constructed when the workspace is started. The images used to +# by machines that are constructed when the workspace is started. The images used to # generate containers for the machines can come from DockerHub or a private # Docker registry. -# +# # You can have an internal registry configured for Che to store images: #CHE_DOCKER_REGISTRY=${CHE_REGISTRY_HOST}:5000 -# +# # You can configure 1..n private registries for Che to connect to when searching -# for Docker images to be used for your workspaces. +# for Docker images to be used for your workspaces. #CHE_DOCKER_REGISTRY_AUTH__URL=https://index.docker.io/v1/ #CHE_DOCKER_REGISTRY_AUTH__USERNAME= #CHE_DOCKER_REGISTRY_AUTH__URL=https://index.docker.io/v1/ @@ -191,15 +191,58 @@ # Force Image Update # If true, then Che always pulls an image from a registry even if it is cached -# If false, Docker only pulls the image if it does not exist locally. This can +# If false, Docker only pulls the image if it does not exist locally. This can # create situations where images are not current, but a forced pull is slower. #CHE_DOCKER_ALWAYS__PULL__IMAGE=true # Control User Processes -# Limits the number of processes that can be forked inside a cgroup. Set -1 for +# Limits the number of processes that can be forked inside a cgroup. Set -1 for # unlimited. Requires Docker running on a 4.3 Linux kernel. #CHE_DOCKER_PIDS__LIMIT=-1 +# CPU Core Limits +# Limit the CPU cores used for running Che workspaces as containers. +# Example: +# CHE_DOCKER_CPUSET__CPUS=0-3 +# CHE_DOCKER_CPUSET__CPUS=0,2 +# See more at https://docs.docker.com/engine/reference/run/#/cpuset-constraint +#CHE_DOCKER_CPUSET__CPUS=NULL + +# CPU Consumption Limit +# Limit the CPU utilitization given to containers powering workspaces started +# by Che. 'period' sets the amount of units for each CPU core. 'quota' sets the +# sets amount of units available per whole CPU. +# Max value of quota could be period * number of CPU cores in a system. +# Example: +# These values allows usage of 100% of 2 cores on 2+ cores system. +# Period declares that 100% is equal to 5000 units +# and container is allowed to use 2x more than 1 core. +# Although max consumption is explained in cores performance workload will be +# split between several cores. +# CHE_DOCKER_CPU__PERIOD=5000 +# CHE_DOCKER_CPU__QUOTA=10000 +# In this example limit is set to half of a CPU core. +# CHE_DOCKER_CPU__PERIOD=10000 +# CHE_DOCKER_CPU__QUOTA=5000 +# See more at https://docs.docker.com/engine/reference/run/#/cpu-period-constraint +# https://docs.docker.com/engine/reference/run/#/cpu-quota-constraint +#CHE_DOCKER_CPU__PERIOD=0 +#CHE_DOCKER_CPU__QUOTA=0 + +# CGroup Parent +# CGroups allow admins to to configure limits on nodes in a system in a specific +# way. The value can start with a slash which means it will be absolute or +# without a slash for relative value. Docker will create this cgroup if it is missing. +# Admin can configure limits on this cgroup on all nodes in a system specific way. +# Example: +# On Ubuntu 16.04 use CHE_DOCKER_PARENT__CGROUP=/my_group. Then let container +# create cgoup by running Che. Then edit +# /sys/fs/cgroup//my_group/ +# For example to limit CPU cores to 0-1 put value "0-1" into file +# /sys/fs/cgroup/cpuset/my_group/cpuset.cpus +# See more at https://docs.docker.com/engine/reference/run/#/specifying-custom-cgroups +#CHE_DOCKER_PARENT__CGROUP=NULL + # SELinux Options # By default, your source code is mounted into a workspace into /projects folder. # On SELinux and other OS, you may need to add additional mounting attributes. @@ -224,7 +267,7 @@ ##### OAUTH ##### ##### ##### # -# You can configure a 3rd party provider's oAuth, which will be used for your users when +# You can configure a 3rd party provider's oAuth, which will be used for your users when # they initiate Git actions from within Che. # # GitHub @@ -240,9 +283,9 @@ ##### ##### ##### JMX ##### ##### ##### -# -# JMX provides a management interface point to within the Che container. JMX is not -# use by other containers such as haproxy or nginx. While Che is running, grab the +# +# JMX provides a management interface point to within the Che container. JMX is not +# use by other containers such as haproxy or nginx. While Che is running, grab the # IP address of the Che container and you can connect to its embedded JMX server. # #CHE_JMX_USERNAME=admin @@ -256,9 +299,9 @@ # Custom che.properties Property # Che's server loads name=value properties in a .properties file. Those values can # be seen by custom extensions that are packaged within a Che server. There are -# also Che properties that are rarely configured that are shown in documentation +# also Che properties that are rarely configured that are shown in documentation # that can be added with a custom format here. You can add as many as you would like. -# +# # Add a new property in the format of CHE_=value. If in your # you have a single underscore '_', that will be replaced with a # dot '.'. A double underscore '__' will be replaced with a single underscore '_'. @@ -268,5 +311,5 @@ #CHE_WORKSPACE_AUTO__SNAPSHOT=false # A complete list of internal properties used by Che are available in the default -# properties file that is embedded in the server's runtime. You can view it in our -# GitHub repository: https://github.com/eclipse/che/blob/master/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties \ No newline at end of file +# properties file that is embedded in the server's runtime. You can view it in our +# GitHub repository: https://github.com/eclipse/che/blob/master/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/ContainerConfig.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/ContainerConfig.java index 732d789d6ab..2a93628e3af 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/ContainerConfig.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/ContainerConfig.java @@ -71,10 +71,18 @@ public void setEnv(String[] env) { this.env = env; } + /** + * @deprecated Use {@link HostConfig#getCpuShares()} + */ + @Deprecated public int getCpuShares() { return cpuShares; } + /** + * @deprecated Use {@link HostConfig#setCpuShares(int)} + */ + @Deprecated public void setCpuShares(int cpuShares) { this.cpuShares = cpuShares; } @@ -182,6 +190,10 @@ public ContainerConfig withEnv(String... env) { return this; } + /** + * @deprecated Use {@link HostConfig#withCpuShares(int)} + */ + @Deprecated public ContainerConfig withCpuShares(int cpuShares) { this.cpuShares = cpuShares; return this; @@ -268,14 +280,26 @@ public ContainerConfig withDomainName(String domainName) { return this; } + /** + * @deprecated Use {@link HostConfig#getCpusetCpus()} + */ + @Deprecated public String getCpuset() { return cpuset; } + /** + * @deprecated Use {@link HostConfig#setCpusetCpus(String)} + */ + @Deprecated public void setCpuset(String cpuset) { this.cpuset = cpuset; } + /** + * @deprecated Use {@link HostConfig#withCpusetCpus(String)} + */ + @Deprecated public ContainerConfig withCpuset(String cpuset) { this.cpuset = cpuset; return this; diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/HostConfig.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/HostConfig.java index 7d45ebbd2c5..f04119d9b0d 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/HostConfig.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/json/HostConfig.java @@ -41,6 +41,8 @@ public class HostConfig { private String pidMode; private boolean readonlyRootfs; private Ulimit[] ulimits; + private Long cpuQuota; + private Long cpuPeriod; private Map portBindings = new HashMap<>(); private int memorySwappiness = -1; @@ -371,6 +373,32 @@ public HostConfig withCpusetCpus(String cpusetCpus) { return this; } + public Long getCpuQuota() { + return cpuQuota; + } + + public void setCpuQuota(Long cpuQuota) { + this.cpuQuota = cpuQuota; + } + + public HostConfig withCpuQuota(Long cpuQuota) { + this.cpuQuota = cpuQuota; + return this; + } + + public Long getCpuPeriod() { + return cpuPeriod; + } + + public void setCpuPeriod(Long cpuPeriod) { + this.cpuPeriod = cpuPeriod; + } + + public HostConfig withCpuPeriod(Long cpuPeriod) { + this.cpuPeriod = cpuPeriod; + return this; + } + public String getPidMode() { return pidMode; } @@ -441,6 +469,8 @@ public String toString() { ", ulimits=" + Arrays.toString(ulimits) + ", portBindings=" + portBindings + ", memorySwappiness=" + memorySwappiness + + ", cpuPeriod='" + cpuPeriod + '\'' + + ", cpuQuota='" + cpuQuota + '\'' + '}'; } } diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/params/BuildImageParams.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/params/BuildImageParams.java index 27444db119f..d8b3f05668f 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/params/BuildImageParams.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/params/BuildImageParams.java @@ -46,6 +46,9 @@ public class BuildImageParams { private Boolean removeIntermediateContainer; private Boolean forceRemoveIntermediateContainers; private Map buildArgs; + private String cpusetCpus; + private Long cpuPeriod; + private Long cpuQuota; /** * Creates arguments holder with required parameters. @@ -315,6 +318,42 @@ public BuildImageParams withDockerfile(String dockerfilePath) { return this; } + /** + * Sets CPU cores config that is allowed to use for image build. + * + * @param cpusetCpus + * CPU cores config + * @return this params instance + */ + public BuildImageParams withCpusetCpus(String cpusetCpus) { + this.cpusetCpus = cpusetCpus; + return this; + } + + /** + * Sets length of a CPU period for CPU consumption limiting in microseconds. + * + * @param cpuPeriod + * length of a CPU period + * @return this params instance + */ + public BuildImageParams withCpuPeriod(Long cpuPeriod) { + this.cpuPeriod = cpuPeriod; + return this; + } + + /** + * Sets amount of CPU time that build container can get in a CPU period. + * + * @param cpuQuota + * amount of CPU time in microseconds + * @return this params instance + */ + public BuildImageParams withCpuQuota(Long cpuQuota) { + this.cpuQuota = cpuQuota; + return this; + } + public String getRepository() { return repository; } @@ -371,6 +410,18 @@ public Map getBuildArgs() { return buildArgs; } + public String getCpusetCpus() { + return cpusetCpus; + } + + public Long getCpuPeriod() { + return cpuPeriod; + } + + public Long getCpuQuota() { + return cpuQuota; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -389,6 +440,9 @@ public boolean equals(Object o) { Objects.equals(noCache, that.noCache) && Objects.equals(removeIntermediateContainer, that.removeIntermediateContainer) && Objects.equals(forceRemoveIntermediateContainers, that.forceRemoveIntermediateContainers) && + Objects.equals(cpusetCpus, that.cpusetCpus) && + Objects.equals(cpuPeriod, that.cpuPeriod) && + Objects.equals(cpuQuota, that.cpuQuota) && Objects.equals(buildArgs, that.buildArgs); } @@ -407,6 +461,9 @@ public int hashCode() { noCache, removeIntermediateContainer, forceRemoveIntermediateContainers, + cpusetCpus, + cpuPeriod, + cpuQuota, buildArgs); } @@ -415,18 +472,21 @@ public String toString() { return "BuildImageParams{" + "repository='" + repository + '\'' + ", tag='" + tag + '\'' + - ", authConfigs=" + authConfigs + - ", doForcePull=" + doForcePull + - ", memoryLimit=" + memoryLimit + - ", memorySwapLimit=" + memorySwapLimit + - ", files=" + files + + ", authConfigs='" + authConfigs + '\'' + + ", doForcePull='" + doForcePull + '\'' + + ", memoryLimit='" + memoryLimit + '\'' + + ", memorySwapLimit='" + memorySwapLimit + '\'' + + ", files=" + files + '\'' + ", dockerfile='" + dockerfile + '\'' + ", remote='" + remote + '\'' + - ", quiet=" + quiet + - ", noCache=" + noCache + - ", removeIntermediateContainer=" + removeIntermediateContainer + - ", forceRemoveIntermediateContainers=" + forceRemoveIntermediateContainers + - ", buildArgs=" + buildArgs + + ", quiet='" + quiet + '\'' + + ", noCache='" + noCache + '\'' + + ", removeIntermediateContainer='" + removeIntermediateContainer + '\'' + + ", forceRemoveIntermediateContainers='" + forceRemoveIntermediateContainers + '\'' + + ", cpusetCpus='" + cpusetCpus + '\'' + + ", cpuPeriod='" + cpuPeriod + '\'' + + ", cpuQuota='" + cpuQuota + '\'' + + ", buildArgs='" + buildArgs + '\'' + '}'; } diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/params/BuildImageParamsTest.java b/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/params/BuildImageParamsTest.java index f2a54c09320..492cab27030 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/params/BuildImageParamsTest.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/params/BuildImageParamsTest.java @@ -11,7 +11,6 @@ package org.eclipse.che.plugin.docker.client.params; import org.eclipse.che.plugin.docker.client.dto.AuthConfigs; - import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -28,24 +27,28 @@ /** * @author Mykola Morhun + * @author Alexander Garagatyi */ public class BuildImageParamsTest { - private static final String REPOSITORY = "repository"; - private static final String TAG = "tag"; - private static final AuthConfigs AUTH_CONFIGS = mock(AuthConfigs.class); - private static final Boolean DO_FORCE_PULL = true; - private static final Long MEMORY_LIMIT = 12345L; - private static final Long MEMORY_SWAP_LIMIT = 67890L; - private static final File FILE = new File("."); - private static final List FILES; - private static final String DOCKERFILE = "/tmp/Dockerfile"; - private static final String REMOTE = "https://github.com/someuser/remote.git"; - private static final Boolean QUIET = false; - private static final Boolean NO_CACHE = false; - private static final Boolean REMOVE_INTERMEDIATE_CONTAINER = true; - private static final Boolean FORCE_REMOVE_INTERMEDIATE_CONTAINERS = true; - private static final Map BUILD_ARGS = new HashMap<>(); + private static final String REPOSITORY = "repository"; + private static final String TAG = "tag"; + private static final AuthConfigs AUTH_CONFIGS = mock(AuthConfigs.class); + private static final Boolean DO_FORCE_PULL = true; + private static final Long MEMORY_LIMIT = 12345L; + private static final Long MEMORY_SWAP_LIMIT = 67890L; + private static final File FILE = new File("."); + private static final String DOCKERFILE = "/tmp/Dockerfile"; + private static final String REMOTE = "https://github.com/someuser/remote.git"; + private static final Boolean QUIET = false; + private static final Boolean NO_CACHE = false; + private static final Boolean REMOVE_INTERMEDIATE_CONTAINER = true; + private static final Boolean FORCE_REMOVE_INTERMEDIATE_CONTAINERS = true; + private static final Map BUILD_ARGS = new HashMap<>(); + private static final String CPUSET_CPUS = "0-3"; + private static final Long CPU_PERIOD = 50000L; + private static final Long CPU_QUOTA = 150000L; + private static final List FILES; static { FILES = new ArrayList<>(); @@ -78,6 +81,9 @@ public void shouldCreateParamsObjectWithRequiredParametersFromFiles() { assertNull(buildImageParams.isRemoveIntermediateContainer()); assertNull(buildImageParams.isForceRemoveIntermediateContainers()); assertNull(buildImageParams.getBuildArgs()); + assertNull(buildImageParams.getCpusetCpus()); + assertNull(buildImageParams.getCpuPeriod()); + assertNull(buildImageParams.getCpuQuota()); } @Test @@ -99,9 +105,11 @@ public void shouldCreateParamsObjectWithRequiredParametersFromRemote() { assertNull(buildImageParams.isRemoveIntermediateContainer()); assertNull(buildImageParams.isForceRemoveIntermediateContainers()); assertNull(buildImageParams.getBuildArgs()); + assertNull(buildImageParams.getCpusetCpus()); + assertNull(buildImageParams.getCpuPeriod()); + assertNull(buildImageParams.getCpuQuota()); } - @Test public void shouldCreateParamsObjectWithAllPossibleParametersFromFiles() { buildImageParams = BuildImageParams.create(FILE) @@ -116,6 +124,9 @@ public void shouldCreateParamsObjectWithAllPossibleParametersFromFiles() { .withNoCache(NO_CACHE) .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) + .withCpusetCpus(CPUSET_CPUS) + .withCpuPeriod(CPU_PERIOD) + .withCpuQuota(CPU_QUOTA) .withBuildArgs(BUILD_ARGS); assertNull(buildImageParams.getRemote()); @@ -133,6 +144,9 @@ public void shouldCreateParamsObjectWithAllPossibleParametersFromFiles() { assertEquals(buildImageParams.isRemoveIntermediateContainer(), REMOVE_INTERMEDIATE_CONTAINER); assertEquals(buildImageParams.isForceRemoveIntermediateContainers(), FORCE_REMOVE_INTERMEDIATE_CONTAINERS); assertEquals(buildImageParams.getBuildArgs(), BUILD_ARGS); + assertEquals(buildImageParams.getCpusetCpus(), CPUSET_CPUS); + assertEquals(buildImageParams.getCpuPeriod(), CPU_PERIOD); + assertEquals(buildImageParams.getCpuQuota(), CPU_QUOTA); } @Test @@ -149,6 +163,9 @@ public void shouldCreateParamsObjectWithAllPossibleParametersFromRemote() { .withNoCache(NO_CACHE) .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) + .withCpusetCpus(CPUSET_CPUS) + .withCpuPeriod(CPU_PERIOD) + .withCpuQuota(CPU_QUOTA) .withBuildArgs(BUILD_ARGS); assertNull(buildImageParams.getFiles()); @@ -166,6 +183,9 @@ public void shouldCreateParamsObjectWithAllPossibleParametersFromRemote() { assertEquals(buildImageParams.isRemoveIntermediateContainer(), REMOVE_INTERMEDIATE_CONTAINER); assertEquals(buildImageParams.isForceRemoveIntermediateContainers(), FORCE_REMOVE_INTERMEDIATE_CONTAINERS); assertEquals(buildImageParams.getBuildArgs(), BUILD_ARGS); + assertEquals(buildImageParams.getCpusetCpus(), CPUSET_CPUS); + assertEquals(buildImageParams.getCpuPeriod(), CPU_PERIOD); + assertEquals(buildImageParams.getCpuQuota(), CPU_QUOTA); } @Test(expectedExceptions = NullPointerException.class) @@ -211,205 +231,63 @@ public void shouldThrowIllegalStateExceptionIfAddFileAfterSetRemote() { @Test public void repositoryParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.getRepository()); } @Test public void tagParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.getTag()); } @Test public void authConfigParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.getAuthConfigs()); } @Test public void doForcePullParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.isDoForcePull()); } @Test public void memoryLimitParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.getMemoryLimit()); } @Test public void memorySwapLimitParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.getMemorySwapLimit()); } @Test public void dockerfileParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); + buildImageParams.withRepository(REPOSITORY); assertNull(buildImageParams.getDockerfile()); } @Test public void quietParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.isQuiet()); } @Test public void noCacheParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.isNoCache()); } @Test public void removeIntermediateContainerParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.isRemoveIntermediateContainer()); } @Test public void forceRemoveIntermediateContainersParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withBuildArgs(BUILD_ARGS); - assertNull(buildImageParams.isForceRemoveIntermediateContainers()); } @Test public void buildArgsParameterShouldEqualsNullIfItNotSet() { - buildImageParams.withRepository(REPOSITORY) - .withTag(TAG) - .withAuthConfigs(AUTH_CONFIGS) - .withDoForcePull(DO_FORCE_PULL) - .withMemoryLimit(MEMORY_LIMIT) - .withMemorySwapLimit(MEMORY_SWAP_LIMIT) - .withDockerfile(DOCKERFILE) - .withQuiet(QUIET) - .withNoCache(NO_CACHE) - .withRemoveIntermediateContainers(REMOVE_INTERMEDIATE_CONTAINER) - .withForceRemoveIntermediateContainers(FORCE_REMOVE_INTERMEDIATE_CONTAINERS); - assertNull(buildImageParams.getBuildArgs()); } @@ -447,4 +325,18 @@ public void shouldAddBuildArgToBuildArgs() { assertEquals(buildImageParams.getBuildArgs().get(key), value); } + @Test + public void cpuQuotaParameterShouldBeNullIfItNotSet() { + assertNull(buildImageParams.getCpuQuota()); + } + + @Test + public void cpuPeriodParameterShouldBeNullIfItNotSet() { + assertNull(buildImageParams.getCpuPeriod()); + } + + @Test + public void cpusetCpusParameterShouldBeNullIfItNotSet() { + assertNull(buildImageParams.getCpusetCpus()); + } } 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 b5b5fed8a31..2e9f2b790ba 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 @@ -140,12 +140,10 @@ public Map getProperties() { md.put("config.workingDir", config.getWorkingDir()); md.put("config.cmd", Arrays.toString(config.getCmd())); md.put("config.volumes", String.valueOf(config.getVolumes())); - md.put("config.cpuset", config.getCpuset()); md.put("config.entrypoint", Arrays.toString(config.getEntrypoint())); md.put("config.exposedPorts", String.valueOf(config.getExposedPorts())); md.put("config.macAddress", config.getMacAddress()); md.put("config.securityOpts", Arrays.toString(config.getSecurityOpts())); - md.put("config.cpuShares", Integer.toString(config.getCpuShares())); md.put("config.env", Arrays.toString(config.getEnv())); md.put("config.attachStderr", Boolean.toString(config.isAttachStderr())); md.put("config.attachStdin", Boolean.toString(config.isAttachStdin())); 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 03cf3e53d5c..c84ccee383b 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 @@ -21,7 +21,6 @@ import org.eclipse.che.api.core.model.machine.ServerConf; import org.eclipse.che.api.core.util.FileCleaner; import org.eclipse.che.api.core.util.LineConsumer; -import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.api.core.util.SystemInfo; import org.eclipse.che.api.environment.server.MachineInstanceProvider; import org.eclipse.che.api.environment.server.model.CheServiceImpl; @@ -35,6 +34,7 @@ import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.Size; +import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.lang.os.WindowsPathEscaper; import org.eclipse.che.plugin.docker.client.DockerConnector; import org.eclipse.che.plugin.docker.client.DockerConnectorConfiguration; @@ -127,6 +127,10 @@ public class MachineProviderImpl implements MachineInstanceProvider { private final double memorySwapMultiplier; private final String networkDriver; private final Set additionalNetworks; + private final String parentCgroup; + private final String cpusetCpus; + private final long cpuPeriod; + private final long cpuQuota; private final WindowsPathEscaper windowsPathEscaper; @Inject @@ -149,6 +153,10 @@ public MachineProviderImpl(DockerConnector docker, @Named("che.docker.swap") double memorySwapMultiplier, @Named("machine.docker.networks") Set> additionalNetworks, @Nullable @Named("che.docker.network_driver") String networkDriver, + @Nullable @Named("che.docker.parent_cgroup") String parentCgroup, + @Nullable @Named("che.docker.cpuset_cpus") String cpusetCpus, + @Named("che.docker.cpu_period") long cpuPeriod, + @Named("che.docker.cpu_quota") long cpuQuota, WindowsPathEscaper windowsPathEscaper) throws IOException { this.docker = docker; @@ -168,6 +176,10 @@ public MachineProviderImpl(DockerConnector docker, // we calculate this field as memorySwap=memory * (1 + multiplier) so we just add 1 to multiplier this.memorySwapMultiplier = memorySwapMultiplier == -1 ? -1 : memorySwapMultiplier + 1; this.networkDriver = networkDriver; + this.parentCgroup = parentCgroup; + this.cpusetCpus = cpusetCpus; + this.cpuPeriod = cpuPeriod; + this.cpuQuota = cpuQuota; this.windowsPathEscaper = windowsPathEscaper; this.pidsLimit = pidsLimit; @@ -403,6 +415,9 @@ protected void buildImage(CheServiceImpl service, .withDoForcePull(doForcePullOnBuild) .withMemoryLimit(service.getMemLimit()) .withMemorySwapLimit(-1) + .withCpusetCpus(cpusetCpus) + .withCpuPeriod(cpuPeriod) + .withCpuQuota(cpuQuota) .withBuildArgs(service.getBuild().getArgs()); docker.buildImage(buildImageParams, progressMonitor); @@ -491,12 +506,8 @@ private String createContainer(String workspaceId, HostConfig hostConfig = new HostConfig(); hostConfig.withBinds(toArrayIfNotNull(service.getVolumes())) - .withExtraHosts(allMachinesExtraHosts) - .withPublishAllPorts(true) .withMemorySwap(machineMemorySwap) .withMemory(service.getMemLimit()) - .withPrivileged(privilegeMode) - .withPidsLimit(pidsLimit) .withNetworkMode(networkName) .withLinks(toArrayIfNotNull(service.getLinks())) .withPortBindings(service.getPorts() @@ -522,11 +533,28 @@ private String createContainer(String workspaceId, .map(entry -> entry.getKey() + "=" + entry.getValue()) .toArray(String[]::new)); + addStaticDockerConfiguration(config); + return docker.createContainer(CreateContainerParams.create(config) .withContainerName(service.getContainerName())) .getId(); } + private void addStaticDockerConfiguration(ContainerConfig config) { + config.getHostConfig() + .withPidsLimit(pidsLimit) + .withExtraHosts(allMachinesExtraHosts) + .withPrivileged(privilegeMode) + .withPublishAllPorts(true); + // CPU limits + config.getHostConfig() + .withCpusetCpus(cpusetCpus) + .withCpuQuota(cpuQuota) + .withCpuPeriod(cpuPeriod); + // Cgroup parent for custom limits + config.getHostConfig().setCgroupParent(parentCgroup); + } + private void addSystemWideContainerSettings(String workspaceId, boolean isDev, CheServiceImpl composeService) throws IOException { @@ -653,7 +681,7 @@ protected Set removeEmptyAndNullValues(Set paths) { */ private Set escapePaths(Set paths) { return paths.stream() - .map(path -> windowsPathEscaper.escapePathStatic(path)) + .map(windowsPathEscaper::escapePath) .collect(toSet()); } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/MachineProviderImplTest.java b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/MachineProviderImplTest.java index 645897b7f01..b0e07c05899 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/MachineProviderImplTest.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/MachineProviderImplTest.java @@ -263,6 +263,17 @@ public void shouldCreateContainerOnInstanceCreationFromRecipe() throws Exception "eclipse-che/" + machine.getContainerName()); } + @Test + public void shouldPublishAllExposedPortsOnCreateContainerOnInstanceCreationFromRecipe() throws Exception { + // when + createInstanceFromRecipe(); + + // then + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); + verify(dockerConnector).createContainer(argumentCaptor.capture()); + assertTrue(argumentCaptor.getValue().getContainerConfig().getHostConfig().isPublishAllPorts()); + } + @Test public void shouldStartContainerOnCreateInstanceFromRecipe() throws Exception { createInstanceFromRecipe(); @@ -285,7 +296,18 @@ public void shouldCreateContainerOnInstanceCreationFromSnapshot() throws Excepti } @Test - public void shouldCreateContainerWithPrivilegeMode() throws Exception { + public void shouldPublishAllExposedPortsOnCreateContainerOnInstanceCreationFromSnapshot() throws Exception { + // when + createInstanceFromSnapshot(); + + // then + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); + verify(dockerConnector).createContainer(argumentCaptor.capture()); + assertTrue(argumentCaptor.getValue().getContainerConfig().getHostConfig().isPublishAllPorts()); + } + + @Test + public void shouldBeAbleToCreateContainerWithPrivilegeMode() throws Exception { provider = spy(new MachineProviderBuilder().setPrivilegedMode(true) .build()); @@ -296,6 +318,54 @@ public void shouldCreateContainerWithPrivilegeMode() throws Exception { assertTrue(argumentCaptor.getValue().getContainerConfig().getHostConfig().isPrivileged()); } + @Test + public void shouldBeAbleToCreateContainerWithCpuSet() throws Exception { + provider = spy(new MachineProviderBuilder().setCpuSet("0-3") + .build()); + + createInstanceFromRecipe(); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); + verify(dockerConnector).createContainer(argumentCaptor.capture()); + assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getCpusetCpus(), "0-3"); + } + + @Test + public void shouldBeAbleToCreateContainerWithCpuPeriod() throws Exception { + provider = spy(new MachineProviderBuilder().setCpuPeriod(200) + .build()); + + createInstanceFromRecipe(); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); + verify(dockerConnector).createContainer(argumentCaptor.capture()); + assertEquals(((long)argumentCaptor.getValue().getContainerConfig().getHostConfig().getCpuPeriod()), 200); + } + + @Test + public void shouldBeAbleToCreateContainerWithCpuQuota() throws Exception { + provider = spy(new MachineProviderBuilder().setCpuQuota(200) + .build()); + + createInstanceFromRecipe(); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); + verify(dockerConnector).createContainer(argumentCaptor.capture()); + assertEquals(((long)argumentCaptor.getValue().getContainerConfig().getHostConfig().getCpuQuota()), 200); + } + + @Test + public void shouldBeAbleToCreateContainerWithCgroupParent() throws Exception { + provider = spy(new MachineProviderBuilder().setParentCgroup("some_parent") + .build()); + + createInstanceFromRecipe(); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); + verify(dockerConnector).createContainer(argumentCaptor.capture()); + assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getCgroupParent(), "some_parent"); + } + @Test public void shouldCreateContainerWithPidsLimit() throws Exception { provider = spy(new MachineProviderBuilder().setPidsLimit(512) @@ -992,7 +1062,6 @@ public void shouldAddEnvVarsFromMachineConfigToContainerOnDevInstanceCreationFro public void shouldAddLinksToContainerOnCreation() throws Exception { // given String links[] = new String[] {"container1", "container2:alias"}; - String networkName = "network"; CheServiceImpl service = createService(); service.setLinks(asList(links)); @@ -1137,6 +1206,11 @@ private class MachineProviderBuilder { private boolean snapshotUseRegistry; private Set> additionalNetworks; private double memorySwapMultiplier; + private String networkDriver; + private String parentCgroup; + private String cpuSet; + private long cpuPeriod; + private long cpuQuota; public MachineProviderBuilder() { devMachineEnvVars = emptySet(); @@ -1209,6 +1283,31 @@ public MachineProviderBuilder setExtraHosts(String extraHosts) { return this; } + public MachineProviderBuilder setNetworkDriver(String networkDriver) { + this.networkDriver = networkDriver; + return this; + } + + public MachineProviderBuilder setParentCgroup(String parentCgroup) { + this.parentCgroup = parentCgroup; + return this; + } + + public MachineProviderBuilder setCpuSet(String cpuSet) { + this.cpuSet = cpuSet; + return this; + } + + public MachineProviderBuilder setCpuPeriod(long cpuPeriod) { + this.cpuPeriod = cpuPeriod; + return this; + } + + public MachineProviderBuilder setCpuQuota(long cpuQuota) { + this.cpuQuota = cpuQuota; + return this; + } + MachineProviderImpl build() throws IOException { return new MachineProviderImpl(dockerConnector, dockerConnectorConfiguration, @@ -1228,7 +1327,11 @@ MachineProviderImpl build() throws IOException { snapshotUseRegistry, memorySwapMultiplier, additionalNetworks, - null, + networkDriver, + parentCgroup, + cpuSet, + cpuPeriod, + cpuQuota, pathEscaper); } } From b768872294066896861133f2fe3c6dbc6a655bbf Mon Sep 17 00:00:00 2001 From: Vitaliy Guliy Date: Wed, 7 Dec 2016 17:45:37 +0200 Subject: [PATCH 66/74] CHE-2463 Improve Panels behaviors in IDE (#3151) Signed-off-by: Vitaliy Guliy --- .../api/editor/AbstractEditorPresenter.java | 6 - .../ide/api/parts/AbstractPartPresenter.java | 2 +- .../eclipse/che/ide/api/parts/EditorTab.java | 6 +- .../che/ide/api/parts/PartPresenter.java | 9 +- .../eclipse/che/ide/api/parts/PartStack.java | 84 ++++++++- .../che/ide/api/parts/PartStackView.java | 7 +- .../che/ide/api/parts/Perspective.java | 19 +- .../che/ide/api/parts/PerspectiveView.java | 4 + .../api/parts/base/BaseActionDelegate.java | 13 +- .../che/ide/api/parts/base/BasePresenter.java | 16 +- .../che/ide/api/parts/base/BaseView.java | 84 ++++++++- .../ide/api/parts/base/MaximizePartEvent.java | 60 ++++++ .../che/ide/api/parts/base/ToolButton.java | 19 ++ .../che/ide/api/parts/base/ToolButton.ui.xml | 12 +- .../org/eclipse/che/ide/api/theme/Theme.java | 4 +- .../eclipse/che/ide/api/parts/partstack.css | 4 + .../che/ide/actions/ExpandEditorAction.java | 24 +-- .../che/ide/imageviewer/ImageViewer.java | 7 +- .../notification/NotificationManagerImpl.java | 7 +- .../che/ide/part/PartStackPresenter.java | 177 +++++++++++++++--- .../che/ide/part/PartStackViewImpl.java | 7 + .../part/editor/EditorPartStackPresenter.java | 7 +- .../ide/part/editor/EditorPartStackView.java | 7 + .../EditorMultiPartStackPresenter.java | 33 +++- .../EditorMultiPartStackViewImpl.java | 3 +- .../project/ProjectExplorerPresenter.java | 6 - .../project/ProjectExplorerViewImpl.java | 2 +- .../widgets/editortab/EditorTabWidget.java | 11 +- .../widgets/partbutton/PartButtonWidget.java | 11 +- .../presentation/FindResultPresenter.java | 5 - .../org/eclipse/che/ide/theme/DarkTheme.java | 16 +- .../org/eclipse/che/ide/theme/LightTheme.java | 10 +- .../general/AbstractPerspective.java | 140 ++++++++------ .../general/PerspectiveViewImpl.java | 13 +- .../project/ProjectPerspective.java | 2 +- .../perspectives/general/WorkBench.css | 6 + .../che/ide/part/PartStackPresenterTest.java | 7 +- .../EditorMultiPartStackPresenterTest.java | 9 - .../presentation/FindResultPresenterTest.java | 7 - .../che/ide/selection/TestSelectionAgent.java | 10 - .../AbstractPerspectivePersistenceTest.java | 2 +- .../general/AbstractPerspectiveTest.java | 41 ++-- .../org/eclipse/che/ide}/FontAwesome.java | 13 +- .../debugger/ide/debug/DebuggerPresenter.java | 7 +- .../git/client/action/AddToIndexAction.java | 2 +- .../ext/git/client/action/HistoryAction.java | 2 +- .../client/action/RemoveFromIndexAction.java | 2 +- .../git/client/action/ResetFilesAction.java | 2 +- .../client/action/ResetToCommitAction.java | 2 +- .../git/client/action/ShowStatusAction.java | 2 +- .../changedList/ChangedListViewImpl.java | 2 +- .../git/client/history/HistoryPresenter.java | 7 +- .../core/client/view/TestResultPresenter.java | 5 - .../client/view/TestResultPresenterTest.java | 7 - .../client/search/FindUsagesPresenter.java | 5 - .../ide/location/OpenLocationPresenter.java | 4 - .../machine/client/MachineExtension.java | 4 +- .../console/OutputConsoleViewImpl.java | 2 +- .../appliance/MachineApplianceViewImpl.java | 7 + .../machine/panel/MachinePanelPresenter.java | 6 - .../widgets/recipe/RecipePartPresenter.java | 6 - .../panel/ProcessesPanelPresenter.java | 5 - .../OperationsPerspectiveTest.java | 3 - .../recipe/RecipePartPresenterTest.java | 7 - .../plugin/svn/ide/copy/CopyPresenter.java | 12 -- .../che/plugin/svn/ide/copy/CopyView.java | 2 +- .../svn/ide/export/ExportPresenter.java | 12 -- .../che/plugin/svn/ide/export/ExportView.java | 2 +- .../plugin/svn/ide/move/MovePresenter.java | 12 -- .../che/plugin/svn/ide/move/MoveView.java | 2 +- .../ide/property/PropertyEditorPresenter.java | 16 -- .../svn/ide/property/PropertyEditorView.java | 4 +- .../ide/action/HelloWorldAction.java | 1 - .../ide/view/HelloWorldViewPresenter.java | 5 - .../helloworldview/HelloWorldPresenter.java | 5 - 75 files changed, 710 insertions(+), 384 deletions(-) create mode 100644 ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/MaximizePartEvent.java rename ide/{che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui => commons-gwt/src/main/java/org/eclipse/che/ide}/FontAwesome.java (91%) diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java index 771b9557236..30edc2d3af4 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java @@ -52,12 +52,6 @@ protected void updateDirtyState(boolean dirty) { firePropertyChange(PROP_DIRTY); } - /** {@inheritDoc} */ - @Override - public void setVisible(boolean visible) { - throw new UnsupportedOperationException("This method isn't supported in this class " + getClass()); - } - /** {@inheritDoc} */ @Override public IsWidget getView() { diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/AbstractPartPresenter.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/AbstractPartPresenter.java index 86587f78a8b..03dcd719927 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/AbstractPartPresenter.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/AbstractPartPresenter.java @@ -26,7 +26,7 @@ /** * Abstract base implementation of all PartPresenter * - * @author Evgen Vidolob + * @author Evgen Vidolob * @author Stéphane Daviet * @author Valeriy Svydenko */ diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorTab.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorTab.java index 4bc63700bae..617bce0ea3f 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorTab.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorTab.java @@ -22,7 +22,7 @@ /** * @author Dmitry Shnurenko */ -public interface EditorTab extends View, TabItem, DoubleClickHandler { +public interface EditorTab extends View, TabItem { void setReadOnlyMark(boolean isVisible); @@ -74,5 +74,9 @@ interface ActionDelegate { void onTabClicked(@NotNull TabItem tab); void onTabClose(@NotNull TabItem tab); + + void onTabDoubleClicked(@NotNull TabItem tab); + } + } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartPresenter.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartPresenter.java index 0f7ed5a4495..3477e0b23f8 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartPresenter.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartPresenter.java @@ -24,12 +24,14 @@ /** * Part is a main UI block of the IDE. * - * @author Nikolay Zamosenchuk + * @author Nikolay Zamosenchuk * @author Stéphane Daviet */ public interface PartPresenter extends Presenter { + /** The property id for getTitle, getTitleImage and getTitleToolTip. */ int TITLE_PROPERTY = 0x001; + /** The property id for getSelection. */ int SELECTION_PROPERTY = 0x002; @@ -47,8 +49,6 @@ public interface PartPresenter extends Presenter { List getRules(); - void setVisible(boolean visible); - IsWidget getView(); /** @@ -124,4 +124,5 @@ public interface PartPresenter extends Presenter { * a property listener */ void removePropertyListener(@NotNull PropertyListener listener); -} \ No newline at end of file + +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStack.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStack.java index b67dd247040..01cf9f32f8b 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStack.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStack.java @@ -20,9 +20,41 @@ * Part Stack is tabbed layout element, containing Parts. * * @author Nikolay Zamosenchuk + * @author Vitaliy Guliy */ public interface PartStack extends Presenter { + /** + * State of the part stack. + */ + enum State { + + /** + * The default state when the part stack is visible. + * Part stack can be minimized, maximized or collapsed. + */ + NORMAL, + + /** + * Part stack is minimized by minimize button. + * Having this state part stack can not be maximized or collapsed but + * only can be restored by clicking the tab button. + */ + MINIMIZED, + + /** + * Part stack is maximized. In this state it can be restored or minimized. + */ + MAXIMIZED, + + /** + * Part stack is collapsed while one is maximized. + * The state will be changed on NORMAL after restoring the perspective. + */ + COLLAPSED + + } + /** * Change the focused state of the PartStack to desired value * @@ -69,11 +101,34 @@ public interface PartStack extends Presenter { void setActivePart(@NotNull PartPresenter part); /** - * Hide given part (remove from the screen). If part not active part that method has no effect. + * Returns the state of the perspective. * - * @param part + * @return + * perspective state + */ + State getPartStackState(); + + /** + * Maximizes the part stack. + */ + void maximize(); + + /** + * Collapses the part stack. + * The part state will be restored when restoring the perspective. + */ + void collapse(); + + /** + * Minimizes / hides the part stack. + * The part state will not be retored when restoring the perspective state. + */ + void minimize(); + + /** + * Restores the part stack and the perspective to the default state. */ - void hidePart(PartPresenter part); + void restore(); /** * Remove given part from PartStack. @@ -95,4 +150,27 @@ public interface PartStack extends Presenter { * @return the parts list */ List getParts(); + + void setDelegate(ActionDelegate delegate); + + interface ActionDelegate { + + /** + * Requests the delegate to maximize the part stack. + * + * @param partStack + * part stack + */ + void onMaximize(PartStack partStack); + + /** + * Requests the delegate to restore part stack state. + * + * @param partStack + * part stack + */ + void onRestore(PartStack partStack); + + } + } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackView.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackView.java index 577e79c05f9..1cb7271292a 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackView.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackView.java @@ -11,6 +11,7 @@ package org.eclipse.che.ide.api.parts; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DoubleClickHandler; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; @@ -27,7 +28,7 @@ enum TabPosition { } /** Tab which can be clicked and closed */ - interface TabItem extends ClickHandler { + interface TabItem extends ClickHandler, DoubleClickHandler { @NotNull IsWidget getView(); @@ -66,6 +67,7 @@ interface TabItem extends ClickHandler { * orientation of the Tab (e.g. LEFT or RIGHT) */ void setTabPosition(@NotNull TabPosition tabPosition); + } /** Add Tab */ @@ -82,6 +84,8 @@ interface TabItem extends ClickHandler { /** Set PartStack focused */ void setFocus(boolean focused); + void setMaximized(boolean maximized); + /** Update Tab */ void updateTabItem(@NotNull PartPresenter partPresenter); @@ -90,4 +94,5 @@ interface ActionDelegate { /** PartStack is being clicked and requests Focus */ void onRequestFocus(); } + } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/Perspective.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/Perspective.java index 5952b820ce8..dd24af6f508 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/Perspective.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/Perspective.java @@ -26,14 +26,20 @@ */ public interface Perspective extends StateComponent { - /** Maximizes central part */ - void maximizeCentralPart(); + /** Maximizes central part stack */ + void maximizeCentralPartStack(); - /** Maximizes bottom part */ - void maximizeBottomPart(); + /** Maximize left part stack */ + void maximizeLeftPartStack(); - /** Restores parts to their states before maximizing */ - void restoreParts(); + /** Maximize right part stack */ + void maximizeRightPartStack(); + + /** Maximizes bottom part stack */ + void maximizeBottomPartStack(); + + /** Restores perspective to the state before maximizing */ + void restore(); /** Store perspective state before changing. */ void storeState(); @@ -114,4 +120,5 @@ public interface Perspective extends StateComponent { * container in which need expose view */ void go(@NotNull AcceptsOneWidget container); + } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PerspectiveView.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PerspectiveView.java index 25a8934524a..585802774e5 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PerspectiveView.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PerspectiveView.java @@ -50,5 +50,9 @@ public interface PerspectiveView extends View { /** Handle View events */ interface ActionDelegate { + + void onResize(int width, int height); + } + } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseActionDelegate.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseActionDelegate.java index 0750226cc75..24b48db0234 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseActionDelegate.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseActionDelegate.java @@ -17,13 +17,20 @@ */ public interface BaseActionDelegate { - /** Hide Part from UI */ - void minimize(); + /** + * Toggles maximized state of the part. + */ + void onToggleMaximize(); + + /** + * Minimizes the part. + */ + void onMinimize(); /** * Activate Part when clicking the mouse. * Is used when the Part contains frames and mouse events are blocked. */ - void activatePart(); + void onActivate(); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BasePresenter.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BasePresenter.java index eb47bb16477..38dfa147477 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BasePresenter.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BasePresenter.java @@ -24,20 +24,28 @@ public abstract class BasePresenter extends AbstractPartPresenter implements Bas protected PartStack partStack; - protected BasePresenter() { + @Override + public void onToggleMaximize() { + if (partStack != null) { + if (partStack.getPartStackState() == PartStack.State.MAXIMIZED) { + partStack.restore(); + } else { + partStack.maximize(); + } + } } /** {@inheritDoc} */ @Override - public void minimize() { + public void onMinimize() { if (partStack != null) { - partStack.hidePart(this); + partStack.minimize(); } } /** {@inheritDoc} */ @Override - public void activatePart() { + public void onActivate() { partStack.setActivePart(this); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java index f4ca707d6b8..1e4b5be84ca 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java @@ -16,15 +16,19 @@ import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.DoubleClickHandler; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.event.dom.client.MouseUpHandler; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.DockLayoutPanel; +import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; +import org.eclipse.che.ide.FontAwesome; import org.eclipse.che.ide.api.mvp.View; import org.eclipse.che.ide.api.parts.Focusable; import org.eclipse.che.ide.api.parts.PartStackUIResources; @@ -43,6 +47,8 @@ */ public abstract class BaseView extends Composite implements View, Focusable { + private final PartStackUIResources resources; + /** Root widget */ private DockLayoutPanel container; @@ -67,6 +73,8 @@ public void onBlur(BlurEvent event) { }; public BaseView(PartStackUIResources resources) { + this.resources = resources; + container = new DockLayoutPanel(Style.Unit.PX); container.getElement().setAttribute("role", "part"); container.setSize("100%", "100%"); @@ -94,10 +102,29 @@ public void onMouseUp(MouseUpEvent event) { toolbarHeader.getElement().setAttribute("role", "toolbar-header"); toolBar.addNorth(toolbarHeader, 22); + // padding 2 pixels from the right + toolbarHeader.addEast(new FlowPanel(), 2); + titleLabel = new Label(); titleLabel.setStyleName(resources.partStackCss().ideBasePartTitleLabel()); toolbarHeader.addWest(titleLabel, 200); + addMinimizeButton(); + addMaximizeButton(); + + /** + * Handle double clicking on the toolbar header + */ + toolbarHeader.addDomHandler(new DoubleClickHandler() { + @Override + public void onDoubleClick(DoubleClickEvent event) { + onToggleMaximize(); + } + }, DoubleClickEvent.getType()); + + } + + private void addMinimizeButton() { SVGImage minimize = new SVGImage(resources.collapseExpandIcon()); minimize.getElement().setAttribute("name", "workBenchIconMinimize"); minimizeButton = new ToolButton(minimize); @@ -105,7 +132,7 @@ public void onMouseUp(MouseUpEvent event) { minimizeButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - minimize(); + onMinimize(); } }); @@ -113,7 +140,41 @@ public void onClick(ClickEvent event) { if (minimizeButton.getElement() instanceof elemental.dom.Element) { Tooltip.create((elemental.dom.Element) minimizeButton.getElement(), - PositionController.VerticalAlign.BOTTOM, PositionController.HorizontalAlign.MIDDLE, "Hide"); + PositionController.VerticalAlign.BOTTOM, PositionController.HorizontalAlign.MIDDLE, "Hide"); + } + } + + private void addMaximizeButton() { + ToolButton maximizeButton = new ToolButton(FontAwesome.ARROWS_ALT); + maximizeButton.getElement().setAttribute("name", "maximizePart"); + maximizeButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + onToggleMaximize(); + } + }); + + addToolButton(maximizeButton); + + if (maximizeButton.getElement() instanceof elemental.dom.Element) { + Tooltip.create((elemental.dom.Element) maximizeButton.getElement(), + PositionController.VerticalAlign.BOTTOM, PositionController.HorizontalAlign.MIDDLE, "Maximize panel"); + } + } + + private void addMenuButton() { + ToolButton menuButton = new ToolButton(FontAwesome.ELLIPSIS_V); + menuButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + } + }); + + addToolButton(menuButton); + + if (menuButton.getElement() instanceof elemental.dom.Element) { + Tooltip.create((elemental.dom.Element) menuButton.getElement(), + PositionController.VerticalAlign.BOTTOM, PositionController.HorizontalAlign.MIDDLE, "Panel options"); } } @@ -124,7 +185,7 @@ public void onClick(ClickEvent event) { */ public final void addToolButton(@NotNull IsWidget button) { if (button != null) { - toolbarHeader.addEast(button, 22); + toolbarHeader.addEast(button, 18); } } @@ -167,10 +228,21 @@ public final void setDelegate(T delegate) { this.delegate = delegate; } - /** Requests delegate to minimize the part */ - protected void minimize() { + /** + * Toggles maximized state of the view. + */ + public void onToggleMaximize() { + if (delegate != null) { + delegate.onToggleMaximize(); + } + } + + /** + * Minimizes the view. + */ + public void onMinimize() { if (delegate != null) { - delegate.minimize(); + delegate.onMinimize(); } } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/MaximizePartEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/MaximizePartEvent.java new file mode 100644 index 00000000000..a649ad4bea2 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/MaximizePartEvent.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.api.parts.base; + +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; +import org.eclipse.che.ide.api.parts.PartPresenter; + +/** + * Fire this event to maximize part. + * + * @author Vitaliy Guliy + */ +public class MaximizePartEvent extends GwtEvent { + + /** + * Implement this handler to handle maximizing the part. + */ + public interface Handler extends EventHandler { + + void onMaximizePart(MaximizePartEvent event); + + } + + public static final GwtEvent.Type TYPE = new GwtEvent.Type<>(); + + private PartPresenter part; + + public MaximizePartEvent(PartPresenter part) { + this.part = part; + } + + /** + * Returns part to be maximized. + * + * @return part + */ + public PartPresenter getPart() { + return part; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(Handler handler) { + handler.onMaximizePart(this); + } + +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.java index 353118ed01e..b44863b11ec 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.java @@ -13,6 +13,8 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.DoubleClickHandler; import com.google.gwt.event.dom.client.HasClickHandlers; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.uibinder.client.UiBinder; @@ -49,6 +51,8 @@ interface TabButtonUiBinder extends UiBinder { public ToolButton(SVGImage image) { initWidget(uiBinder.createAndBindUi(this)); iconPanel.add(image); + + blockDoubleClicking(); } /** @@ -63,6 +67,8 @@ public ToolButton(String htmlImageResource) { FlowPanel image = new FlowPanel(); image.getElement().setInnerHTML(htmlImageResource); iconPanel.add(image); + + blockDoubleClicking(); } @Override @@ -70,4 +76,17 @@ public HandlerRegistration addClickHandler(ClickHandler clickHandler) { return iconPanel.addDomHandler(clickHandler, ClickEvent.getType()); } + /** + * Blocks double clicking on the button and on the parent element. + */ + private void blockDoubleClicking() { + addDomHandler(new DoubleClickHandler() { + @Override + public void onDoubleClick(DoubleClickEvent event) { + event.stopPropagation(); + event.preventDefault(); + } + }, DoubleClickEvent.getType()); + } + } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.ui.xml b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.ui.xml index faeb9ab9002..2e8a883a82f 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.ui.xml +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/ToolButton.ui.xml @@ -18,15 +18,15 @@ @eval toolButtonColor org.eclipse.che.ide.api.theme.Style.theme.toolButtonColor(); @eval toolButtonHoverColor org.eclipse.che.ide.api.theme.Style.theme.toolButtonHoverColor(); - @eval toolButtonBorder org.eclipse.che.ide.api.theme.Style.theme.toolButtonBorder(); @eval toolButtonActiveBorder org.eclipse.che.ide.api.theme.Style.theme.toolButtonActiveBorder(); + @eval toolButtonActiveColor org.eclipse.che.ide.api.theme.Style.theme.toolButtonActiveColor(); @eval toolButtonHoverBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.toolButtonHoverBackgroundColor(); @eval toolButtonActiveBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.toolButtonActiveBackgroundColor(); @eval toolButtonHoverBoxShadow org.eclipse.che.ide.api.theme.Style.theme.toolButtonHoverBoxShadow(); @eval toolButtonActiveBoxShadow org.eclipse.che.ide.api.theme.Style.theme.toolButtonActiveBoxShadow(); .button { - width: 22px; + width: 18px; height: 22px; } @@ -47,7 +47,7 @@ margin: auto; padding: 3px; box-sizing: content-box; - border: toolButtonBorder; + border: 1px solid transparent; border-radius: 3px; fill: toolButtonColor; font-size: 8px; @@ -60,7 +60,6 @@ .button:hover > div { border: toolButtonActiveBorder; background-color: toolButtonHoverBackgroundColor; - box-shadow: toolButtonHoverBoxShadow; fill: toolButtonHoverColor; color: toolButtonHoverColor; } @@ -69,9 +68,8 @@ .button:active > div { border: toolButtonActiveBorder; background-color: toolButtonActiveBackgroundColor; - box-shadow: toolButtonActiveBoxShadow; - fill: toolButtonHoverColor; - color: toolButtonHoverColor; + fill: toolButtonActiveColor; + color: toolButtonActiveColor; } .button:active > svg > *, diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java index cc1b00b541d..619760e0cd4 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java @@ -1577,14 +1577,14 @@ public interface Theme { String toolButtonHoverColor(); - String toolButtonBorder(); - String toolButtonActiveBorder(); String toolButtonHoverBackgroundColor(); String toolButtonActiveBackgroundColor(); + String toolButtonActiveColor(); + String toolButtonHoverBoxShadow(); String toolButtonActiveBoxShadow(); diff --git a/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css index 929e210e130..4f8b9267a37 100644 --- a/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css +++ b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css @@ -128,6 +128,10 @@ border-bottom-color: tabUnderlineColor; } +div[maximized="true"] div[name="maximizePart"] i { + color: blueIconColor; +} + .ide-Base-Part-Title-Label { display: inline-block; line-height: 20px; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/ExpandEditorAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/ExpandEditorAction.java index 55423140ec8..1e563aeaff8 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/ExpandEditorAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/ExpandEditorAction.java @@ -28,9 +28,11 @@ import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.action.CustomComponentAction; import org.eclipse.che.ide.api.action.Presentation; +import org.eclipse.che.ide.api.parts.PartStack; +import org.eclipse.che.ide.api.parts.PartStackType; import org.eclipse.che.ide.api.parts.Perspective; import org.eclipse.che.ide.api.parts.PerspectiveManager; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; /** * @author Evgen Vidolob @@ -45,7 +47,6 @@ public class ExpandEditorAction extends Action implements CustomComponentAction private FlowPanel buttonPanel; private FlowPanel button; - private boolean expanded; @Inject public ExpandEditorAction(Resources resources, @@ -107,18 +108,17 @@ public void toggleExpand() { return; } - expanded = !expanded; + PartStack partStack = perspective.getPartStack(PartStackType.EDITING); + if (partStack == null) { + return; + } - if (expanded) { - perspective.maximizeCentralPart(); - if (button != null) { - button.getElement().setInnerHTML(FontAwesome.COMPRESS); - } + if (partStack.getPartStackState() == PartStack.State.NORMAL) { + perspective.maximizeCentralPartStack(); + button.getElement().setInnerHTML(FontAwesome.COMPRESS); } else { - perspective.restoreParts(); - if (button != null) { - button.getElement().setInnerHTML(FontAwesome.EXPAND); - } + perspective.restore(); + button.getElement().setInnerHTML(FontAwesome.EXPAND); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/imageviewer/ImageViewer.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/imageviewer/ImageViewer.java index b1f485cbdd9..d5e1529c52f 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/imageviewer/ImageViewer.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/imageviewer/ImageViewer.java @@ -171,12 +171,6 @@ public void close(final boolean save) { // nothing to do } - /** {@inheritDoc} */ - @Override - public void setVisible(boolean visible) { - editorView.setVisible(visible); - } - /** {@inheritDoc} */ @Override public IsWidget getView() { @@ -196,4 +190,5 @@ public void onFileOperation(FileEvent event) { workspaceAgent.removePart(this); } } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java index 7ef78ee57ec..eb1e2fff0e1 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/notification/NotificationManagerImpl.java @@ -349,12 +349,6 @@ public String getTitle() { return TITLE; } - /** {@inheritDoc} */ - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - /** {@inheritDoc} */ @Override public SVGResource getTitleImage() { @@ -390,4 +384,5 @@ public void onNotificationStatusChanged(StatusNotification notification) { nPopupStack.push(notification); } } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java index 941f7c3df19..050931daa33 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java @@ -61,6 +61,7 @@ public class PartStackPresenter implements Presenter, PartStackView.ActionDelega private final PartsComparator partsComparator; private final Map constraints; private final PartStackEventHandler partStackHandler; + private final EventBus eventBus; protected final Map parts; protected final TabItemFactory tabItemFactory; @@ -71,6 +72,10 @@ public class PartStackPresenter implements Presenter, PartStackView.ActionDelega protected TabItem activeTab; protected double currentSize; + private State state = State.NORMAL; + + private ActionDelegate delegate; + @Inject public PartStackPresenter(final EventBus eventBus, PartStackEventHandler partStackEventHandler, @@ -81,6 +86,7 @@ public PartStackPresenter(final EventBus eventBus, this.view = view; this.view.setDelegate(this); + this.eventBus = eventBus; this.partStackHandler = partStackEventHandler; this.workBenchPartController = workBenchPartController; this.tabItemFactory = tabItemFactory; @@ -108,6 +114,11 @@ public void propertyChanged(PartPresenter source, int propId) { currentSize = DEFAULT_PART_SIZE; } + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + private void updatePartTab(@NotNull PartPresenter part) { if (!containsPart(part)) { return; @@ -189,14 +200,15 @@ public PartPresenter getActivePart() { /** {@inheritDoc} */ @Override public void setActivePart(@NotNull PartPresenter part) { - TabItem activeTab = getTabByPart(part); + TabItem tab = getTabByPart(part); - if (activeTab == null) { + if (tab == null) { return; } activePart = part; - selectActiveTab(activeTab); + activeTab = tab; + selectActiveTab(tab); } @Nullable @@ -211,20 +223,6 @@ protected TabItem getTabByPart(@NotNull PartPresenter part) { return null; } - /** {@inheritDoc} */ - @Override - public void hidePart(PartPresenter part) { - TabItem activeTab = getTabByPart(part); - - if (activeTab == null) { - return; - } - - this.activeTab = activeTab; - - onTabClicked(activeTab); - } - /** {@inheritDoc} */ @Override public void removePart(PartPresenter part) { @@ -273,23 +271,149 @@ public void setFocus(boolean focused) { view.setFocus(focused); } + @Override + public void maximize() { + // Update the view state. + view.setMaximized(true); + + // Update dimensions of the part stack if it's already maximized. Used when resizing the view. + if (state == State.MAXIMIZED) { + workBenchPartController.maximize(); + return; + } + + // Part stack can be maximized only having NORMAL state. + if (state != State.NORMAL) { + return; + } + + // Maximize and update the state. + currentSize = workBenchPartController.getSize(); + workBenchPartController.maximize(); + state = State.MAXIMIZED; + + // Ask the delegate to maximize this part stack and collapse other. + if (delegate != null) { + delegate.onMaximize(this); + } + } + + @Override + public void collapse() { + // Update the view state. + view.setMaximized(false); + + // Part stack can be collapsed only having NORMAL state. + if (state != State.NORMAL) { + return; + } + + // Collapse and update the state. + currentSize = workBenchPartController.getSize(); + workBenchPartController.setSize(0); + state = State.COLLAPSED; + + // Deselect the active tab. + if (activeTab != null) { + activeTab.unSelect(); + } + } + + @Override + public State getPartStackState() { + return state; + } + + @Override + public void minimize() { + // Update the view state. + view.setMaximized(false); + + // Ask the delegate to restore pack stack if it's maximized. + if (state == State.MAXIMIZED) { + if (delegate != null) { + delegate.onRestore(this); + } + } + + // Part stack can be minimized only having NORMAL state. + if (state == State.NORMAL) { + currentSize = workBenchPartController.getSize(); + workBenchPartController.setSize(0); + state = State.MINIMIZED; + } + + // Deselect active tab. + if (activeTab != null) { + activeTab.unSelect(); + } + } + + @Override + public void restore() { + // Update the view state. + view.setMaximized(false); + + // Don't restore part stack if it's in MINIMIZED or NORMAL state. + if (state == State.MINIMIZED || state == State.NORMAL) { + return; + } + + // Restore and update the stack. + State prevState = state; + state = State.NORMAL; + workBenchPartController.setSize(currentSize); + + // Ask the delegate to restore part stacks if this part stack was maximized. + if (prevState == State.MAXIMIZED) { + if (delegate != null) { + delegate.onRestore(this); + } + } + + // Select active tab. + if (activeTab != null) { + activeTab.select(); + } + } + /** {@inheritDoc} */ @Override public void onTabClicked(@NotNull TabItem selectedTab) { - //handle somehow part close event - if (selectedTab.equals(activeTab)) { - selectedTab.unSelect(); + // Change the state to COLLAPSED for the following restoring. + if (state == State.MINIMIZED) { + state = State.COLLAPSED; + } - currentSize = workBenchPartController.getSize(); + // Restore COLLAPSED part stack. + if (state == State.COLLAPSED) { + activeTab = selectedTab; - workBenchPartController.setSize(0); + if (delegate != null) { + delegate.onRestore(this); + } - activeTab = null; - activePart = null; + activePart = parts.get(selectedTab); + activePart.onOpen(); + selectActiveTab(activeTab); return; } + // Minimize the part stack if user clicked on the active tab. + if (selectedTab.equals(activeTab)) { + if (state == State.NORMAL) { + minimize(); + + activeTab.unSelect(); + activeTab = null; + activePart = null; + } + + return; + } + + // Change active tab. activeTab = selectedTab; activePart = parts.get(selectedTab); activePart.onOpen(); @@ -297,10 +421,6 @@ public void onTabClicked(@NotNull TabItem selectedTab) { } private void selectActiveTab(@NotNull TabItem selectedTab) { - double partSize = workBenchPartController.getSize(); - currentSize = partSize >= MIN_PART_SIZE ? partSize : currentSize; - - workBenchPartController.setSize(currentSize); workBenchPartController.setHidden(false); PartPresenter selectedPart = parts.get(selectedTab); @@ -313,4 +433,5 @@ public interface PartStackEventHandler { /** PartStack is being clicked and requests Focus */ void onRequestFocus(PartStack partStack); } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackViewImpl.java index 67498bef6c0..4291c5c3cc1 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackViewImpl.java @@ -73,6 +73,8 @@ public void setWidget(IsWidget widget) { addDomHandler(this, MouseDownEvent.getType()); addDomHandler(this, ContextMenuEvent.getType()); + + setMaximized(false); } /** {@inheritDoc} */ @@ -177,4 +179,9 @@ public void updateTabItem(@NotNull PartPresenter partPresenter) { tabItem.update(partPresenter); } + @Override + public void setMaximized(boolean maximized) { + getElement().setAttribute("maximized", "" + maximized); + } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java index 0874b7967c9..e45c6929753 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java @@ -33,6 +33,7 @@ import org.eclipse.che.ide.api.parts.PartPresenter; import org.eclipse.che.ide.api.parts.PartStackView.TabItem; import org.eclipse.che.ide.api.parts.PropertyListener; +import org.eclipse.che.ide.api.parts.base.MaximizePartEvent; import org.eclipse.che.ide.api.resources.ResourceChangedEvent; import org.eclipse.che.ide.api.resources.ResourceChangedEvent.ResourceChangedHandler; import org.eclipse.che.ide.api.resources.ResourceDelta; @@ -116,7 +117,6 @@ public EditorPartStackPresenter(EditorPartStackView view, ActionManager actionManager, ClosePaneAction closePaneAction, CloseAllTabsPaneAction closeAllTabsPaneAction) { - //noinspection ConstantConditions super(eventBus, partStackEventHandler, tabItemFactory, partsComparator, view, null); this.editorPaneMenuItemFactory = editorPaneMenuItemFactory; this.eventBus = eventBus; @@ -281,6 +281,11 @@ public void onTabClicked(@NotNull TabItem tab) { view.selectTab(parts.get(tab)); } + @Override + public void onTabDoubleClicked(@NotNull TabItem tab) { + eventBus.fireEvent(new MaximizePartEvent(parts.get(tab))); + } + /** {@inheritDoc} */ @Override public void removePart(PartPresenter part) { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackView.java index 82d8677455f..e03224aaf8a 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackView.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackView.java @@ -83,6 +83,8 @@ public void setWidget(IsWidget widget) { }; addDomHandler(this, MouseDownEvent.getType()); + + setMaximized(false); } /** {@inheritDoc} */ @@ -248,6 +250,11 @@ public void setFocus(boolean focused) { } } + @Override + public void setMaximized(boolean maximized) { + getElement().setAttribute("maximized", Boolean.toString(maximized)); + } + /** {@inheritDoc} */ @Override public void updateTabItem(@NotNull PartPresenter partPresenter) { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackPresenter.java index 51d53177a00..66666e2ef20 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackPresenter.java @@ -45,6 +45,8 @@ public class EditorMultiPartStackPresenter implements EditorMultiPartStack, private PartPresenter activeEditor; private EditorPartStack activeEditorPartStack; + private State state = State.NORMAL; + @Inject public EditorMultiPartStackPresenter(EventBus eventBus, EditorMultiPartStackView view, @@ -56,6 +58,9 @@ public EditorMultiPartStackPresenter(EventBus eventBus, eventBus.addHandler(ActivePartChangedEvent.TYPE, this); } + @Override + public void setDelegate(ActionDelegate delegate) { + } @Override public void go(AcceptsOneWidget container) { @@ -138,11 +143,28 @@ public void setActivePart(@NotNull PartPresenter part) { } @Override - public void hidePart(PartPresenter part) { - EditorPartStack editorPartStack = getPartStackByPart(part); - if (editorPartStack != null) { - editorPartStack.hidePart(part); - } + public void maximize() { + state = State.MAXIMIZED; + } + + @Override + public void collapse() { + state = State.COLLAPSED; + } + + @Override + public void minimize() { + state = State.MINIMIZED; + } + + @Override + public void restore() { + state = State.NORMAL; + } + + @Override + public State getPartStackState() { + return state; } /** {@inheritDoc} */ @@ -292,4 +314,5 @@ public void onActivePartChanged(ActivePartChangedEvent event) { activeEditorPartStack = getPartStackByPart(activePart); } } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java index 7bcc3876c62..e6a6c0b2e22 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/multipart/EditorMultiPartStackViewImpl.java @@ -32,7 +32,7 @@ /** * @author Roman Nikitenko */ -public class EditorMultiPartStackViewImpl extends ResizeComposite implements EditorMultiPartStackView{ +public class EditorMultiPartStackViewImpl extends ResizeComposite implements EditorMultiPartStackView { private LayoutPanel contentPanel; @@ -75,7 +75,6 @@ public void setWidget(IsWidget widget) { return; } - relativePartStackView.split(widget, constraints.direction, size); splitEditorParts.put(partStack, relativePartStackView.getReplica()); splitEditorParts.put(relativePartStack, relativePartStackView.getSpecimen()); 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 53ac311303a..0c4089c33f8 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 @@ -306,12 +306,6 @@ public View getView() { return view; } - /** {@inheritDoc} */ - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - /** {@inheritDoc} */ @NotNull @Override diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java index 44a5fc0efec..1a2baaabed4 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/explorer/project/ProjectExplorerViewImpl.java @@ -39,7 +39,7 @@ import org.eclipse.che.ide.project.node.SyntheticNode; import org.eclipse.che.ide.resources.tree.ResourceNode; import org.eclipse.che.ide.resources.tree.SkipHiddenNodesInterceptor; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import org.eclipse.che.ide.ui.Tooltip; import org.eclipse.che.ide.ui.smartTree.NodeDescriptor; import org.eclipse.che.ide.ui.smartTree.NodeLoader; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java index caa15355693..f210f781e12 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java @@ -237,17 +237,9 @@ public void onContextMenu(ContextMenuEvent event) { /** {@inheritDoc} */ @Override public void onDoubleClick(@NotNull DoubleClickEvent event) { - expandEditor(); + delegate.onTabDoubleClicked(this); } - private native void expandEditor() /*-{ - try { - $wnd.IDE.eventHandlers.expandEditor(); - } catch (e) { - console.log(e.message); - } - }-*/; - /** {@inheritDoc} */ @Override public void setDelegate(ActionDelegate delegate) { @@ -335,4 +327,5 @@ public void onFileOperation(FileEvent event) { delegate.onTabClose(this); } } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/partbutton/PartButtonWidget.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/partbutton/PartButtonWidget.java index de36f8ca3a4..e394f68d4f5 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/partbutton/PartButtonWidget.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/partbutton/PartButtonWidget.java @@ -13,6 +13,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.DoubleClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; @@ -70,6 +71,7 @@ public PartButtonWidget(Resources resources, @Assisted String title) { setStyleName(resources.partStackCss().idePartStackTab()); ensureDebugId("partButton-" + title); + addDomHandler(this, DoubleClickEvent.getType()); addDomHandler(this, ClickEvent.getType()); tabName.setText(title); @@ -181,13 +183,19 @@ public void onClick(@NotNull ClickEvent event) { delegate.onTabClicked(this); } + @Override + public void onDoubleClick(DoubleClickEvent event) { + event.stopPropagation(); + event.preventDefault(); + } + /** {@inheritDoc} */ @Override public void select() { tabSelected = true; addStyleName(tabPosition == BELOW ? resources.partStackCss().selectedBottomTab() - : resources.partStackCss().selectedRightOrLeftTab()); + : resources.partStackCss().selectedRightOrLeftTab()); updateBadge(); } @@ -236,4 +244,5 @@ public void setDelegate(@NotNull ActionDelegate delegate) { interface PartButtonWidgetUiBinder extends UiBinder { } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/search/presentation/FindResultPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/search/presentation/FindResultPresenter.java index 891508cb5a1..b06d2c09279 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/search/presentation/FindResultPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/search/presentation/FindResultPresenter.java @@ -70,11 +70,6 @@ public String getTitle() { return localizationConstant.actionFullTextSearch(); } - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - @Override public IsWidget getView() { return view; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java index df928046b05..f73ae05074d 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java @@ -1471,24 +1471,24 @@ public String toolButtonHoverColor() { return "#D8D8D8"; } - @Override - public String toolButtonBorder() { - return "1px solid transparent"; - } - @Override public String toolButtonActiveBorder() { - return "1px solid #24272c"; + return "1px solid #262626"; } @Override public String toolButtonHoverBackgroundColor() { - return "#44484D"; + return "#262626"; } @Override public String toolButtonActiveBackgroundColor() { - return "#33373B"; + return "#262626"; + } + + @Override + public String toolButtonActiveColor() { + return "#4eabff"; } @Override diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java index 131ac1cc205..767f860e369 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java @@ -1447,11 +1447,6 @@ public String toolButtonHoverColor() { return "#333333"; } - @Override - public String toolButtonBorder() { - return "1px solid transparent"; - } - @Override public String toolButtonActiveBorder() { return "1px solid #8E8E8E"; @@ -1467,6 +1462,11 @@ public String toolButtonActiveBackgroundColor() { return "#AFAFB0"; } + @Override + public String toolButtonActiveColor() { + return "#4eabff"; + } + @Override public String toolButtonHoverBoxShadow() { return "none"; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/AbstractPerspective.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/AbstractPerspective.java index 11f7ee55eed..3ebc44664d3 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/AbstractPerspective.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/AbstractPerspective.java @@ -25,8 +25,11 @@ import org.eclipse.che.ide.api.parts.PartPresenter; import org.eclipse.che.ide.api.parts.PartStack; import org.eclipse.che.ide.api.parts.PartStackType; +import static org.eclipse.che.ide.api.parts.PartStackType.EDITING; import org.eclipse.che.ide.api.parts.PartStackView; import org.eclipse.che.ide.api.parts.Perspective; +import org.eclipse.che.ide.api.parts.PerspectiveView; +import org.eclipse.che.ide.api.parts.base.MaximizePartEvent; import org.eclipse.che.ide.workspace.PartStackPresenterFactory; import org.eclipse.che.ide.workspace.PartStackViewFactory; import org.eclipse.che.ide.workspace.WorkBenchControllerFactory; @@ -52,34 +55,25 @@ * @author Dmitry Shnurenko */ //TODO need rewrite this, remove direct dependency on PerspectiveViewImpl and other GWT Widgets -public abstract class AbstractPerspective implements Presenter, Perspective, ActivePartChangedHandler { - - private enum State { - NORMAL, - MAXIMIZED_LEFT_PART, - MAXIMIZED_RIGHT_PART, - MAXIMIZED_BOTTOM_PART, - MAXIMIZED_CENTRAL_PART - } +public abstract class AbstractPerspective implements Presenter, Perspective, + ActivePartChangedHandler, MaximizePartEvent.Handler, + PerspectiveView.ActionDelegate, PartStack.ActionDelegate { protected final Map partStacks; protected final PerspectiveViewImpl view; private final String perspectiveId; private final DynaProvider dynaProvider; + private final WorkBenchPartController leftPartController; private final WorkBenchPartController rightPartController; private final WorkBenchPartController belowPartController; - private double leftPartSize; - private double rightPartSize; - private double belowPartSize; - - private State layoutState = State.NORMAL; - private PartPresenter activePart; private PartPresenter activePartBeforeChangePerspective; + private PartStack maximizedPartStack; + protected AbstractPerspective(@NotNull String perspectiveId, @NotNull PerspectiveViewImpl view, @NotNull PartStackPresenterFactory stackPresenterFactory, @@ -92,25 +86,28 @@ protected AbstractPerspective(@NotNull String perspectiveId, this.dynaProvider = dynaProvider; this.partStacks = new HashMap<>(); - PartStackView navigationView = partViewFactory.create(LEFT, view.getLeftPanel()); + view.setDelegate(this); + PartStackView navigationView = partViewFactory.create(LEFT, view.getLeftPanel()); leftPartController = controllerFactory.createController(view.getSplitPanel(), view.getNavigationPanel()); PartStack navigationPartStack = stackPresenterFactory.create(navigationView, leftPartController); + navigationPartStack.setDelegate(this); partStacks.put(NAVIGATION, navigationPartStack); PartStackView informationView = partViewFactory.create(BELOW, view.getBottomPanel()); - belowPartController = controllerFactory.createController(view.getSplitPanel(), view.getInformationPanel()); PartStack informationStack = stackPresenterFactory.create(informationView, belowPartController); + informationStack.setDelegate(this); partStacks.put(INFORMATION, informationStack); PartStackView toolingView = partViewFactory.create(RIGHT, view.getRightPanel()); - rightPartController = controllerFactory.createController(view.getSplitPanel(), view.getToolPanel()); PartStack toolingPartStack = stackPresenterFactory.create(toolingView, rightPartController); + toolingPartStack.setDelegate(this); partStacks.put(TOOLING, toolingPartStack); eventBus.addHandler(ActivePartChangedEvent.TYPE, this); + eventBus.addHandler(MaximizePartEvent.TYPE, this); } /** @@ -160,58 +157,82 @@ public void removePart(@NotNull PartPresenter part) { public void hidePart(@NotNull PartPresenter part) { PartStack destPartStack = findPartStackByPart(part); if (destPartStack != null) { - destPartStack.hidePart(part); + destPartStack.minimize(); } } /** {@inheritDoc} */ @Override - public void maximizeCentralPart() { - if (layoutState == State.MAXIMIZED_CENTRAL_PART) { - return; - } - - leftPartSize = leftPartController.getSize(); - rightPartSize = rightPartController.getSize(); - belowPartSize = belowPartController.getSize(); + public void maximizeCentralPartStack() { + onMaximize(partStacks.get(EDITING)); + } - leftPartController.setHidden(true); - rightPartController.setHidden(true); - belowPartController.setHidden(true); + /** {@inheritDoc} */ + @Override + public void maximizeLeftPartStack() { + onMaximize(partStacks.get(NAVIGATION)); + } - layoutState = State.MAXIMIZED_CENTRAL_PART; + /** {@inheritDoc} */ + @Override + public void maximizeRightPartStack() { + onMaximize(partStacks.get(TOOLING)); } /** {@inheritDoc} */ @Override - public void maximizeBottomPart() { - if (layoutState == State.MAXIMIZED_BOTTOM_PART) { + public void maximizeBottomPartStack() { + onMaximize(partStacks.get(INFORMATION)); + } + + @Override + public void onMaximizePart(MaximizePartEvent event) { + PartStack partStack = findPartStackByPart(event.getPart()); + if (partStack == null) { + return; + } + + if (partStack.getPartStackState() == PartStack.State.MAXIMIZED) { + onRestore(partStack); + } else { + onMaximize(partStack); + } + } + + @Override + public void onMaximize(PartStack partStack) { + if (partStack == null) { return; } - leftPartSize = leftPartController.getSize(); - rightPartSize = rightPartController.getSize(); - belowPartSize = belowPartController.getSize(); + if (partStack.equals(maximizedPartStack)) { + return; + } - leftPartController.setHidden(true); - rightPartController.setHidden(true); - belowPartController.maximize(); + maximizedPartStack = partStack; - layoutState = State.MAXIMIZED_BOTTOM_PART; + for (PartStack ps : partStacks.values()) { + if (!ps.equals(partStack)) { + ps.collapse(); + } + } + + partStack.maximize(); } - /** {@inheritDoc} */ @Override - public void restoreParts() { - if (layoutState == State.NORMAL) { - return; + public void onRestore(PartStack partStack) { + for (PartStack ps : partStacks.values()) { + ps.restore(); } - leftPartController.setSize(leftPartSize); - rightPartController.setSize(rightPartSize); - belowPartController.setSize(belowPartSize); + maximizedPartStack = null; + } - layoutState = State.NORMAL; + /** {@inheritDoc} */ + @Override + public void restore() { + onRestore(null); } /** {@inheritDoc} */ @@ -239,12 +260,10 @@ public void setActivePart(@NotNull PartPresenter part, @NotNull PartStackType ty */ public PartStack findPartStackByPart(@NotNull PartPresenter part) { for (PartStackType partStackType : PartStackType.values()) { - if (partStacks.get(partStackType).containsPart(part)) { return partStacks.get(partStackType); } } - return null; } @@ -263,7 +282,6 @@ public void addPart(@NotNull PartPresenter part, @NotNull PartStackType type, @N if (rules.isEmpty() && !destPartStack.containsPart(part)) { destPartStack.addPart(part, constraint); - return; } @@ -272,6 +290,13 @@ public void addPart(@NotNull PartPresenter part, @NotNull PartStackType type, @N } } + @Override + public void onResize(int width, int height) { + if (maximizedPartStack != null) { + maximizedPartStack.maximize(); + } + } + /** {@inheritDoc} */ @Override @Nullable @@ -286,7 +311,6 @@ public JsonObject getState() { state.put("ACTIVE_PART", activePart.getClass().getName()); state.put("PART_STACKS", partStacks); - partStacks.put(PartStackType.INFORMATION.name(), getPartStackState(this.partStacks.get(INFORMATION), belowPartController)); partStacks.put(PartStackType.NAVIGATION.name(), getPartStackState(this.partStacks.get(NAVIGATION), leftPartController)); partStacks.put(PartStackType.TOOLING.name(), getPartStackState(this.partStacks.get(TOOLING), rightPartController)); @@ -325,13 +349,13 @@ public void loadState(@NotNull JsonObject state) { JsonObject partStack = part_stacks.getObject(partStackType); switch (PartStackType.valueOf(partStackType)) { case INFORMATION: - belowPartSize = restorePartController(partStacks.get(INFORMATION), belowPartController, partStack, activeParts); + restorePartController(partStacks.get(INFORMATION), belowPartController, partStack, activeParts); break; case NAVIGATION: - leftPartSize = restorePartController(partStacks.get(NAVIGATION), leftPartController, partStack, activeParts); + restorePartController(partStacks.get(NAVIGATION), leftPartController, partStack, activeParts); break; case TOOLING: - rightPartSize = restorePartController(partStacks.get(TOOLING), rightPartController, partStack, activeParts); + restorePartController(partStacks.get(TOOLING), rightPartController, partStack, activeParts); break; } } @@ -339,6 +363,7 @@ public void loadState(@NotNull JsonObject state) { setActivePart(part); } } + if (state.hasKey("ACTIVE_PART")) { String activePart = state.getString("ACTIVE_PART"); Provider provider = dynaProvider.getProvider(activePart); @@ -346,10 +371,9 @@ public void loadState(@NotNull JsonObject state) { setActivePart(provider.get()); } } - } - private double restorePartController(PartStack stack, WorkBenchPartController controller, JsonObject partStack, + private void restorePartController(PartStack stack, WorkBenchPartController controller, JsonObject partStack, List activeParts) { double size = 0; if (partStack.hasKey("SIZE")) { @@ -390,6 +414,6 @@ private double restorePartController(PartStack stack, WorkBenchPartController co activeParts.add(provider.get()); } } - return size; } + } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/PerspectiveViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/PerspectiveViewImpl.java index 8b2e3ebca5c..848ae88ea76 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/PerspectiveViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/perspectives/general/PerspectiveViewImpl.java @@ -70,6 +70,8 @@ interface PerspectiveViewImplUiBinder extends UiBinderanyObject())).thenReturn(partStackPresenter); perspective = - new DummyPerspective(view, stackPresenterFactory, partStackViewFactory, controllerFactory, eventBus, partStackPresenter, - dynaProvider); + new DummyPerspective(view, stackPresenterFactory, partStackViewFactory, controllerFactory, eventBus, + extraPartStackPresenter, partStackPresenter, dynaProvider); } @Test @@ -186,22 +191,22 @@ public void partShouldBeHided() { perspective.hidePart(partPresenter); - verify(partStackPresenter).hidePart(partPresenter); + verify(partStackPresenter).minimize(); } @Test - public void partsShouldBeCollapsed() { - perspective.maximizeCentralPart(); + public void partShouldBeMaximized() { + perspective.onMaximize(partStackPresenter); - verify(workBenchController, times(3)).getSize(); - verify(workBenchController, times(3)).setHidden(true); + verify(partStackPresenter).maximize(); } @Test - public void partsShouldBeRestored() { - perspective.maximizeBottomPart(); - perspective.restoreParts(); - verify(workBenchController, times(3)).setSize(anyDouble()); + public void partShouldBeCollapsed() { + perspective.onMaximize(extraPartStackPresenter); + + verify(partStackPresenter, times(3)).collapse(); + verify(extraPartStackPresenter).maximize(); } @Test @@ -276,11 +281,20 @@ public DummyPerspective(@NotNull PerspectiveViewImpl view, @NotNull PartStackViewFactory partViewFactory, @NotNull WorkBenchControllerFactory controllerFactory, @NotNull EventBus eventBus, - PartStackPresenter partStackPresenter, + + PartStackPresenter extraPartStackPresenter, + PartStackPresenter editingPartStackPresenter, + DynaProvider dynaProvider) { super(SOME_TEXT, view, stackPresenterFactory, partViewFactory, controllerFactory, eventBus, dynaProvider); - partStacks.put(EDITING, partStackPresenter); + if (extraPartStackPresenter != null) { + partStacks.put(NAVIGATION, extraPartStackPresenter); + } + + if (editingPartStackPresenter != null) { + partStacks.put(EDITING, editingPartStackPresenter); + } } @Override @@ -288,4 +302,5 @@ public void go(@NotNull AcceptsOneWidget container) { throw new NotSupportedException("This method will be tested in the class which extends AbstractPerspective"); } } + } diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/FontAwesome.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/FontAwesome.java similarity index 91% rename from ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/FontAwesome.java rename to ide/commons-gwt/src/main/java/org/eclipse/che/ide/FontAwesome.java index 13088565d14..c7733ecc959 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/FontAwesome.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/FontAwesome.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.ui; +package org.eclipse.che.ide; /** * Font awesome icons. @@ -17,6 +17,11 @@ */ public class FontAwesome { + /** + * http://fortawesome.github.io/Font-Awesome/icon/arrows-alt/ + */ + public static final String ARROWS_ALT = ""; + /** * http://fortawesome.github.io/Font-Awesome/icon/arrow-circle-o-left/ */ @@ -47,6 +52,11 @@ public class FontAwesome { */ public static final String DOWNLOAD = ""; + /** + * http://fortawesome.github.io/Font-Awesome/icon/ellipsis-v/ + */ + public static final String ELLIPSIS_V = ""; + /** * http://fortawesome.github.io/Font-Awesome/icon/expand/ */ @@ -121,4 +131,5 @@ public class FontAwesome { * http://fontawesome.io/icon/square-o/ */ public static final String SQUARE_O = ""; + } diff --git a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/DebuggerPresenter.java b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/DebuggerPresenter.java index 1a93a76d2fa..1fd653e4de6 100644 --- a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/DebuggerPresenter.java +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/DebuggerPresenter.java @@ -120,11 +120,6 @@ public String getTitle() { return TITLE; } - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - @Override public IsWidget getView() { return view; @@ -183,7 +178,7 @@ public void showDebuggerPanel() { } public void hideDebuggerPanel() { - partStack.hidePart(this); + partStack.minimize(); } public boolean isDebuggerPanelOpened() { 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 2356a9da89e..9f9e0574182 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 @@ -18,7 +18,7 @@ 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.add.AddToIndexPresenter; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import static com.google.common.base.Preconditions.checkState; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/HistoryAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/HistoryAction.java index 4931650c4e8..5934ff915fc 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/HistoryAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/HistoryAction.java @@ -19,7 +19,7 @@ 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.history.HistoryPresenter; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import static com.google.common.base.Preconditions.checkState; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/RemoveFromIndexAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/RemoveFromIndexAction.java index 1d703bd10ce..4f71f2dda0a 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/RemoveFromIndexAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/RemoveFromIndexAction.java @@ -18,7 +18,7 @@ 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.remove.RemoveFromIndexPresenter; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import static com.google.common.base.Preconditions.checkState; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetFilesAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetFilesAction.java index ad8127ef9ee..7c4928a6267 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetFilesAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetFilesAction.java @@ -18,7 +18,7 @@ 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.reset.files.ResetFilesPresenter; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import static com.google.common.base.Preconditions.checkState; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetToCommitAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetToCommitAction.java index d44dc7990a8..7e91a12366d 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetToCommitAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ResetToCommitAction.java @@ -18,7 +18,7 @@ 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.reset.commit.ResetToCommitPresenter; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import static com.google.common.base.Preconditions.checkState; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ShowStatusAction.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ShowStatusAction.java index a380c0fdcb1..e65b76c48c1 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ShowStatusAction.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/action/ShowStatusAction.java @@ -18,7 +18,7 @@ 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.status.StatusCommandPresenter; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import static com.google.common.base.Preconditions.checkState; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/changedList/ChangedListViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/changedList/ChangedListViewImpl.java index c2ad9d448f1..c9b0d52f137 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/changedList/ChangedListViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/changedList/ChangedListViewImpl.java @@ -29,7 +29,7 @@ import org.eclipse.che.ide.ext.git.client.compare.FileStatus.Status; import org.eclipse.che.ide.project.shared.NodesResources; import org.eclipse.che.ide.resource.Path; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import org.eclipse.che.ide.ui.smartTree.NodeLoader; import org.eclipse.che.ide.ui.smartTree.NodeStorage; import org.eclipse.che.ide.ui.smartTree.SelectionModel; 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 297fa245bd8..d19655d6304 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 @@ -161,7 +161,7 @@ public void apply(PromiseError error) throws OperationException { consolesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console); notificationManager.notify(constant.logFailed(), FAIL, FLOAT_MODE); } - partStack.hidePart(HistoryPresenter.this); + partStack.minimize(); workspaceAgent.removePart(HistoryPresenter.this); isViewClosed = true; } @@ -434,11 +434,6 @@ protected enum DiffWith { DIFF_WITH_PREV_VERSION } - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - @Override public IsWidget getView() { return view; diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java index 90d2bfd1045..7b9f8d77b88 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/main/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenter.java @@ -51,11 +51,6 @@ public String getTitle() { return localizationConstant.titleTestResultPresenter(); } - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - @Override public IsWidget getView() { return view; diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java index 171051753ae..af05339404b 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/src/test/java/org/eclipse/che/ide/ext/java/testing/core/client/view/TestResultPresenterTest.java @@ -65,13 +65,6 @@ public void titleToolTipShouldBeReturned() { verify(localizationConstant).titleTestResultPresenterToolTip(); } - @Test - public void visibilityShouldBeUpdated() { - testResultPresenter.setVisible(false); - - verify(view).setVisible(false); - } - @Test public void viewShouldBeReturned() { assertEquals(testResultPresenter.getView(), view); diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/search/FindUsagesPresenter.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/search/FindUsagesPresenter.java index d220136a306..e54fbaf9537 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/search/FindUsagesPresenter.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/search/FindUsagesPresenter.java @@ -87,11 +87,6 @@ public String getTitle() { return localizationConstant.findUsagesPartTitle(); } - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - @Override public IsWidget getView() { return view; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/location/OpenLocationPresenter.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/location/OpenLocationPresenter.java index deb967a7dcb..b5bbd28a096 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/location/OpenLocationPresenter.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/location/OpenLocationPresenter.java @@ -99,10 +99,6 @@ public String getTitle() { return title; } - @Override - public void setVisible(boolean visible) { - } - @Override public IsWidget getView() { return view; diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java index 8e0badc50cd..5933862229b 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java @@ -142,7 +142,7 @@ private void maximizeTerminal() { public void execute() { Perspective perspective = perspectiveManager.getActivePerspective(); if (perspective != null) { - perspective.maximizeBottomPart(); + perspective.maximizeBottomPartStack(); } } }); @@ -154,7 +154,7 @@ public void execute() { private void restoreTerminal() { Perspective perspective = perspectiveManager.getActivePerspective(); if (perspective != null) { - perspective.restoreParts(); + perspective.restore(); } } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/OutputConsoleViewImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/OutputConsoleViewImpl.java index fe659d69b6e..522154a0c5b 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/OutputConsoleViewImpl.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/OutputConsoleViewImpl.java @@ -38,7 +38,7 @@ import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.extension.machine.client.MachineResources; -import org.eclipse.che.ide.ui.FontAwesome; +import org.eclipse.che.ide.FontAwesome; import org.eclipse.che.ide.ui.Tooltip; import static com.google.common.collect.Lists.newArrayList; diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/appliance/MachineApplianceViewImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/appliance/MachineApplianceViewImpl.java index 294439ef5f4..d515499b2b1 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/appliance/MachineApplianceViewImpl.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/appliance/MachineApplianceViewImpl.java @@ -56,6 +56,8 @@ public MachineApplianceViewImpl(MachineResources resources, Label unavailableLab this.tabContainers = new ArrayList<>(); addContainer(unavailableLabel); + + setMaximized(false); } /** {@inheritDoc} */ @@ -132,6 +134,11 @@ public void setFocus(boolean focused) { //to do nothing } + @Override + public void setMaximized(boolean maximized) { + getElement().setAttribute("maximized", "" + maximized); + } + /** {@inheritDoc} */ @Override public void updateTabItem(@NotNull PartPresenter partPresenter) { diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/panel/MachinePanelPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/panel/MachinePanelPresenter.java index e0112939a11..60492960169 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/panel/MachinePanelPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/machine/panel/MachinePanelPresenter.java @@ -202,12 +202,6 @@ public String getTitle() { return locale.machinePanelTitle(); } - /** {@inheritDoc} */ - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - /** {@inheritDoc} */ @Override public IsWidget getView() { diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenter.java index 5a30c11a696..197ad553e48 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenter.java @@ -271,12 +271,6 @@ public String getTitle() { return locale.viewRecipePanelTitle(); } - /** {@inheritDoc} */ - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - /** {@inheritDoc} */ @Override public IsWidget getView() { diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java index a6d5cae5e0d..cfa18efb0d3 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java @@ -245,11 +245,6 @@ public String getTitle() { return localizationConstant.viewProcessesTitle(); } - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - @Override public IsWidget getView() { return view; diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/OperationsPerspectiveTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/OperationsPerspectiveTest.java index 21beee2d1bb..64f01c6d4f8 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/OperationsPerspectiveTest.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/OperationsPerspectiveTest.java @@ -18,7 +18,6 @@ import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.parts.PartStackType; import org.eclipse.che.ide.api.parts.PartStackView; import org.eclipse.che.ide.extension.machine.client.perspective.widgets.machine.appliance.MachineAppliancePresenter; @@ -61,8 +60,6 @@ public class OperationsPerspectiveTest { @Mock private MachineAppliancePresenter infoContainer; @Mock - private NotificationManager notificationManager; - @Mock private RecipePartPresenter recipePanel; @Mock private EventBus eventBus; diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenterTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenterTest.java index cf0b81353c6..5e3af8a278c 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenterTest.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/perspective/widgets/recipe/RecipePartPresenterTest.java @@ -332,13 +332,6 @@ public void titleShouldBeReturned() throws Exception { verify(locale).viewRecipePanelTitle(); } - @Test - public void panelShouldBeHidden() throws Exception { - recipePartPresenter.setVisible(false); - - verify(recipePartView).setVisible(false); - } - @Test public void toolTipShouldBeShowed() throws Exception { recipePartPresenter.getTitleToolTip(); diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyPresenter.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyPresenter.java index 3079fb66361..247dd911722 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyPresenter.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyPresenter.java @@ -201,18 +201,6 @@ public void onTargetCheckBoxChanged() { validate(); } - /** {@inheritDoc} */ - @Override - public void minimize() { - //stub - } - - /** {@inheritDoc} */ - @Override - public void activatePart() { - //stub - } - private void validate() { ValidationStrategy strategy; diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyView.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyView.java index cd4ddff5389..835e57b996a 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyView.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/copy/CopyView.java @@ -26,7 +26,7 @@ public interface CopyView extends View { /** Action handler for the view actions/controls. */ - interface ActionDelegate extends BaseActionDelegate { + interface ActionDelegate { /** Perform actions when copy button clicked. */ void onCopyClicked(); diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportPresenter.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportPresenter.java index 9d2637f70e2..7803d31ee8c 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportPresenter.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportPresenter.java @@ -172,16 +172,4 @@ private void openExportPopup(Path project, Path exportPath, String revision, Sta notification.setStatus(SUCCESS); } - /** {@inheritDoc} */ - @Override - public void minimize() { - - } - - /** {@inheritDoc} */ - @Override - public void activatePart() { - - } - } diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportView.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportView.java index 6fd1d3a34c8..aa7d27dad26 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportView.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/export/ExportView.java @@ -22,7 +22,7 @@ public interface ExportView extends View { /** Action handler for the view actions/controls. */ - public interface ActionDelegate extends BaseActionDelegate { + interface ActionDelegate { /** Perform actions when cancel button clicked. */ void onCancelClicked(); diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MovePresenter.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MovePresenter.java index c54b176135f..9e03d613e3a 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MovePresenter.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MovePresenter.java @@ -156,18 +156,6 @@ public void onCancelClicked() { view.onClose(); } - /** {@inheritDoc} */ - @Override - public void minimize() { - //stub - } - - /** {@inheritDoc} */ - @Override - public void activatePart() { - //stub - } - /** {@inheritDoc} */ @Override public void onUrlsChanged() { diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MoveView.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MoveView.java index 8dd917bb5d2..61197cde753 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MoveView.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/move/MoveView.java @@ -25,7 +25,7 @@ @ImplementedBy(MoveViewImpl.class) public interface MoveView extends View { /** Action handler for the view actions/controls. */ - interface ActionDelegate extends BaseActionDelegate { + interface ActionDelegate { void onMoveClicked(); /** Perform actions when cancel button clicked. */ diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorPresenter.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorPresenter.java index eb7d9a6a89a..63b79557bc8 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorPresenter.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorPresenter.java @@ -129,22 +129,6 @@ public void apply(PromiseError error) throws OperationException { }); } - /** - * {@inheritDoc} - */ - @Override - public void minimize() { - // stub - } - - /** - * {@inheritDoc} - */ - @Override - public void activatePart() { - // stub - } - private void editProperty(Project project) { final String propertyName = view.getSelectedProperty(); final Depth depth = view.getDepth(); diff --git a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorView.java b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorView.java index 4de8d5e5619..b150448674d 100644 --- a/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorView.java +++ b/plugins/plugin-svn/che-plugin-svn-ext-ide/src/main/java/org/eclipse/che/plugin/svn/ide/property/PropertyEditorView.java @@ -24,7 +24,8 @@ */ public interface PropertyEditorView extends View { - public interface ActionDelegate extends BaseActionDelegate { + interface ActionDelegate { + void onCancelClicked(); void onOkClicked(); @@ -32,6 +33,7 @@ public interface ActionDelegate extends BaseActionDelegate { void onPropertyNameChanged(String propertyName); void obtainExistingPropertiesForPath(); + } /** Perform actions when close window performed. */ diff --git a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/action/HelloWorldAction.java b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/action/HelloWorldAction.java index 777dbcf9dff..5d127d5be2e 100644 --- a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/action/HelloWorldAction.java +++ b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/action/HelloWorldAction.java @@ -40,7 +40,6 @@ public HelloWorldAction(WorkspaceAgent workspaceAgent, HelloWorldViewPresenter h public void actionPerformed(ActionEvent e) { workspaceAgent.openPart(helloWorldViewPresenter, PartStackType.INFORMATION); workspaceAgent.setActivePart(helloWorldViewPresenter); - helloWorldViewPresenter.setVisible(true); } } diff --git a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/view/HelloWorldViewPresenter.java b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/view/HelloWorldViewPresenter.java index daaf92e16d2..474f7606729 100644 --- a/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/view/HelloWorldViewPresenter.java +++ b/samples/sample-plugin-embedjs/che-sample-plugin-embedjs-ide/src/main/java/org/eclipse/che/plugin/embedjsexample/ide/view/HelloWorldViewPresenter.java @@ -66,11 +66,6 @@ public SVGResource getTitleImage() { return (HelloWorldResources.INSTANCE.icon()); } - @Override - public void setVisible(boolean visible) { - helloWorldView.setVisible(visible); - } - @Override public View getView() { return helloWorldView; diff --git a/samples/sample-plugin-parts/che-sample-plugin-parts-ide/src/main/java/org/eclipse/che/plugin/parts/ide/helloworldview/HelloWorldPresenter.java b/samples/sample-plugin-parts/che-sample-plugin-parts-ide/src/main/java/org/eclipse/che/plugin/parts/ide/helloworldview/HelloWorldPresenter.java index 9637122af1f..064843901a4 100644 --- a/samples/sample-plugin-parts/che-sample-plugin-parts-ide/src/main/java/org/eclipse/che/plugin/parts/ide/helloworldview/HelloWorldPresenter.java +++ b/samples/sample-plugin-parts/che-sample-plugin-parts-ide/src/main/java/org/eclipse/che/plugin/parts/ide/helloworldview/HelloWorldPresenter.java @@ -39,11 +39,6 @@ public String getTitle() { return "Hello World View"; } - @Override - public void setVisible(boolean visible) { - view.setVisible(visible); - } - @Override public SVGResource getTitleImage() { return (SamplePartsResources.INSTANCE.icon()); From aaceba1cca6c404c651acad6c245760a7e236e01 Mon Sep 17 00:00:00 2001 From: Vladyslav Zhukovskyi Date: Wed, 7 Dec 2016 18:09:42 +0200 Subject: [PATCH 67/74] warning: [MissingOverride] clone overrides method in Object; expected @Override (#3261) * Add missing override annotation Findbugs warns with the following message: warning: [MissingOverride] clone overrides method in Object; expected @Override * Add missing override annotation * Add missing override annotation * Add missing override annotation * Add missing override annotation * Add missing override annotation * Add missing override annotation * Add missing override annotation * Remove @Override annotation due to GWT library doesn't have clone method * Remove @Override annotation due to GWT library doesn't have clone method --- .../eclipse/che/ide/api/action/PropertyChangeEvent.java | 1 + .../che/ide/api/data/tree/settings/NodeSettings.java | 1 + .../che/ide/api/editor/annotation/AnnotationModelImpl.java | 1 + .../che/ide/api/editor/annotation/AnnotationsIterator.java | 3 +++ .../che/ide/api/editor/annotation/RegionIterator.java | 3 +++ .../che/ide/api/editor/document/AbstractDocument.java | 1 + .../che/ide/api/editor/events/doc/DocReadyWrapper.java | 1 + .../che/ide/api/editor/partition/ConstantPartitioner.java | 2 ++ .../che/ide/api/editor/partition/DefaultPartitioner.java | 3 +++ .../che/ide/api/editor/partition/PartitionScanner.java | 1 + .../eclipse/che/ide/api/editor/reconciler/DirtyRegion.java | 3 +++ .../ide/api/editor/reconciler/ReconcilerWithAutoSave.java | 1 + .../java/org/eclipse/che/ide/api/editor/text/Position.java | 3 +++ .../org/eclipse/che/ide/api/editor/text/RegionImpl.java | 5 +++++ .../org/eclipse/che/ide/api/editor/text/TypedPosition.java | 3 +++ .../eclipse/che/ide/api/editor/text/TypedRegionImpl.java | 4 ++++ .../eclipse/che/ide/api/editor/text/rules/TokenImpl.java | 5 +++++ .../eclipse/che/ide/api/editor/texteditor/TextEditor.java | 2 ++ .../che/ide/api/editor/texteditor/TextEditorPresenter.java | 1 + .../che/ide/api/event/HttpSessionDestroyedEvent.java | 2 ++ .../java/org/eclipse/che/ide/api/machine/DevMachine.java | 3 +++ .../org/eclipse/che/ide/api/parts/EditorPartStack.java | 1 + .../java/org/eclipse/che/ide/api/parts/base/BaseView.java | 1 + .../main/java/org/eclipse/che/ide/api/resources/File.java | 7 +++++++ 24 files changed, 58 insertions(+) diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/PropertyChangeEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/PropertyChangeEvent.java index 6481c7064dd..2009f87d380 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/PropertyChangeEvent.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/PropertyChangeEvent.java @@ -113,6 +113,7 @@ public Object getOldValue() { * * @return a string representation of the object */ + @Override public String toString() { StringBuilder sb = new StringBuilder(getClass().getName()); sb.append("[propertyName=").append(getPropertyName()); diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/data/tree/settings/NodeSettings.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/data/tree/settings/NodeSettings.java index 4e9ec423ff8..c95aeaea91f 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/data/tree/settings/NodeSettings.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/data/tree/settings/NodeSettings.java @@ -30,6 +30,7 @@ public boolean isShowHiddenFiles() { return showHiddenFiles; } + @Override public void setShowHiddenFiles(boolean show) { this.showHiddenFiles = show; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationModelImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationModelImpl.java index b7deb60ecef..a79448c281d 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationModelImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationModelImpl.java @@ -306,6 +306,7 @@ public void shiftLines(final int fromLine, final int lineDelta, final int charDe this.annotations.putAll(modified); } + @Override public void clear() { this.annotations.clear(); this.positions.clear(); diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationsIterator.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationsIterator.java index 3c745b0aa95..6aa51b01e6a 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationsIterator.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/AnnotationsIterator.java @@ -47,16 +47,19 @@ public AnnotationsIterator(final List positions, next = findNext(); } + @Override public boolean hasNext() { return next != null; } + @Override public Annotation next() { final Annotation result = next; next = findNext(); return result; } + @Override public void remove() { throw new UnsupportedOperationException(); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/RegionIterator.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/RegionIterator.java index 5ac8008cfa8..a2b14dfd2a3 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/RegionIterator.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/annotation/RegionIterator.java @@ -59,10 +59,12 @@ public RegionIterator(Iterator parentIterator, AnnotationModel model next = findNext(); } + @Override public boolean hasNext() { return next != null; } + @Override public Annotation next() { if (!hasNext()) { throw new NoSuchElementException(); @@ -73,6 +75,7 @@ public Annotation next() { return result; } + @Override public void remove() { throw new UnsupportedOperationException(); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/AbstractDocument.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/AbstractDocument.java index b38f3a4f7e9..b105c2d63fe 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/AbstractDocument.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/AbstractDocument.java @@ -38,6 +38,7 @@ public Document getDocument() { return this; } + @Override public DocumentHandle getDocumentHandle() { return this; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/events/doc/DocReadyWrapper.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/events/doc/DocReadyWrapper.java index 2f99d5617bd..c65a376c4b4 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/events/doc/DocReadyWrapper.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/events/doc/DocReadyWrapper.java @@ -43,6 +43,7 @@ public DocReadyWrapper(final EventBus generalEventBus, final EditorHandle editor this.docReadyRegistration = generalEventBus.addHandler(DocumentReadyEvent.TYPE, new DocumentReadyHandler() { + @Override public void onDocumentReady(final DocumentReadyEvent event) { if (event == null) { return; diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/ConstantPartitioner.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/ConstantPartitioner.java index 324a980521b..c0aaaa564b7 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/ConstantPartitioner.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/ConstantPartitioner.java @@ -89,10 +89,12 @@ public TypedRegion getPartition(final int offset) { return new TypedRegionImpl(offset, this.documentLength, this.contentType); } + @Override public DocumentHandle getDocumentHandle() { return documentHandle; } + @Override public void setDocumentHandle(DocumentHandle handle) { this.documentHandle = handle; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/DefaultPartitioner.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/DefaultPartitioner.java index 2793861485e..eff97b9c5ba 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/DefaultPartitioner.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/DefaultPartitioner.java @@ -53,6 +53,7 @@ public DefaultPartitioner(final PartitionScanner scanner, this.positionCategory = DocumentPositionMap.Categories.DEFAULT_CATEGORY; } + @Override public void initialize() { this.documentPositionMap.addPositionCategory(this.positionCategory); this.documentPositionMap.setContentLength(this.documentHandle.getDocument().getContentsCharCount()); @@ -415,10 +416,12 @@ private int getContentLength() { return getDocumentHandle().getDocument().getContentsCharCount(); } + @Override public DocumentHandle getDocumentHandle() { return documentHandle; } + @Override public void setDocumentHandle(DocumentHandle handle) { this.documentHandle = handle; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/PartitionScanner.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/PartitionScanner.java index 8a64b6ec895..bac7429306d 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/PartitionScanner.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/partition/PartitionScanner.java @@ -27,5 +27,6 @@ public interface PartitionScanner extends TokenScanner { * Set the string to scan. * @param content the new content to parse */ + @Override void setScannedString(String content); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/DirtyRegion.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/DirtyRegion.java index 4de97149765..45f0e805e2f 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/DirtyRegion.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/DirtyRegion.java @@ -69,16 +69,19 @@ private String normalizeTypeValue(String type) { } /** Returns the offset of the region. */ + @Override public int getOffset() { return fOffset; } /** Returns the length of the region. */ + @Override public int getLength() { return fLength; } /** Returns the content type of the region. */ + @Override public String getType() { return fType; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/ReconcilerWithAutoSave.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/ReconcilerWithAutoSave.java index f58b22e445b..16106370a14 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/ReconcilerWithAutoSave.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/reconciler/ReconcilerWithAutoSave.java @@ -215,6 +215,7 @@ public String getDocumentPartitioning() { return partition; } + @Override public void addReconcilingStrategy(final String contentType, final ReconcilingStrategy strategy) { strategies.put(contentType, strategy); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/Position.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/Position.java index 38eb75217b8..c5c57e2d61c 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/Position.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/Position.java @@ -70,6 +70,7 @@ protected Position() { } /* @see java.lang.Object#hashCode() */ + @Override public int hashCode() { int deleted = isDeleted ? 0 : 1; return (offset << 24) | (length << 16) | deleted; @@ -86,6 +87,7 @@ public void undelete() { } /* @see java.lang.Object#isEquals(java.lang.Object) */ + @Override public boolean equals(Object other) { if (other instanceof Position) { Position rp = (Position)other; @@ -189,6 +191,7 @@ public void setOffset(int offset) { /* * @see java.lang.Object#toString() */ + @Override public String toString() { String position = "offset: " + offset + ", length: " + length; //$NON-NLS-1$//$NON-NLS-2$ return isDeleted ? position + " (deleted)" : position; //$NON-NLS-1$ diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/RegionImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/RegionImpl.java index 27a943e57ae..308f4f05e6a 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/RegionImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/RegionImpl.java @@ -33,16 +33,19 @@ public RegionImpl(int offset, int length) { } /* @see org.eclipse.jface.text.IRegion#getLength() */ + @Override public int getLength() { return fLength; } /* @see org.eclipse.jface.text.IRegion#getOffset() */ + @Override public int getOffset() { return fOffset; } /* @see java.lang.Object#isEquals(java.lang.Object) */ + @Override public boolean equals(Object o) { if (o instanceof Region) { Region r = (Region)o; @@ -52,11 +55,13 @@ public boolean equals(Object o) { } /* @see java.lang.Object#hashCode() */ + @Override public int hashCode() { return (fOffset << 24) | (fLength << 16); } /* @see java.lang.Object#toString() */ + @Override public String toString() { return "offset: " + fOffset + ", length: " + fLength; //$NON-NLS-1$ //$NON-NLS-2$; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedPosition.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedPosition.java index 1dfadecece3..d45ce594ed7 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedPosition.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedPosition.java @@ -62,6 +62,7 @@ public String getType() { /* * @see java.lang.Object#isEquals(java.lang.Object) */ + @Override public boolean equals(Object o) { if (o instanceof TypedPosition) { if (super.equals(o)) { @@ -75,6 +76,7 @@ public boolean equals(Object o) { /* * @see java.lang.Object#hashCode() */ + @Override public int hashCode() { int type = fType == null ? 0 : fType.hashCode(); return super.hashCode() | type; @@ -83,6 +85,7 @@ public int hashCode() { /* * @see org.eclipse.jface.text.Region#toString() */ + @Override public String toString() { return fType + " - " + super.toString(); //$NON-NLS-1$ } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedRegionImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedRegionImpl.java index a9bfb7b676c..c676b0bc1c2 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedRegionImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/TypedRegionImpl.java @@ -32,11 +32,13 @@ public TypedRegionImpl(int offset, int length, String type) { } /* @see org.eclipse.jface.text.ITypedRegion#getProjectType() */ + @Override public String getType() { return fType; } /* @see java.lang.Object#isEquals(java.lang.Object) */ + @Override public boolean equals(Object o) { if (o instanceof TypedRegionImpl) { TypedRegionImpl r = (TypedRegionImpl)o; @@ -46,6 +48,7 @@ public boolean equals(Object o) { } /* @see java.lang.Object#hashCode() */ + @Override public int hashCode() { int type = fType == null ? 0 : fType.hashCode(); return super.hashCode() | type; @@ -55,6 +58,7 @@ public int hashCode() { * @see org.eclipse.jface.text.Region#toString() * @since 3.5 */ + @Override public String toString() { return fType + " - " + super.toString(); //$NON-NLS-1$ } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/rules/TokenImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/rules/TokenImpl.java index d5b82374f78..0f6351ef644 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/rules/TokenImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/text/rules/TokenImpl.java @@ -63,6 +63,7 @@ public TokenImpl(Object data) { /* * @see IToken#getData() */ + @Override public Object getData() { return fData; } @@ -82,6 +83,7 @@ public void setData(Object data) { /* * @see IToken#isOther() */ + @Override public boolean isOther() { return (fType == T_OTHER); } @@ -89,6 +91,7 @@ public boolean isOther() { /* * @see IToken#isEOF() */ + @Override public boolean isEOF() { return (fType == T_EOF); } @@ -96,6 +99,7 @@ public boolean isEOF() { /* * @see IToken#isWhitespace() */ + @Override public boolean isWhitespace() { return (fType == T_WHITESPACE); } @@ -103,6 +107,7 @@ public boolean isWhitespace() { /* * @see IToken#isUndefined() */ + @Override public boolean isUndefined() { return (fType == T_UNDEFINED); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditor.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditor.java index 9becea3e0ce..ef7e125290e 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditor.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditor.java @@ -45,6 +45,7 @@ public interface TextEditor extends EditorPartPresenter { /** * @return the text editor view implementation */ + @Override TextEditorPartView getView(); /** @@ -66,6 +67,7 @@ public interface TextEditor extends EditorPartPresenter { * @param save * true if unsaved changed should be saved, and false if unsaved changed should be discarded */ + @Override void close(boolean save); /** diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorPresenter.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorPresenter.java index f47803ba765..95e602360a4 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorPresenter.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/TextEditorPresenter.java @@ -853,6 +853,7 @@ public EditorWidget getEditorWidget() { return this.editorWidget; } + @Override public boolean isFocused() { return this.isFocused; } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/HttpSessionDestroyedEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/HttpSessionDestroyedEvent.java index cd1d0458e88..d83f8b75cfc 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/HttpSessionDestroyedEvent.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/HttpSessionDestroyedEvent.java @@ -20,10 +20,12 @@ public class HttpSessionDestroyedEvent extends GwtEvent { public static Type TYPE = new Type(); + @Override public Type getAssociatedType() { return TYPE; } + @Override protected void dispatch(HttpSessionDestroyedHandler handler) { handler.onHttpSessionDestroyed(this); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java index 2e2fede2869..5ab0521742d 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java @@ -69,6 +69,7 @@ public boolean isDev() { return true; } + @Override public String getType() { return devMachineDescriptor.getConfig().getType(); } @@ -95,6 +96,7 @@ public String getWsAgentWebSocketUrl() { throw new RuntimeException(message); } + @Override public String getTerminalUrl() { for (Link link : devMachineLinks) { if (Constants.TERMINAL_REFERENCE.equals(link.getRel())) { @@ -153,6 +155,7 @@ public MachineConfig getConfig() { return machineConfig; } + @Override public String getId() { return devMachineDescriptor.getId(); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorPartStack.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorPartStack.java index a3af4394c0c..5b030530666 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorPartStack.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/EditorPartStack.java @@ -99,5 +99,6 @@ public interface EditorPartStack extends PartStack { * * @return the parts list. */ + @Override List getParts(); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java index 1e4b5be84ca..dda62d04982 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java @@ -267,6 +267,7 @@ public final void setContentWidget(Widget widget) { * @param title * part title */ + @Override public void setTitle(@NotNull String title) { titleLabel.setText(title); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/File.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/File.java index f7629acc6d5..a686f94f041 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/File.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/File.java @@ -33,24 +33,31 @@ public interface File extends Resource, VirtualFile, ModificationTracker { /** @see VirtualFile#getPath() */ + @Override String getPath(); /** @see VirtualFile#getDisplayName() */ + @Override String getDisplayName(); /** @see VirtualFile#getMediaType() */ + @Override String getMediaType(); /** @see VirtualFile#isReadOnly() */ + @Override boolean isReadOnly(); /** @see VirtualFile#getContentUrl() */ + @Override String getContentUrl(); /** @see VirtualFile#getContent() */ + @Override Promise getContent(); /** @see VirtualFile#updateContent(String) */ + @Override Promise updateContent(String content); /** From a7820faa96c9434a6a7b40135b2700aea3376f70 Mon Sep 17 00:00:00 2001 From: Vitaliy Guliy Date: Wed, 7 Dec 2016 19:50:24 +0200 Subject: [PATCH 68/74] CHE-3177 Properly maximize console and terminal tabs (#3304) * CHE-3177 Properly maximize console and terminal tabs Signed-off-by: Vitaliy Guliy * CHE-3177 Properly maximize console and terminal tabs Signed-off-by: Vitaliy Guliy --- .../api/parts/PartStackStateChangedEvent.java | 54 +++++++++++++++++++ .../ide/api/parts/PartStackUIResources.java | 4 ++ .../che/ide/api/parts/base/BaseView.java | 7 +-- .../che/ide/api/parts/maximize-part.svg | 18 +++++++ .../eclipse/che/ide/api/parts/partstack.css | 4 ++ .../che/ide/part/PartStackPresenter.java | 34 ++++++++++++ .../che/ide/part/PartStackPresenterTest.java | 3 +- .../che/ide/ui/multisplitpanel/SubPanel.java | 15 +++++- .../panel/SubPanelPresenter.java | 17 +++++- .../multisplitpanel/panel/SubPanelView.java | 4 ++ .../panel/SubPanelViewImpl.java | 9 ++++ .../che/ide/ui/multisplitpanel/tab/Tab.java | 11 ++-- .../ide/ui/multisplitpanel/tab/TabWidget.java | 8 +++ .../terminal/TerminalViewImpl.java | 9 +++- .../panel/ProcessesPanelPresenter.java | 28 +++++++++- .../processes/panel/ProcessesPanelView.java | 12 ++++- .../panel/ProcessesPanelViewImpl.java | 12 +++++ .../panel/ProcessesPanelPresenterTest.java | 2 +- 18 files changed, 236 insertions(+), 15 deletions(-) create mode 100644 ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackStateChangedEvent.java create mode 100644 ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/maximize-part.svg diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackStateChangedEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackStateChangedEvent.java new file mode 100644 index 00000000000..66d9e13f8e8 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackStateChangedEvent.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.ide.api.parts; + +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; + +/** + * Is fired when a part stack state is changed. + * + * @author Vitaliy Guliy + */ +public class PartStackStateChangedEvent extends GwtEvent { + + /** + * Implement to handle changing the part stack state. + */ + public interface Handler extends EventHandler { + + void onPartStackStateChanged(PartStackStateChangedEvent event); + + } + + public static final GwtEvent.Type TYPE = new GwtEvent.Type(); + + private PartStack partStack; + + public PartStackStateChangedEvent(PartStack partStack) { + this.partStack = partStack; + } + + public PartStack getPartStack() { + return partStack; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(Handler handler) { + handler.onPartStackStateChanged(this); + } + +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackUIResources.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackUIResources.java index d5947c26a4b..e9f8b5e38a5 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackUIResources.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/PartStackUIResources.java @@ -71,4 +71,8 @@ interface PartStackCss extends CssResource { @Source("close-icon.svg") SVGResource closeIcon(); + + @Source("maximize-part.svg") + SVGResource maximizePart(); + } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java index dda62d04982..94deaab4d26 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/parts/base/BaseView.java @@ -109,8 +109,8 @@ public void onMouseUp(MouseUpEvent event) { titleLabel.setStyleName(resources.partStackCss().ideBasePartTitleLabel()); toolbarHeader.addWest(titleLabel, 200); - addMinimizeButton(); addMaximizeButton(); + addMinimizeButton(); /** * Handle double clicking on the toolbar header @@ -145,8 +145,9 @@ public void onClick(ClickEvent event) { } private void addMaximizeButton() { - ToolButton maximizeButton = new ToolButton(FontAwesome.ARROWS_ALT); - maximizeButton.getElement().setAttribute("name", "maximizePart"); + SVGImage maximize = new SVGImage(resources.maximizePart()); + maximize.getElement().setAttribute("name", "workBenchIconMaximize"); + ToolButton maximizeButton = new ToolButton(maximize); maximizeButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { diff --git a/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/maximize-part.svg b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/maximize-part.svg new file mode 100644 index 00000000000..468c38482cb --- /dev/null +++ b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/maximize-part.svg @@ -0,0 +1,18 @@ + + + + + + + diff --git a/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css index 4f8b9267a37..d8eb6f28558 100644 --- a/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css +++ b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/parts/partstack.css @@ -132,6 +132,10 @@ div[maximized="true"] div[name="maximizePart"] i { color: blueIconColor; } +div[maximized="true"] svg[name="workBenchIconMaximize"] { + fill: blueIconColor; +} + .ide-Base-Part-Title-Label { display: inline-block; line-height: 20px; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java index 050931daa33..56d7d47f456 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/PartStackPresenter.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.ide.part; +import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; @@ -22,6 +23,7 @@ import org.eclipse.che.ide.api.mvp.Presenter; import org.eclipse.che.ide.api.parts.PartPresenter; import org.eclipse.che.ide.api.parts.PartStack; +import org.eclipse.che.ide.api.parts.PartStackStateChangedEvent; import org.eclipse.che.ide.api.parts.PartStackView; import org.eclipse.che.ide.api.parts.PartStackView.TabItem; import org.eclipse.che.ide.api.parts.PropertyListener; @@ -296,6 +298,14 @@ public void maximize() { if (delegate != null) { delegate.onMaximize(this); } + + // Notify the part stack state has been changed. + Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { + @Override + public void execute() { + eventBus.fireEvent(new PartStackStateChangedEvent(PartStackPresenter.this)); + } + }); } @Override @@ -317,6 +327,14 @@ public void collapse() { if (activeTab != null) { activeTab.unSelect(); } + + // Notify the part stack state has been changed. + Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { + @Override + public void execute() { + eventBus.fireEvent(new PartStackStateChangedEvent(PartStackPresenter.this)); + } + }); } @Override @@ -347,6 +365,14 @@ public void minimize() { if (activeTab != null) { activeTab.unSelect(); } + + // Notify the part stack state has been changed. + Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { + @Override + public void execute() { + eventBus.fireEvent(new PartStackStateChangedEvent(PartStackPresenter.this)); + } + }); } @Override @@ -375,6 +401,14 @@ public void restore() { if (activeTab != null) { activeTab.select(); } + + // Notify the part stack state has been changed. + Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { + @Override + public void execute() { + eventBus.fireEvent(new PartStackStateChangedEvent(PartStackPresenter.this)); + } + }); } /** {@inheritDoc} */ diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/PartStackPresenterTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/PartStackPresenterTest.java index c0268966bb5..eca809febde 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/PartStackPresenterTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/PartStackPresenterTest.java @@ -11,6 +11,7 @@ package org.eclipse.che.ide.part; import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.api.constraints.Constraints; @@ -51,7 +52,7 @@ * @author Roman Nikitenko * @author Dmitry Shnurenko */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(GwtMockitoTestRunner.class) public class PartStackPresenterTest { private static final String SOME_TEXT = "someText"; diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java index c162d12e1d9..4d080af6563 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java @@ -77,6 +77,12 @@ public interface SubPanel { */ void setFocusListener(FocusListener listener); + /** + * Set the listener to be notified when some widget on + * this panel or on any child sub-panel was double clicked. + */ + void setDoubleClickListener(DoubleClickListener listener); + interface WidgetRemovingListener { /** Invoked when a widget is going to be removed. */ @@ -91,8 +97,15 @@ interface RemoveCallback { } interface FocusListener { - /** Invoked when a {@code widget} on a {@code panel} gains the focus. */ void focusGained(SubPanel panel, IsWidget widget); } + + interface DoubleClickListener { + + /** Invoked when a {@code widget} on a {@code panel} was double clicked. */ + void onDoubleClicked(SubPanel panel, IsWidget widget); + + } + } diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelPresenter.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelPresenter.java index f66772b0cc5..3671303bae1 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelPresenter.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelPresenter.java @@ -40,8 +40,8 @@ public class SubPanelPresenter implements SubPanel, SubPanelView.ActionDelegate private final List widgets; private final Map removingListeners; - private FocusListener focusListener; - + private FocusListener focusListener; + private DoubleClickListener doubleClickListener; @AssistedInject public SubPanelPresenter(SubPanelFactory subPanelFactory, SubPanelViewFactory subPanelViewFactory) { @@ -81,6 +81,7 @@ public SubPanelView getView() { public void splitHorizontally() { final SubPanel subPanel = subPanelFactory.newPanel(this); subPanel.setFocusListener(focusListener); + subPanel.setDoubleClickListener(doubleClickListener); view.splitHorizontally(subPanel.getView()); } @@ -88,6 +89,7 @@ public void splitHorizontally() { public void splitVertically() { final SubPanel subPanel = subPanelFactory.newPanel(this); subPanel.setFocusListener(focusListener); + subPanel.setDoubleClickListener(doubleClickListener); view.splitVertically(subPanel.getView()); } @@ -134,11 +136,21 @@ public void setFocusListener(FocusListener listener) { focusListener = listener; } + @Override + public void setDoubleClickListener(DoubleClickListener listener) { + doubleClickListener = listener; + } + @Override public void onWidgetFocused(IsWidget widget) { focusListener.focusGained(this, widget); } + @Override + public void onWidgetDoubleClicked(IsWidget widget) { + doubleClickListener.onDoubleClicked(this, widget); + } + @Override public void onWidgetRemoving(IsWidget widget, RemoveCallback removeCallback) { final WidgetRemovingListener listener = removingListeners.remove(widget); @@ -146,4 +158,5 @@ public void onWidgetRemoving(IsWidget widget, RemoveCallback removeCallback) { listener.onWidgetRemoving(removeCallback); } } + } diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelView.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelView.java index 27c6bd6b1d7..37a91056e10 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelView.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelView.java @@ -68,7 +68,11 @@ interface ActionDelegate { /** Called when the {@code widget} gains the focus. */ void onWidgetFocused(IsWidget widget); + /** Called when the widget tab was double clicked. */ + void onWidgetDoubleClicked(IsWidget widget); + /** Called when the {@code widget} is going to be removed from the panel. */ void onWidgetRemoving(IsWidget widget, SubPanel.RemoveCallback removeCallback); } + } diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelViewImpl.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelViewImpl.java index b6919d86d7d..17853e89107 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelViewImpl.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/panel/SubPanelViewImpl.java @@ -319,6 +319,15 @@ public void onTabClicked(Tab tab) { } } + @Override + public void onTabDoubleClicked(Tab tab) { + final WidgetToShow widget = tabs2Widgets.get(tab); + if (widget != null) { + activateWidget(widget); + delegate.onWidgetDoubleClicked(widget.getWidget()); + } + } + private void selectTab(Tab tab) { for (Tab tabItem : tabs2Widgets.keySet()) { tabItem.unSelect(); diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/Tab.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/Tab.java index a7660408003..2204e44b526 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/Tab.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/Tab.java @@ -12,6 +12,7 @@ import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DoubleClickHandler; import org.eclipse.che.ide.api.mvp.View; import org.eclipse.che.ide.ui.multisplitpanel.SubPanel; import org.vectomatic.dom.svg.ui.SVGResource; @@ -21,7 +22,7 @@ * * @author Artem Zatsarynnyi */ -public interface Tab extends View, ClickHandler { +public interface Tab extends View, ClickHandler, DoubleClickHandler { /** Returns the icon associated with tab. */ SVGResource getIcon(); @@ -35,10 +36,14 @@ public interface Tab extends View, ClickHandler { interface ActionDelegate { - /** Called when {@code tab} is clicked. */ + /** Is called when {@code tab} is clicked. */ void onTabClicked(Tab tab); - /** Called when {@code tab} is going to be closed. */ + /** Is called when {@code tab} is double clicked. */ + void onTabDoubleClicked(Tab tab); + + /** Is called when {@code tab} is going to be closed. */ void onTabClosing(Tab tab); } + } diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/TabWidget.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/TabWidget.java index ebea253221b..8b7c682fff8 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/TabWidget.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/tab/TabWidget.java @@ -14,6 +14,7 @@ import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DoubleClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; @@ -69,6 +70,7 @@ public TabWidget(PartStackUIResources resources, @Assisted String title, @Assist iconPanel.add(new SVGImage(getIcon())); addDomHandler(this, ClickEvent.getType()); + addDomHandler(this, DoubleClickEvent.getType()); if (closable) { closeButton.addDomHandler(new ClickHandler() { @@ -111,6 +113,11 @@ public void onClick(@NotNull ClickEvent event) { } } + @Override + public void onDoubleClick(DoubleClickEvent event) { + delegate.onTabDoubleClicked(this); + } + @Override public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; @@ -118,4 +125,5 @@ public void setDelegate(ActionDelegate delegate) { interface TabItemWidgetUiBinder extends UiBinder { } + } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java index 624e400c807..65814f01ee2 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/perspective/terminal/TerminalViewImpl.java @@ -18,6 +18,7 @@ import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Focusable; import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.Widget; import javax.validation.constraints.NotNull; @@ -27,7 +28,7 @@ * * @author Dmitry Shnurenko */ -final class TerminalViewImpl extends Composite implements TerminalView, Focusable { +final class TerminalViewImpl extends Composite implements TerminalView, Focusable, RequiresResize { interface TerminalViewImplUiBinder extends UiBinder { } @@ -76,6 +77,12 @@ public void showErrorMessage(@NotNull String message) { terminalPanel.setVisible(false); } + @Override + public void onResize() { + resizeTimer.cancel(); + resizeTimer.schedule(200); + } + private Timer resizeTimer = new Timer() { @Override public void run() { diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java index cfa18efb0d3..4d20b72fb64 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java @@ -47,6 +47,7 @@ import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.outputconsole.OutputConsole; import org.eclipse.che.ide.api.parts.PartStack; +import org.eclipse.che.ide.api.parts.PartStackStateChangedEvent; import org.eclipse.che.ide.api.parts.PartStackType; import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.parts.base.BasePresenter; @@ -74,10 +75,10 @@ import org.vectomatic.dom.svg.ui.SVGResource; import javax.validation.constraints.NotNull; -import java.util.HashMap; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -107,7 +108,8 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP MachineStateEvent.Handler, WsAgentStateHandler, EnvironmentOutputEvent.Handler, - DownloadWorkspaceOutputEvent.Handler { + DownloadWorkspaceOutputEvent.Handler, + PartStackStateChangedEvent.Handler { public static final String SSH_PORT = "22"; private static final String DEFAULT_TERMINAL_NAME = "Terminal"; @@ -189,6 +191,7 @@ public ProcessesPanelPresenter(ProcessesPanelView view, eventBus.addHandler(MachineStateEvent.TYPE, this); eventBus.addHandler(EnvironmentOutputEvent.TYPE, this); eventBus.addHandler(DownloadWorkspaceOutputEvent.TYPE, this); + eventBus.addHandler(PartStackStateChangedEvent.TYPE, this); updateMachineList(); @@ -1006,6 +1009,27 @@ public void onProcessFinished(ProcessFinishedEvent event) { } } + @Override + public void onToggleMaximizeConsole() { + super.onToggleMaximize(); + + if (partStack != null) { + if (partStack.getPartStackState() == PartStack.State.MAXIMIZED) { + view.setProcessesTreeVisible(false); + } else { + view.setProcessesTreeVisible(true); + } + } + } + + @Override + public void onPartStackStateChanged(PartStackStateChangedEvent event) { + if (partStack.equals(event.getPartStack()) && + partStack.getPartStackState() == PartStack.State.NORMAL) { + view.setProcessesTreeVisible(true); + } + } + /** * Prints text to the machine console. * diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java index c7c5df627e5..573791845f3 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelView.java @@ -90,6 +90,9 @@ public interface ProcessesPanelView extends View implements ProcessesPanelView, SubPanel.FocusListener, + SubPanel.DoubleClickListener, RequiresResize { @UiField(provided = true) @@ -195,6 +196,7 @@ public void onKeyboard(KeyboardEvent event) { final SubPanel subPanel = subPanelFactory.newPanel(); subPanel.setFocusListener(this); + subPanel.setDoubleClickListener(this); splitLayoutPanel.add(subPanel.getView()); focusedSubPanel = subPanel; @@ -489,6 +491,11 @@ public void focusGained(SubPanel subPanel, IsWidget widget) { } } + @Override + public void onDoubleClicked(final SubPanel panel, final IsWidget widget) { + delegate.onToggleMaximizeConsole(); + } + @Override public void onResize() { for (WidgetToShow widgetToShow : widget2Panels.keySet()) { @@ -499,6 +506,11 @@ public void onResize() { } } + @Override + public void setProcessesTreeVisible(boolean visible) { + splitLayoutPanel.setWidgetHidden(navigationPanel, !visible); + } + interface ProcessesPartViewImplUiBinder extends UiBinder { } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java index a5003fd68a0..cd87bc8be3d 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java @@ -190,7 +190,7 @@ public void shouldAddMachineWhenMachineCreating() throws Exception { MachineStateEvent machineStateEvent = mock(MachineStateEvent.class); when(machineStateEvent.getMachine()).thenReturn(machine); - verify(eventBus, times(7)).addHandler(anyObject(), machineStateHandlerCaptor.capture()); + verify(eventBus, times(8)).addHandler(anyObject(), machineStateHandlerCaptor.capture()); MachineStateEvent.Handler machineStateHandler = machineStateHandlerCaptor.getAllValues().get(0); machineStateHandler.onMachineCreating(machineStateEvent); From e7befbacc37958d08f1a9de23e602d1841208182 Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Wed, 7 Dec 2016 20:11:16 +0200 Subject: [PATCH 69/74] set nightly versions for M9-SN iteration (#3315) * set nightly versions for M9-SN iteration --- dockerfiles/action/Dockerfile | 2 +- dockerfiles/cli/Dockerfile | 2 +- dockerfiles/dir/Dockerfile | 2 +- dockerfiles/lib/dto-pom.xml | 4 ++-- dockerfiles/test/Dockerfile | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dockerfiles/action/Dockerfile b/dockerfiles/action/Dockerfile index 7ec902cd3b2..fb41f7e3290 100644 --- a/dockerfiles/action/Dockerfile +++ b/dockerfiles/action/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-action [command] -FROM eclipse/che-lib:5.0.0-M8 +FROM eclipse/che-lib:nightly ENTRYPOINT ["node", "/che-lib/index.js", "che-action"] diff --git a/dockerfiles/cli/Dockerfile b/dockerfiles/cli/Dockerfile index 530565128eb..6c84027ec7b 100644 --- a/dockerfiles/cli/Dockerfile +++ b/dockerfiles/cli/Dockerfile @@ -9,7 +9,7 @@ # # use: # docker run -v $(pwd):/che eclipse/che-cli [command] -FROM eclipse/che-base:5.0.0-M8 +FROM eclipse/che-base:nightly COPY scripts /scripts/ COPY version /version/ diff --git a/dockerfiles/dir/Dockerfile b/dockerfiles/dir/Dockerfile index 61c4c2118e7..26c1d378df4 100644 --- a/dockerfiles/dir/Dockerfile +++ b/dockerfiles/dir/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-dir [command] -FROM eclipse/che-lib:5.0.0-M8 +FROM eclipse/che-lib:nightly ENTRYPOINT ["node", "/che-lib/index.js", "che-dir"] diff --git a/dockerfiles/lib/dto-pom.xml b/dockerfiles/lib/dto-pom.xml index 4108a8f7a65..07e6bd82f7c 100644 --- a/dockerfiles/lib/dto-pom.xml +++ b/dockerfiles/lib/dto-pom.xml @@ -17,13 +17,13 @@ maven-depmgt-pom org.eclipse.che.depmgt - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT dto-typescript pom Che TypeScript DTO - 5.0.0-M8 + 5.0.0-M9-SNAPSHOT diff --git a/dockerfiles/test/Dockerfile b/dockerfiles/test/Dockerfile index 6e95735574d..260b89138c8 100644 --- a/dockerfiles/test/Dockerfile +++ b/dockerfiles/test/Dockerfile @@ -10,6 +10,6 @@ # use: # docker run -v /var/run/docker.sock:/var/run/docker.sock eclipse/che-test [command] -FROM eclipse/che-lib:5.0.0-M8 +FROM eclipse/che-lib:nightly ENTRYPOINT ["node", "/che-lib/index.js", "che-test"] From d7a019c0d0dddfb42383ec14a31011cca8ea6b96 Mon Sep 17 00:00:00 2001 From: Ann Shumilova Date: Mon, 28 Nov 2016 12:29:14 +0200 Subject: [PATCH 70/74] CHE-3183: avoid using includes function Signed-off-by: Ann Shumilova --- .../projects/create-project/create-project.controller.ts | 2 +- .../add-port-dialog/add-port-dialog.controller.ts | 4 ++-- .../edit-port-dialog/edit-port-dialog.controller.ts | 2 +- .../edit-machine-name-dialog.controller.ts | 2 +- .../workspace-details/workspace-details.controller.ts | 2 +- dashboard/src/components/api/che-workspace.factory.ts | 4 ++-- .../api/environment/compose-environment-manager.ts | 2 +- .../src/components/api/environment/docker-file-parser.ts | 2 +- .../src/components/api/environment/environment-manager.ts | 6 +++--- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dashboard/src/app/projects/create-project/create-project.controller.ts b/dashboard/src/app/projects/create-project/create-project.controller.ts index 61463511546..6d9f971d305 100755 --- a/dashboard/src/app/projects/create-project/create-project.controller.ts +++ b/dashboard/src/app/projects/create-project/create-project.controller.ts @@ -1223,7 +1223,7 @@ export class CreateProjectController { isResourceProblem(): boolean { let currentCreationStep = this.getCreationSteps()[this.getCurrentProgressStep()]; - return currentCreationStep.hasError && currentCreationStep.logs.includes('You can stop other workspaces'); + return currentCreationStep.hasError && currentCreationStep.logs.indexOf('You can stop other workspaces') >= 0; } setStackTab(stackTab: string): void { diff --git a/dashboard/src/app/workspaces/workspace-details/environments/list-ports/add-port-dialog/add-port-dialog.controller.ts b/dashboard/src/app/workspaces/workspace-details/environments/list-ports/add-port-dialog/add-port-dialog.controller.ts index ccaae1a133e..b358d0d5532 100644 --- a/dashboard/src/app/workspaces/workspace-details/environments/list-ports/add-port-dialog/add-port-dialog.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/environments/list-ports/add-port-dialog/add-port-dialog.controller.ts @@ -37,7 +37,7 @@ export class AddPortDialogController { } isUnique(port) { - return !this.usedPorts.includes(port); + return this.usedPorts.indexOf(port) < 0; } fillInUsedPorts() { @@ -49,7 +49,7 @@ export class AddPortDialogController { getLowestFreePort() { let port; for (port=this.portMin; port<=this.portMax; port++) { - if (!this.usedPorts.includes(port)) { + if (this.usedPorts.indexOf(port) < 0) { break; } } diff --git a/dashboard/src/app/workspaces/workspace-details/environments/list-ports/edit-port-dialog/edit-port-dialog.controller.ts b/dashboard/src/app/workspaces/workspace-details/environments/list-ports/edit-port-dialog/edit-port-dialog.controller.ts index 21dff787ac2..66be432bc94 100644 --- a/dashboard/src/app/workspaces/workspace-details/environments/list-ports/edit-port-dialog/edit-port-dialog.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/environments/list-ports/edit-port-dialog/edit-port-dialog.controller.ts @@ -35,7 +35,7 @@ export class EditPortDialogController { } isUnique(port) { - return !this.usedPorts.includes(port); + return this.usedPorts.indexOf(port) < 0; } fillInUsedPorts() { diff --git a/dashboard/src/app/workspaces/workspace-details/environments/machine-config/edit-machine-name-dialog/edit-machine-name-dialog.controller.ts b/dashboard/src/app/workspaces/workspace-details/environments/machine-config/edit-machine-name-dialog/edit-machine-name-dialog.controller.ts index 8190f997d11..e0eb0109763 100644 --- a/dashboard/src/app/workspaces/workspace-details/environments/machine-config/edit-machine-name-dialog/edit-machine-name-dialog.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/environments/machine-config/edit-machine-name-dialog/edit-machine-name-dialog.controller.ts @@ -27,7 +27,7 @@ export class EditMachineNameDialogController { } isUnique(name) { - return !this.machinesNames.includes(name); + return this.machinesNames.indexOf(name) < 0; } /** diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts index cbff108002e..94ec3da67ab 100644 --- a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts @@ -402,7 +402,7 @@ export class WorkspaceDetailsController { iterations = 100; while (iterations--) { name = 'wksp-' + (('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)); // jshint ignore:line - if (!this.usedNamesList.includes(name)) { + if (!this.usedNamesList.indexOf(name) >= 0) { break; } } diff --git a/dashboard/src/components/api/che-workspace.factory.ts b/dashboard/src/components/api/che-workspace.factory.ts index 34cd61aa234..51edae6eaa4 100644 --- a/dashboard/src/components/api/che-workspace.factory.ts +++ b/dashboard/src/components/api/che-workspace.factory.ts @@ -291,7 +291,7 @@ export class CheWorkspace { } let devMachine = this.lodash.find(defaultEnvironment.machines, (machine) => { - return machine.agents.includes('org.eclipse.che.ws-agent'); + return machine.agents.indexOf('org.eclipse.che.ws-agent') >= 0; }); // check dev machine is provided and add if there is no: @@ -482,7 +482,7 @@ export class CheWorkspace { * @param workspaceId */ startUpdateWorkspaceStatus(workspaceId) { - if (!this.subscribedWorkspacesIds.includes(workspaceId)) { + if (this.subscribedWorkspacesIds.indexOf(workspaceId) < 0) { let bus = this.cheWebsocket.getBus(); this.subscribedWorkspacesIds.push(workspaceId); diff --git a/dashboard/src/components/api/environment/compose-environment-manager.ts b/dashboard/src/components/api/environment/compose-environment-manager.ts index 008228d9618..036c2321018 100644 --- a/dashboard/src/components/api/environment/compose-environment-manager.ts +++ b/dashboard/src/components/api/environment/compose-environment-manager.ts @@ -100,7 +100,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager { let services: any = Object.keys(recipe.services); services.forEach((serviceName: string) => { let serviceFields: any = Object.keys(recipe.services[serviceName] || {}); - if (!serviceFields || (serviceFields.includes('build') === false && serviceFields.includes('image') === false)) { + if (!serviceFields || (serviceFields.indexOf('build') < 0 && serviceFields.indexOf('image') < 0)) { throw new Error('Service \'' + serviceName + '\' should contain \'build\' or \'image\' section.'); } }); diff --git a/dashboard/src/components/api/environment/docker-file-parser.ts b/dashboard/src/components/api/environment/docker-file-parser.ts index 7f237dc4ac8..41d8e203e18 100644 --- a/dashboard/src/components/api/environment/docker-file-parser.ts +++ b/dashboard/src/components/api/environment/docker-file-parser.ts @@ -116,7 +116,7 @@ export class DockerfileParser { switch (instruction) { case 'ENV': - if (argumentStr.includes('=')) { + if (argumentStr.indexOf('=') >= 0) { // this argument string contains one or more environment variables let match; while (match = this.envVariablesRE.exec(argumentStr)) { diff --git a/dashboard/src/components/api/environment/environment-manager.ts b/dashboard/src/components/api/environment/environment-manager.ts index 3a9930e84ea..7dafe322d54 100644 --- a/dashboard/src/components/api/environment/environment-manager.ts +++ b/dashboard/src/components/api/environment/environment-manager.ts @@ -104,7 +104,7 @@ export class EnvironmentManager { * @returns {boolean} */ isDev(machine: any): boolean { - return machine.agents && machine.agents.includes(WS_AGENT_NAME); + return machine.agents && machine.agents.indexOf(WS_AGENT_NAME) >= 0; } /** @@ -120,10 +120,10 @@ export class EnvironmentManager { if (!hasWsAgent) { machine.agents.push(WS_AGENT_NAME); } - if (!machine.agents.includes(SSH_AGENT_NAME)) { + if (machine.agents.indexOf(SSH_AGENT_NAME) < 0) { machine.agents.push(SSH_AGENT_NAME); } - if (!machine.agents.includes(TERMINAL_AGENT_NAME)) { + if (machine.agents.indexOf(TERMINAL_AGENT_NAME) < 0) { machine.agents.push(TERMINAL_AGENT_NAME); } return; From 255340768828174db3716b390fb30ae2443f97ce Mon Sep 17 00:00:00 2001 From: Ann Shumilova Date: Fri, 25 Nov 2016 09:56:20 +0200 Subject: [PATCH 71/74] Define tests phase for dashboard and skip condition Signed-off-by: Ann Shumilova --- dashboard/pom.xml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dashboard/pom.xml b/dashboard/pom.xml index 63a4d839843..a14e2f41964 100644 --- a/dashboard/pom.xml +++ b/dashboard/pom.xml @@ -70,10 +70,6 @@ - - - - @@ -86,6 +82,21 @@ + + compilation + test + + run + + + + + + + + + + From 25ae094ba7d4489f29828c459f7b6b9c25bfb943 Mon Sep 17 00:00:00 2001 From: Anatoliy Bazko Date: Thu, 8 Dec 2016 12:25:31 +0200 Subject: [PATCH 72/74] Zend Debugger for PHP (#3202) --- assembly/assembly-ide-war/pom.xml | 4 + .../resources/org/eclipse/che/ide/IDE.gwt.xml | 1 + assembly/assembly-wsagent-war/pom.xml | 4 + .../debugger/ide/debug/ActiveFileHandler.java | 15 +- .../ide/debug/BasicActiveFileHandler.java} | 135 ++-- .../che/plugin/gdb/ide/GdbDebugger.java | 3 +- .../gdb/ide/GdbDebuggerFileHandler.java | 143 ---- .../che-java-testing-core-ide/pom.xml | 28 +- .../plugin/nodejsdbg/ide/NodeJsDebugger.java | 3 +- plugins/plugin-zend-debugger/README.md | 49 ++ .../che-plugin-zend-debugger-ide/pom.xml | 120 +++ .../che/plugin/zdb/ide/ZendDbgExtension.java | 32 + .../che/plugin/zdb/ide/ZendDbgGinModule.java | 37 + .../zdb/ide/ZendDbgLocalizationConstant.java | 35 + .../che/plugin/zdb/ide/ZendDbgResources.java | 28 + .../che/plugin/zdb/ide/ZendDebugger.java | 78 ++ .../ZendDbgConfigurationPagePresenter.java | 129 +++ .../ZendDbgConfigurationPageView.java | 102 +++ .../ZendDbgConfigurationPageViewImpl.java | 138 ++++ .../ZendDbgConfigurationPageViewImpl.ui.xml | 29 + .../ZendDbgConfigurationType.java | 76 ++ .../che/plugin/zdb/ZendDebugger.gwt.xml | 23 + .../ZendDbgLocalizationConstant.properties | 15 + .../zend-dbg-configuration-type.svg | 20 + ...ZendDbgConfigurationPagePresenterTest.java | 140 ++++ .../ZendDbgConfigurationTypeTest.java | 62 ++ .../src/test/resources/logback-test.xml | 23 + .../che-plugin-zend-debugger-server/pom.xml | 130 +++ .../che/plugin/zdb/server/ZendDbgFactory.java | 79 ++ .../zdb/server/ZendDbgLocationHandler.java | 67 ++ .../che/plugin/zdb/server/ZendDbgModule.java | 34 + .../che/plugin/zdb/server/ZendDebugger.java | 500 ++++++++++++ .../server/connection/AbstractDbgMessage.java | 36 + .../zdb/server/connection/IDbgMessage.java | 45 ++ .../connection/ZendDbgClientMessages.java | 507 ++++++++++++ .../server/connection/ZendDbgConnection.java | 354 +++++++++ .../connection/ZendDbgEngineMessages.java | 744 ++++++++++++++++++ .../server/connection/ZendDbgSettings.java | 69 ++ .../exceptions/ZendDbgTimeoutException.java | 30 + .../zdb/server/expressions/IDbgDataFacet.java | 47 ++ .../zdb/server/expressions/IDbgDataType.java | 63 ++ .../server/expressions/IDbgExpression.java | 69 ++ .../server/expressions/ZendDbgExpression.java | 105 +++ .../ZendDbgExpressionEvaluator.java | 319 ++++++++ .../expressions/ZendDbgExpressionResult.java | 86 ++ .../server/utils/ZendDbgConnectionUtils.java | 206 +++++ .../zdb/server/utils/ZendDbgFileUtils.java | 91 +++ .../server/utils/ZendDbgVariableUtils.java | 49 ++ .../zdb/server/variables/IDbgVariable.java | 39 + .../zdb/server/variables/ZendDbgVariable.java | 127 +++ .../server/variables/ZendDbgVariables.java | 49 ++ .../server/AbstractZendDbgSessionTest.java | 105 +++ .../zdb/server/ZendDbgAvailabilityTest.java | 63 ++ .../zdb/server/ZendDbgConfigurationTest.java | 50 ++ .../plugin/zdb/server/ZendDbgSessionTest.java | 195 +++++ .../src/test/resources/findbugs-exclude.xml | 14 + .../src/test/resources/logback-test.xml | 23 + .../src/test/resources/php/classes.php | 28 + .../src/test/resources/php/hello.php | 10 + plugins/plugin-zend-debugger/pom.xml | 51 ++ plugins/pom.xml | 1 + pom.xml | 10 + 62 files changed, 5650 insertions(+), 217 deletions(-) rename plugins/{plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebuggerFileHandler.java => plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/BasicActiveFileHandler.java} (54%) delete mode 100644 plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebuggerFileHandler.java create mode 100644 plugins/plugin-zend-debugger/README.md create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/pom.xml create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgExtension.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgGinModule.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgResources.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDebugger.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenter.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageView.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.ui.xml create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationType.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ZendDebugger.gwt.xml create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.properties create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/configuration/zend-dbg-configuration-type.svg create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenterTest.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationTypeTest.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/resources/logback-test.xml create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/pom.xml create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgFactory.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgLocationHandler.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgModule.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDebugger.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/AbstractDbgMessage.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/IDbgMessage.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgClientMessages.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgConnection.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgEngineMessages.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgSettings.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/exceptions/ZendDbgTimeoutException.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataFacet.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataType.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgExpression.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpression.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionEvaluator.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionResult.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgConnectionUtils.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgFileUtils.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgVariableUtils.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/IDbgVariable.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariable.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariables.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/AbstractZendDbgSessionTest.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgAvailabilityTest.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgConfigurationTest.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgSessionTest.java create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/findbugs-exclude.xml create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/logback-test.xml create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/classes.php create mode 100644 plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/hello.php create mode 100644 plugins/plugin-zend-debugger/pom.xml diff --git a/assembly/assembly-ide-war/pom.xml b/assembly/assembly-ide-war/pom.xml index 4662e4257af..213d799b606 100644 --- a/assembly/assembly-ide-war/pom.xml +++ b/assembly/assembly-ide-war/pom.xml @@ -260,6 +260,10 @@ org.eclipse.che.plugin che-plugin-web-ext-web + + org.eclipse.che.plugin + che-plugin-zend-debugger-ide + com.google.gwt gwt-user diff --git a/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml b/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml index 9cd5ab567ae..0b4c2246e12 100644 --- a/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml +++ b/assembly/assembly-ide-war/src/main/resources/org/eclipse/che/ide/IDE.gwt.xml @@ -46,6 +46,7 @@ + diff --git a/assembly/assembly-wsagent-war/pom.xml b/assembly/assembly-wsagent-war/pom.xml index 6722dbcb633..66ffaa72c0e 100644 --- a/assembly/assembly-wsagent-war/pom.xml +++ b/assembly/assembly-wsagent-war/pom.xml @@ -224,6 +224,10 @@ org.eclipse.che.plugin che-plugin-svn-ext-server + + org.eclipse.che.plugin + che-plugin-zend-debugger-server + org.everrest everrest-core diff --git a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/ActiveFileHandler.java b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/ActiveFileHandler.java index 0c91f9fb72a..5e9baa012a0 100644 --- a/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/ActiveFileHandler.java +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/ActiveFileHandler.java @@ -12,23 +12,28 @@ import com.google.gwt.user.client.rpc.AsyncCallback; -import org.eclipse.che.ide.api.resources.VirtualFile; import org.eclipse.che.api.debug.shared.model.Location; +import org.eclipse.che.ide.api.resources.VirtualFile; /** - * Responsible to open files in editor when debugger stopped at breakpoint. + * Handles resources is being debugged. + * + * @see Location#getTarget() + * @see Location#getLineNumber() * * @author Anatoliy Bazko */ public interface ActiveFileHandler { /** - * Open file, scroll to the debug line and do some actions from {@code callback} + * Opens resource is being debugged and scrolls to the position {@link Location#getLineNumber()}. + * If resource has been found then {@link AsyncCallback#onSuccess(Object)} must be invoked + * and {@link AsyncCallback#onFailure(Throwable)} otherwise. * * @param location - * location to the source file. See more {@link Location} + * the location of the resource is being debugged * @param callback - * some action which should be performed after opening file + * the callback */ void openFile(Location location, AsyncCallback callback); } diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebuggerFileHandler.java b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/BasicActiveFileHandler.java similarity index 54% rename from plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebuggerFileHandler.java rename to plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/BasicActiveFileHandler.java index c42aad489fc..cea9f870707 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebuggerFileHandler.java +++ b/plugins/plugin-debugger/che-plugin-debugger-ide/src/main/java/org/eclipse/che/plugin/debugger/ide/debug/BasicActiveFileHandler.java @@ -8,13 +8,12 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.plugin.nodejsdbg.ide; +package org.eclipse.che.plugin.debugger.ide.debug; import com.google.common.base.Optional; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; -import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.debug.shared.model.Location; import org.eclipse.che.api.promises.client.Operation; @@ -26,100 +25,130 @@ import org.eclipse.che.ide.api.editor.document.Document; import org.eclipse.che.ide.api.editor.text.TextPosition; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; -import org.eclipse.che.ide.api.event.FileEvent; 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.api.resources.VirtualFile; -import org.eclipse.che.plugin.debugger.ide.debug.ActiveFileHandler; /** - * Responsible to open files in editor when debugger stopped at breakpoint. - * * @author Anatoliy Bazko */ -public class NodeJsDebuggerFileHandler implements ActiveFileHandler { +public class BasicActiveFileHandler implements ActiveFileHandler { private final EditorAgent editorAgent; - private final EventBus eventBus; private final AppContext appContext; @Inject - public NodeJsDebuggerFileHandler(EditorAgent editorAgent, - EventBus eventBus, - AppContext appContext) { + public BasicActiveFileHandler(EditorAgent editorAgent, AppContext appContext) { this.editorAgent = editorAgent; - this.eventBus = eventBus; this.appContext = appContext; } + /** + * Tries to open file in the editor. + * To perform the operation the following sequence of methods invocation are processed: + * + * {@link BasicActiveFileHandler#tryFindFileInProject(Location, AsyncCallback)} + * {@link BasicActiveFileHandler#tryFindFileInWorkspace(Location, AsyncCallback)} + * {@link BasicActiveFileHandler#trySearchSource(Location, AsyncCallback)} + * + * @see ActiveFileHandler#openFile(Location, AsyncCallback) + */ @Override public void openFile(final Location location, final AsyncCallback callback) { - final Resource resource = appContext.getResource(); + tryFindFileInProject(location, new AsyncCallback() { + @Override + public void onSuccess(VirtualFile virtualFile) { + callback.onSuccess(virtualFile); + } + + @Override + public void onFailure(Throwable caught) { + tryFindFileInWorkspace(location, new AsyncCallback() { + @Override + public void onSuccess(VirtualFile virtualFile) { + callback.onSuccess(virtualFile); + } + + @Override + public void onFailure(Throwable caught) { + trySearchSource(location, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + callback.onFailure(caught); + } + + @Override + public void onSuccess(VirtualFile result) { + callback.onSuccess(result); + } + }); + } + }); + } + }); + } + + protected void tryFindFileInProject(final Location location, + final AsyncCallback callback) { + Resource resource = appContext.getResource(); if (resource == null) { callback.onFailure(new IllegalStateException("Resource is undefined")); return; } - final Optional project = resource.getRelatedProject(); + + Optional project = resource.getRelatedProject(); if (!project.isPresent()) { callback.onFailure(new IllegalStateException("Project is undefined")); return; } - findFileInProject(project.get(), location, callback); - } - - private void findFileInProject(final Project project, - final Location location, - final AsyncCallback callback) { - project.getFile(location.getTarget()).then(new Operation>() { + project.get().getFile(location.getTarget()).then(new Operation>() { @Override public void apply(Optional file) throws OperationException { if (file.isPresent()) { - openFileInEditorAndScrollToLine(file.get(), callback, location.getLineNumber()); - callback.onSuccess(file.get()); + openFileAndScrollToLine(file.get(), location.getLineNumber(), callback); } else { - findFileInWorkspace(location, callback); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } } }).catchError(new Operation() { @Override - public void apply(PromiseError arg) throws OperationException { - callback.onFailure(new IllegalArgumentException("File not found." + arg.getMessage())); + public void apply(PromiseError error) throws OperationException { + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } }); } - private void findFileInWorkspace(final Location location, - final AsyncCallback callback) { + protected void tryFindFileInWorkspace(final Location location, + final AsyncCallback callback) { try { appContext.getWorkspaceRoot().getFile(location.getTarget()).then(new Operation>() { @Override public void apply(Optional file) throws OperationException { if (file.isPresent()) { - openFileInEditorAndScrollToLine(file.get(), callback, location.getLineNumber()); - callback.onSuccess(file.get()); + openFileAndScrollToLine(file.get(), location.getLineNumber(), callback); } else { - searchSource(location, callback); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } } }).catchError(new Operation() { @Override public void apply(PromiseError arg) throws OperationException { - callback.onFailure(new IllegalArgumentException("File not found." + arg.getMessage())); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } }); } catch (IllegalStateException ignored) { - searchSource(location, callback); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } } - private void searchSource(final Location location, final AsyncCallback callback) { + protected void trySearchSource(final Location location, final AsyncCallback callback) { appContext.getWorkspaceRoot().search(location.getTarget(), "").then(new Operation() { @Override public void apply(Resource[] resources) throws OperationException { if (resources.length == 0) { - callback.onFailure(new IllegalArgumentException("File not found.")); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); return; } @@ -127,37 +156,36 @@ public void apply(Resource[] resources) throws OperationException { @Override public void apply(Optional file) throws OperationException { if (file.isPresent()) { - openFileInEditorAndScrollToLine(file.get(), callback, location.getLineNumber()); - callback.onSuccess(file.get()); + openFileAndScrollToLine(file.get(), location.getLineNumber(), callback); } else { - callback.onFailure(new IllegalArgumentException("File not found.")); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } } }).catchError(new Operation() { @Override public void apply(PromiseError arg) throws OperationException { - callback.onFailure(new IllegalArgumentException("File not found. " + arg.getMessage())); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } }); } }).catchError(new Operation() { @Override public void apply(PromiseError arg) throws OperationException { - callback.onFailure(new IllegalArgumentException("File not found. " + arg.getMessage())); + callback.onFailure(new IllegalArgumentException(location.getTarget() + " not found.")); } }); } - private void openFileInEditorAndScrollToLine(final VirtualFile virtualFile, - final AsyncCallback callback, - final int scrollToLine) { + protected void openFileAndScrollToLine(final VirtualFile virtualFile, + final int scrollToLine, + final AsyncCallback callback) { editorAgent.openEditor(virtualFile, new EditorAgent.OpenEditorCallback() { @Override public void onEditorOpened(EditorPartPresenter editor) { new Timer() { @Override public void run() { - scrollEditorToExecutionPoint((TextEditor)editorAgent.getActiveEditor(), scrollToLine); + scrollToLine(editorAgent.getActiveEditor(), scrollToLine); callback.onSuccess(virtualFile); } }.schedule(300); @@ -168,7 +196,7 @@ public void onEditorActivated(EditorPartPresenter editor) { new Timer() { @Override public void run() { - scrollEditorToExecutionPoint((TextEditor)editorAgent.getActiveEditor(), scrollToLine); + scrollToLine(editorAgent.getActiveEditor(), scrollToLine); callback.onSuccess(virtualFile); } }.schedule(300); @@ -176,18 +204,19 @@ public void run() { @Override public void onInitializationFailed() { - callback.onFailure(null); + callback.onFailure(new IllegalStateException("Initialization " + virtualFile.getName() + " in the editor failed")); } }); - - eventBus.fireEvent(FileEvent.createOpenFileEvent(virtualFile)); } - private void scrollEditorToExecutionPoint(TextEditor editor, int lineNumber) { - Document document = editor.getDocument(); - if (document != null) { - TextPosition newPosition = new TextPosition(lineNumber, 0); - document.setCursorPosition(newPosition); + protected void scrollToLine(EditorPartPresenter editor, int lineNumber) { + if (editor instanceof TextEditor) { + TextEditor textEditor = (TextEditor)editor; + Document document = textEditor.getDocument(); + if (document != null) { + TextPosition newPosition = new TextPosition(lineNumber, 0); + document.setCursorPosition(newPosition); + } } } } diff --git a/plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebugger.java b/plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebugger.java index 2ed8e5b736c..8037cc3b226 100644 --- a/plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebugger.java +++ b/plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebugger.java @@ -28,6 +28,7 @@ import org.eclipse.che.ide.util.storage.LocalStorageProvider; import org.eclipse.che.ide.websocket.MessageBusProvider; import org.eclipse.che.plugin.debugger.ide.debug.AbstractDebugger; +import org.eclipse.che.plugin.debugger.ide.debug.BasicActiveFileHandler; import javax.validation.constraints.NotNull; import java.util.Map; @@ -52,7 +53,7 @@ public GdbDebugger(DebuggerServiceClient service, LocalStorageProvider localStorageProvider, MessageBusProvider messageBusProvider, EventBus eventBus, - GdbDebuggerFileHandler activeFileHandler, + BasicActiveFileHandler activeFileHandler, DebuggerManager debuggerManager, BreakpointManager breakpointManager, AppContext appContext) { diff --git a/plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebuggerFileHandler.java b/plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebuggerFileHandler.java deleted file mode 100644 index d32777bf15d..00000000000 --- a/plugins/plugin-gdb/che-plugin-gdb-ide/src/main/java/org/eclipse/che/plugin/gdb/ide/GdbDebuggerFileHandler.java +++ /dev/null @@ -1,143 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.plugin.gdb.ide; - -import com.google.common.base.Optional; -import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.inject.Inject; -import com.google.web.bindery.event.shared.EventBus; - -import org.eclipse.che.api.debug.shared.model.Location; -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.editor.EditorAgent; -import org.eclipse.che.ide.api.editor.EditorPartPresenter; -import org.eclipse.che.ide.api.editor.texteditor.TextEditor; -import org.eclipse.che.ide.api.event.FileEvent; -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.api.resources.VirtualFile; -import org.eclipse.che.ide.resource.Path; -import org.eclipse.che.plugin.debugger.ide.debug.ActiveFileHandler; -import org.eclipse.che.ide.api.editor.document.Document; -import org.eclipse.che.ide.api.editor.text.TextPosition; - -/** - * Responsible to open files in editor when debugger stopped at breakpoint. - * - * @author Anatoliy Bazko - */ -public class GdbDebuggerFileHandler implements ActiveFileHandler { - - private final EditorAgent editorAgent; - private final EventBus eventBus; - private final AppContext appContext; - - @Inject - public GdbDebuggerFileHandler(EditorAgent editorAgent, - EventBus eventBus, - AppContext appContext) { - this.editorAgent = editorAgent; - this.eventBus = eventBus; - this.appContext = appContext; - } - - @Override - public void openFile(final Location location, final AsyncCallback callback) { - final Resource resource = appContext.getResource(); - if (resource == null) { - callback.onFailure(new IllegalStateException("Resource is undefined")); - return; - } - final Optional project = resource.getRelatedProject(); - if (!project.isPresent()) { - callback.onFailure(new IllegalStateException("Project is undefined")); - return; - } - - final Path filePath = project.get().getLocation().append(location.getTarget()); - VirtualFile activeFile = null; - final EditorPartPresenter activeEditor = editorAgent.getActiveEditor(); - if (activeEditor != null) { - activeFile = activeEditor.getEditorInput().getFile(); - } - - if (activeEditor == null || !activeFile.getLocation().equals(filePath)) { - doOpenFile(filePath, location.getLineNumber(), callback); - } else { - scrollEditorToExecutionPoint((TextEditor)activeEditor, location.getLineNumber()); - callback.onSuccess(activeEditor.getEditorInput().getFile()); - } - } - - private void doOpenFile(final Path filePath, final int lineNumber, final AsyncCallback callback) { - appContext.getWorkspaceRoot().getFile(filePath).then(new Operation>() { - @Override - public void apply(Optional file) throws OperationException { - if (file.isPresent()) { - handleActivatedFile(file.get(), callback, lineNumber); - eventBus.fireEvent(FileEvent.createOpenFileEvent(file.get())); - } else { - callback.onFailure(new IllegalStateException("File is undefined")); - } - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - callback.onFailure(error.getCause()); - } - }); - } - - public void handleActivatedFile(final VirtualFile virtualFile, final AsyncCallback callback, final int debugLine) { - editorAgent.openEditor(virtualFile, new EditorAgent.OpenEditorCallback() { - @Override - public void onEditorOpened(EditorPartPresenter editor) { - new Timer() { - @Override - public void run() { - scrollEditorToExecutionPoint((TextEditor)editorAgent.getActiveEditor(), debugLine); - callback.onSuccess(virtualFile); - } - }.schedule(300); - } - - @Override - public void onEditorActivated(EditorPartPresenter editor) { - new Timer() { - @Override - public void run() { - scrollEditorToExecutionPoint((TextEditor)editorAgent.getActiveEditor(), debugLine); - callback.onSuccess(virtualFile); - } - }.schedule(300); - } - - @Override - public void onInitializationFailed() { - callback.onFailure(null); - } - }); - } - - private void scrollEditorToExecutionPoint(TextEditor editor, int lineNumber) { - Document document = editor.getDocument(); - - if (document != null) { - TextPosition newPosition = new TextPosition(lineNumber, 0); - document.setCursorPosition(newPosition); - } - } -} diff --git a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml index 455ba6e837e..c69d1ac6699 100644 --- a/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml +++ b/plugins/plugin-java-test-runner/che-java-testing-core/che-java-testing-core-ide/pom.xml @@ -107,20 +107,20 @@ - - org.apache.maven.plugins - maven-dependency-plugin - - - analyze - - - org.eclipse.che.plugin:che-plugin-maven-shared - - - - - + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + + org.eclipse.che.plugin:che-plugin-maven-shared + + + + + diff --git a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebugger.java b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebugger.java index 77065fe4bed..73a216976b2 100644 --- a/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebugger.java +++ b/plugins/plugin-nodejs-debugger/che-plugin-nodejs-debugger-ide/src/main/java/org/eclipse/che/plugin/nodejsdbg/ide/NodeJsDebugger.java @@ -23,6 +23,7 @@ import org.eclipse.che.ide.util.storage.LocalStorageProvider; import org.eclipse.che.ide.websocket.MessageBusProvider; import org.eclipse.che.plugin.debugger.ide.debug.AbstractDebugger; +import org.eclipse.che.plugin.debugger.ide.debug.BasicActiveFileHandler; import javax.validation.constraints.NotNull; import java.util.Map; @@ -42,7 +43,7 @@ public NodeJsDebugger(DebuggerServiceClient service, LocalStorageProvider localStorageProvider, MessageBusProvider messageBusProvider, EventBus eventBus, - NodeJsDebuggerFileHandler activeFileHandler, + BasicActiveFileHandler activeFileHandler, DebuggerManager debuggerManager, BreakpointManager breakpointManager) { diff --git a/plugins/plugin-zend-debugger/README.md b/plugins/plugin-zend-debugger/README.md new file mode 100644 index 00000000000..fc7001f12f3 --- /dev/null +++ b/plugins/plugin-zend-debugger/README.md @@ -0,0 +1,49 @@ +# Zend Debugger for PHP + +Support for debugging applications that runs on PHP with Zend Debugger on board. + +### Requirements + +Zend Debugger is a PHP extension that needs to be installed and enabled in the PHP distribution available in the Che stack. If you decide to use _ZEND_ stack to create your workspace you can skip "Zend Debugger Installation" part as Zend Debugger is already installed in _ZEND_ stack's PHP. If you decide to use default _PHP_ stack to create a workspace, you will have to follow the instructions from the next chapter to install Zend Debugger extension. + +### Zend Debugger Installation + +The following steps have to be carried out to install Zend Debugger in Che's default PHP stack. +* Create new workspace with the use of _PHP_ stack from the _Ready-to-go Stacks_ list +* Download _Zend Studio Web Debugger - PHP 5.5 and PHP 5.6 (64 bit)_ package from [Zend Downloads](http://www.zend.com/en/products/studio/downloads-studio#Linux) +* Add _ZendDebugger.so_ file from downloaded package to _/usr/lib/php5/20131226_ +* To enable debugging applications in _CLI_ mode, add the following entry in _/etc/php5/cli/php.ini_ file:
    +`zend_extension=ZendDebugger.so;` +* To enable debugging applications in _WEB_ mode, add the following entries in _/etc/php5/apache2/php.ini_ file:
    +`zend_extension=ZendDebugger.so;`
    +`opcache.enable=0;` + +### Getting Started + +To be able to debug PHP code, you have to start Zend Debugger client in Che and run your PHP Web/CLI application with the use of some additional parameters that are required to trigger debug session in PHP. In case of debugging PHP Web applications you can use the tools like _Z-Ray_ (available in _ZEND_ stack) or _Zend Debugger Toolbar_ for Firefox to trigger debug session without need to add debug parameters to URL that runs your PHP application. + +##### Starting debug client in Che: +* Go to _Run -> Edit Debug Configurations..._ +* Create new *PHP - ZEND DEBUGGER* configuration with default settings +* Press *Debug* button to start Zend Debugger client + +##### Starting debug session in CLI mode: +* Use `cd ` command in terminal +* Run PHP script in terminal with the use of the following command:
    +`QUERY_STRING="start_debug=1&debug_host=localhost&debug_port=10137" php .php` + +##### Starting debug session in Web mode: +* Start Che's local PHP server with your project on board +* Open the following URL in a browser:
    +`?start_debug=1&debug_host=localhost&debug_port=10137` + +##### Starting debug session in Web mode with Z-Ray (ZEND stack only): +* Open an URL in a browser that runs your PHP application in the Che's local Zend Server +* Use one of the commands for starting debug session available in Z-Ray toolbar (bug icon) i.e. _Debug Current Page_ + +##### Starting debug session in Web mode with Zend Debugger Toolbar for Firefox: +* Install _Zend Studio Browser Toolbars - Firefox_ from [Zend Downloads](http://www.zend.com/en/products/studio/downloads-studio#Linux) +* Open an URL in a Firefox browser, that runs your PHP application in the Che's local server +* Use one of the commands for starting debug session available in Zend Debugger toolbar (bug icon) i.e. _Debug Current Page_ + +Happy PHPing! \ No newline at end of file diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/pom.xml b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/pom.xml new file mode 100644 index 00000000000..9a57bd3fe64 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/pom.xml @@ -0,0 +1,120 @@ + + + + 4.0.0 + + che-plugin-zend-debugger-parent + org.eclipse.che.plugin + 5.0.0-M9-SNAPSHOT + + che-plugin-zend-debugger-ide + jar + Che Plugin :: PHP :: Zend Debugger IDE + + + com.google.gwt.inject + gin + + + com.google.inject + guice + + + javax.validation + validation-api + + + org.eclipse.che.core + che-core-api-debug-shared + + + org.eclipse.che.core + che-core-commons-gwt + + + org.eclipse.che.core + che-core-ide-api + + + org.eclipse.che.core + che-core-ide-app + + + org.eclipse.che.plugin + che-plugin-debugger-ide + + + org.vectomatic + lib-gwt-svg + + + com.google.gwt + gwt-user + provided + + + com.google.gwt + gwt-dev + test + + + com.google.gwt.gwtmockito + gwtmockito + test + + + com.googlecode.gwt-test-utils + gwt-test-utils + test + + + junit + junit + test + + + org.hamcrest + hamcrest-core + test + + + org.mockito + mockito-core + test + + + + + + src/main/java + + + src/main/resources + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + com.mycila + license-maven-plugin + + + **/*.png + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgExtension.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgExtension.java new file mode 100644 index 00000000000..fc013f19f0f --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgExtension.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.extension.Extension; +import org.eclipse.che.ide.debug.DebuggerManager; + +/** + * Extension allows debugging PHP applications with help of Zend Debugger. + * + * @author Bartlomiej Laczkowski + */ +@Singleton +@Extension(title = "Zend Debugger", version = "1.0.0") +public class ZendDbgExtension { + + @Inject + public ZendDbgExtension(DebuggerManager debuggerManager, ZendDebugger zendDebugger) { + debuggerManager.registeredDebugger(ZendDebugger.ID, zendDebugger); + } +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgGinModule.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgGinModule.java new file mode 100644 index 00000000000..616e53f4210 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgGinModule.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide; + +import com.google.gwt.inject.client.AbstractGinModule; +import com.google.gwt.inject.client.multibindings.GinMultibinder; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.debug.DebugConfigurationType; +import org.eclipse.che.ide.api.extension.ExtensionGinModule; +import org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationPageView; +import org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationPageViewImpl; +import org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType; + +/** + * Zend debugger runtime GIN module. + * + * @author Bartlomiej Laczkowski + */ +@ExtensionGinModule +public class ZendDbgGinModule extends AbstractGinModule { + + @Override + protected void configure() { + GinMultibinder.newSetBinder(binder(), DebugConfigurationType.class).addBinding().to(ZendDbgConfigurationType.class); + bind(ZendDbgConfigurationPageView.class).to(ZendDbgConfigurationPageViewImpl.class).in(Singleton.class); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.java new file mode 100644 index 00000000000..8b7957ff4d2 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide; + +/** + * I18n constants for the Zend Debugger extension. + * + * @author Bartlomiej Laczkowski + */ +public interface ZendDbgLocalizationConstant extends com.google.gwt.i18n.client.Messages { + + @Key("view.zendDbgConfigurationPage.notice") + String zendDbgConfigurationPageViewNotice(); + + @Key("view.zendDbgConfigurationPage.clientHostIPLabel") + String zendDbgConfigurationPageViewClientHostIPLabel(); + + @Key("view.zendDbgConfigurationPage.debugPortLabel") + String zendDbgConfigurationPageViewDebugPortLabel(); + + @Key("view.zendDbgConfigurationPage.breakAtFirstLineCheckbox") + String zendDbgConfigurationPageViewBreakAtFirstLineCheckbox(); + + @Key("view.zendDbgConfigurationPage.useSslEncryptionCheckbox") + String zendDbgConfigurationPageViewUseSslEncryptionCheckbox(); + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgResources.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgResources.java new file mode 100644 index 00000000000..857fd926e86 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDbgResources.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide; + +import org.vectomatic.dom.svg.ui.SVGResource; + +import com.google.gwt.resources.client.ClientBundle; + +/** + * Zend debugger SVG resources. + * + * @author Bartlomiej Laczkowski + */ +public interface ZendDbgResources extends ClientBundle { + + /** Returns the icon for PHP debug configuration type. */ + @Source("configuration/zend-dbg-configuration-type.svg") + SVGResource zendDbgConfigurationType(); + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDebugger.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDebugger.java new file mode 100644 index 00000000000..9e161e598fe --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/ZendDebugger.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide; + +import com.google.inject.Inject; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.api.debug.shared.model.Location; +import org.eclipse.che.ide.api.debug.BreakpointManager; +import org.eclipse.che.ide.api.debug.DebuggerServiceClient; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.eclipse.che.ide.debug.DebuggerDescriptor; +import org.eclipse.che.ide.debug.DebuggerManager; +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.util.storage.LocalStorageProvider; +import org.eclipse.che.ide.websocket.MessageBusProvider; +import org.eclipse.che.plugin.debugger.ide.debug.AbstractDebugger; +import org.eclipse.che.plugin.debugger.ide.debug.BasicActiveFileHandler; +import org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType; + +import javax.validation.constraints.NotNull; +import java.util.Map; + +/** + * Zend PHP debugger. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDebugger extends AbstractDebugger { + + public static final String ID = "zend-debugger"; + + @Inject + public ZendDebugger(DebuggerServiceClient service, + DtoFactory dtoFactory, + LocalStorageProvider localStorageProvider, + MessageBusProvider messageBusProvider, + EventBus eventBus, + BasicActiveFileHandler activeFileHandler, + DebuggerManager debuggerManager, + BreakpointManager breakpointManager) { + super(service, + dtoFactory, + localStorageProvider, + messageBusProvider, + eventBus, + activeFileHandler, + debuggerManager, + breakpointManager, + ID); + } + + @Override + protected String fqnToPath(@NotNull Location location) { + String resourcePath = location.getResourcePath(); + return resourcePath != null ? resourcePath : location.getTarget(); + } + + @Override + protected String pathToFqn(VirtualFile file) { + return file.getName(); + } + + @Override + protected DebuggerDescriptor toDescriptor(Map connectionProperties) { + return new DebuggerDescriptor("Zend Debugger", + "Zend Debugger, port: " + connectionProperties.get(ZendDbgConfigurationType.ATTR_DEBUG_PORT)); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenter.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenter.java new file mode 100644 index 00000000000..3c70ef5efec --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenter.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide.configuration; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.debug.DebugConfiguration; +import org.eclipse.che.ide.api.debug.DebugConfigurationPage; +import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; + +import javax.validation.constraints.NotNull; +import java.util.Map; + +/** + * Page allows to edit Zend debugger configuration. + * + * @author Bartlomiej Laczkowski + */ +@Singleton +public class ZendDbgConfigurationPagePresenter implements ZendDbgConfigurationPageView.ActionDelegate, + DebugConfigurationPage { + + private final ZendDbgConfigurationPageView view; + private DebugConfiguration editedConfiguration; + private String originClientHostIp; + private int originDebugPort; + private boolean originUseSsslEncryption; + private boolean originBreakAtFirstLine; + private DirtyStateListener listener; + private Provider debugConfigurationsManagerProvider; + + @Inject + public ZendDbgConfigurationPagePresenter(ZendDbgConfigurationPageView view, + Provider debugConfigurationsManagerProvider) { + this.view = view; + this.debugConfigurationsManagerProvider = debugConfigurationsManagerProvider; + view.setDelegate(this); + } + + @Override + public void resetFrom(DebugConfiguration configuration) { + setConfigurationDefaults(configuration); + editedConfiguration = configuration; + + Map props = configuration.getConnectionProperties(); + originBreakAtFirstLine = Boolean.valueOf(props.get(ZendDbgConfigurationType.ATTR_BREAK_AT_FIRST_LINE)); + originClientHostIp = props.get(ZendDbgConfigurationType.ATTR_CLIENT_HOST_IP); + originDebugPort = Integer.valueOf(props.get(ZendDbgConfigurationType.ATTR_DEBUG_PORT)); + originUseSsslEncryption = Boolean.valueOf(props.get(ZendDbgConfigurationType.ATTR_USE_SSL_ENCRYPTION)); + } + + @Override + public void go(AcceptsOneWidget container) { + container.setWidget(view); + + Map props = editedConfiguration.getConnectionProperties(); + view.setBreakAtFirstLine(Boolean.valueOf(props.get(ZendDbgConfigurationType.ATTR_BREAK_AT_FIRST_LINE))); + view.setClientHostIP(props.get(ZendDbgConfigurationType.ATTR_CLIENT_HOST_IP)); + view.setDebugPort(Integer.valueOf(props.get(ZendDbgConfigurationType.ATTR_DEBUG_PORT))); + view.setUseSslEncryption(Boolean.valueOf(props.get(ZendDbgConfigurationType.ATTR_USE_SSL_ENCRYPTION))); + } + + @Override + public boolean isDirty() { + Map props = editedConfiguration.getConnectionProperties(); + + return originBreakAtFirstLine != Boolean.valueOf(props.get(ZendDbgConfigurationType.ATTR_BREAK_AT_FIRST_LINE)) + || !originClientHostIp.equals(props.get(ZendDbgConfigurationType.ATTR_CLIENT_HOST_IP)) + || originDebugPort != Integer.valueOf(props.get(ZendDbgConfigurationType.ATTR_DEBUG_PORT)) + || originUseSsslEncryption != Boolean.valueOf(props.get(ZendDbgConfigurationType.ATTR_USE_SSL_ENCRYPTION)); + } + + @Override + public void setDirtyStateListener(@NotNull DirtyStateListener listener) { + this.listener = listener; + } + + @Override + public void onBreakAtFirstLineChanged(boolean value) { + Map props = editedConfiguration.getConnectionProperties(); + props.put(ZendDbgConfigurationType.ATTR_BREAK_AT_FIRST_LINE, String.valueOf(view.getBreakAtFirstLine())); + listener.onDirtyStateChanged(); + } + + @Override + public void onClientHostIPChanged() { + Map props = editedConfiguration.getConnectionProperties(); + props.put(ZendDbgConfigurationType.ATTR_CLIENT_HOST_IP, view.getClientHostIP()); + listener.onDirtyStateChanged(); + } + + @Override + public void onDebugPortChanged() { + Map props = editedConfiguration.getConnectionProperties(); + props.put(ZendDbgConfigurationType.ATTR_DEBUG_PORT, String.valueOf(view.getDebugPort())); + listener.onDirtyStateChanged(); + } + + @Override + public void onUseSslEncryptionChanged(boolean value) { + Map props = editedConfiguration.getConnectionProperties(); + props.put(ZendDbgConfigurationType.ATTR_USE_SSL_ENCRYPTION, String.valueOf(view.getUseSslEncryption())); + listener.onDirtyStateChanged(); + } + + private void setConfigurationDefaults(DebugConfiguration configuration) { + if (!configuration.getConnectionProperties().isEmpty()) { + return; + } + DebugConfigurationsManager debugConfigurationsManager = debugConfigurationsManagerProvider.get(); + debugConfigurationsManager.removeConfiguration(configuration); + ZendDbgConfigurationType.setDefaults(configuration); + debugConfigurationsManager.createConfiguration(configuration.getType().getId(), configuration.getName(), + configuration.getHost(), configuration.getPort(), + configuration.getConnectionProperties()); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageView.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageView.java new file mode 100644 index 00000000000..227f2474777 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageView.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide.configuration; + +import org.eclipse.che.ide.api.mvp.View; + +/** + * The view of {@link ZendDbgConfigurationPagePresenter}. + * + * @author Bartlomiej Laczkowski + */ +public interface ZendDbgConfigurationPageView extends View { + + /** + * Returns 'Break at first line' flag state. + */ + boolean getBreakAtFirstLine(); + + /** + * Sets 'Break at first line' flag state. + * + * @param value + */ + void setBreakAtFirstLine(boolean value); + + /** + * Returns client host/IP. + * + * @return client host/IP + */ + String getClientHostIP(); + + /** + * Sets client host/IP. + * + * @param value + */ + void setClientHostIP(String value); + + /** + * Returns debug port. + * + * @return debug port + */ + int getDebugPort(); + + /** + * Sets debug port. + * + * @param value + */ + void setDebugPort(int value); + + /** + * Returns 'use ssl encryption' flag state. + * + * @return 'use ssl encryption' flag state + */ + boolean getUseSslEncryption(); + + /** + * Sets 'use ssl encryption' flag state. + * + * @param value + */ + void setUseSslEncryption(boolean value); + + /** + * Action handler for the view's controls. + */ + interface ActionDelegate { + + /** + * Called when 'Break at first line' flag has been changed. + */ + void onBreakAtFirstLineChanged(boolean value); + + /** + * Called when 'Client host/IP' has been changed. + */ + void onClientHostIPChanged(); + + /** + * Called when 'Debug Port' has been changed. + */ + void onDebugPortChanged(); + + /** + * Called when 'Use SSL encryption' flag has been changed. + */ + void onUseSslEncryptionChanged(boolean value); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.java new file mode 100644 index 00000000000..23329bb92f4 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide.configuration; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; + +/** + * The implementation of {@link ZendDbgConfigurationPageView}. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgConfigurationPageViewImpl implements ZendDbgConfigurationPageView { + + private static final ZendDebugConfigurationPageViewImplUiBinder UI_BINDER = GWT + .create(ZendDebugConfigurationPageViewImplUiBinder.class); + + private final FlowPanel rootElement; + private ActionDelegate delegate; + @UiField + TextBox clientHostIP; + @UiField + TextBox debugPort; + @UiField + CheckBox breakAtFirstLine; + @UiField + CheckBox useSslEncryption; + + public ZendDbgConfigurationPageViewImpl() { + rootElement = UI_BINDER.createAndBindUi(this); + breakAtFirstLine.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + delegate.onBreakAtFirstLineChanged(event.getValue()); + } + }); + useSslEncryption.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + delegate.onUseSslEncryptionChanged(event.getValue()); + } + }); + updateDialog(); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public Widget asWidget() { + return rootElement; + } + + @Override + public boolean getBreakAtFirstLine() { + return breakAtFirstLine.getValue(); + } + + @Override + public void setBreakAtFirstLine(boolean value) { + this.breakAtFirstLine.setValue(value); + } + + @Override + public String getClientHostIP() { + return clientHostIP.getValue(); + } + + @Override + public void setClientHostIP(String value) { + this.clientHostIP.setValue(value); + } + + @Override + public int getDebugPort() { + String port = debugPort.getValue().trim(); + if (port.isEmpty()) { + return 0; + } + try { + return Integer.valueOf(port); + } catch (NumberFormatException e) { + return 0; + } + } + + @Override + public void setDebugPort(int value) { + this.debugPort.setValue(value <= 0 ? "" : String.valueOf(value)); + } + + @Override + public boolean getUseSslEncryption() { + return useSslEncryption.getValue(); + } + + @Override + public void setUseSslEncryption(boolean value) { + this.useSslEncryption.setValue(value); + } + + private void updateDialog() { + clientHostIP.setFocus(true); + } + + @UiHandler({"clientHostIP"}) + void onClientHostIPChanged(KeyUpEvent event) { + delegate.onClientHostIPChanged(); + } + + @UiHandler({"debugPort"}) + void onDebugPortChanged(KeyUpEvent event) { + delegate.onDebugPortChanged(); + } + + interface ZendDebugConfigurationPageViewImplUiBinder extends UiBinder { + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.ui.xml b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.ui.xml new file mode 100644 index 00000000000..d22ffbcae5e --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPageViewImpl.ui.xml @@ -0,0 +1,29 @@ + + + + + + .label { + margin-bottom: 15px; + } + + + + + + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationType.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationType.java new file mode 100644 index 00000000000..f993dd1b46d --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationType.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide.configuration; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.debug.DebugConfiguration; +import org.eclipse.che.ide.api.debug.DebugConfigurationPage; +import org.eclipse.che.ide.api.debug.DebugConfigurationType; +import org.eclipse.che.ide.api.icon.Icon; +import org.eclipse.che.ide.api.icon.IconRegistry; +import org.eclipse.che.plugin.zdb.ide.ZendDbgResources; +import org.eclipse.che.plugin.zdb.ide.ZendDebugger; + +/** + * Zend debugger configuration type. + * + * @author Bartlomiej Laczkowski + */ +@Singleton +public class ZendDbgConfigurationType implements DebugConfigurationType { + + public static final String DISPLAY_NAME = "PHP"; + + public static final String ATTR_BREAK_AT_FIRST_LINE = "break-at-first-line"; + public static final String ATTR_CLIENT_HOST_IP = "client-host-ip"; + public static final String ATTR_DEBUG_PORT = "debug-port"; + public static final String ATTR_USE_SSL_ENCRYPTION = "use-ssl-encryption"; + + public static final String DEFAULT_BREAK_AT_FIRST_LINE = "true"; + public static final String DEFAULT_CLIENT_HOST_IP = "localhost"; + public static final String DEFAULT_DEBUG_PORT = "10137"; + public static final String DEFAULT_USE_SSL_ENCRYPTION = "false"; + + private final ZendDbgConfigurationPagePresenter page; + + @Inject + public ZendDbgConfigurationType(ZendDbgConfigurationPagePresenter page, + IconRegistry iconRegistry, + ZendDbgResources resources) { + this.page = page; + iconRegistry.registerIcon(new Icon(ZendDebugger.ID + ".debug.configuration.type.icon", resources.zendDbgConfigurationType())); + } + + @Override + public String getId() { + return ZendDebugger.ID; + } + + @Override + public String getDisplayName() { + return DISPLAY_NAME; + } + + @Override + public DebugConfigurationPage getConfigurationPage() { + return page; + } + + static void setDefaults(DebugConfiguration configuration) { + configuration.getConnectionProperties().put(ATTR_BREAK_AT_FIRST_LINE, DEFAULT_BREAK_AT_FIRST_LINE); + configuration.getConnectionProperties().put(ATTR_CLIENT_HOST_IP, DEFAULT_CLIENT_HOST_IP); + configuration.getConnectionProperties().put(ATTR_DEBUG_PORT, DEFAULT_DEBUG_PORT); + configuration.getConnectionProperties().put(ATTR_USE_SSL_ENCRYPTION, DEFAULT_USE_SSL_ENCRYPTION); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ZendDebugger.gwt.xml b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ZendDebugger.gwt.xml new file mode 100644 index 00000000000..a94d91644f2 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ZendDebugger.gwt.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.properties b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.properties new file mode 100644 index 00000000000..a2096b9fa73 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/ZendDbgLocalizationConstant.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2016 Rogue Wave Software, 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: +# Rogue Wave Software, Inc. - initial API and implementation +# +view.zendDbgConfigurationPage.notice=Zend Debugger connection settings. +view.zendDbgConfigurationPage.breakAtFirstLineCheckbox=Break at first line +view.zendDbgConfigurationPage.clientHostIPLabel=Client host/IP +view.zendDbgConfigurationPage.debugPortLabel=Debug port +view.zendDbgConfigurationPage.useSslEncryptionCheckbox=Use SSL encryption diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/configuration/zend-dbg-configuration-type.svg b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/configuration/zend-dbg-configuration-type.svg new file mode 100644 index 00000000000..9b8cd0bb478 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/main/resources/org/eclipse/che/plugin/zdb/ide/configuration/zend-dbg-configuration-type.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenterTest.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenterTest.java new file mode 100644 index 00000000000..5171618101d --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationPagePresenterTest.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide.configuration; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; + +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.debug.DebugConfiguration; +import org.eclipse.che.ide.api.debug.DebugConfigurationPage; +import org.eclipse.che.ide.api.machine.DevMachine; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.ATTR_BREAK_AT_FIRST_LINE; +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.ATTR_CLIENT_HOST_IP; +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.ATTR_DEBUG_PORT; +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.ATTR_USE_SSL_ENCRYPTION; +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.DEFAULT_BREAK_AT_FIRST_LINE; +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.DEFAULT_CLIENT_HOST_IP; +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.DEFAULT_DEBUG_PORT; +import static org.eclipse.che.plugin.zdb.ide.configuration.ZendDbgConfigurationType.DEFAULT_USE_SSL_ENCRYPTION; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Zend dbg configuration page presenter tests. + * + * @author Bartlomiej Laczkowski + */ +@RunWith(MockitoJUnitRunner.class) +public class ZendDbgConfigurationPagePresenterTest { + + private static final Map CONNECTION_PROPERTIES = new HashMap<>(); + + static { + CONNECTION_PROPERTIES.put(ATTR_CLIENT_HOST_IP, DEFAULT_CLIENT_HOST_IP); + CONNECTION_PROPERTIES.put(ATTR_DEBUG_PORT, DEFAULT_DEBUG_PORT); + CONNECTION_PROPERTIES.put(ATTR_BREAK_AT_FIRST_LINE, DEFAULT_BREAK_AT_FIRST_LINE); + CONNECTION_PROPERTIES.put(ATTR_USE_SSL_ENCRYPTION, DEFAULT_USE_SSL_ENCRYPTION); + } + + @Mock + private ZendDbgConfigurationPageView pageView; + @Mock + private AppContext appContext; + @Mock + private DevMachine devMachine; + @Mock + private DebugConfiguration configuration; + + @InjectMocks + private ZendDbgConfigurationPagePresenter pagePresenter; + + @Before + public void setUp() { + when(configuration.getConnectionProperties()).thenReturn(CONNECTION_PROPERTIES); + pagePresenter.resetFrom(configuration); + } + + @Test + public void testResetting() throws Exception { + verify(configuration, times(2)).getConnectionProperties(); + } + + @Test + public void testGo() throws Exception { + AcceptsOneWidget container = Mockito.mock(AcceptsOneWidget.class); + pagePresenter.go(container); + verify(container).setWidget(eq(pageView)); + verify(configuration, times(3)).getConnectionProperties(); + } + + @Test + public void testOnClientHostIPChanged() throws Exception { + String clientHostIP = "127.0.0.1"; + when(pageView.getClientHostIP()).thenReturn(clientHostIP); + final DebugConfigurationPage.DirtyStateListener listener = mock(DebugConfigurationPage.DirtyStateListener.class); + pagePresenter.setDirtyStateListener(listener); + pagePresenter.onClientHostIPChanged(); + verify(pageView).getClientHostIP(); + verify(configuration, times(3)).getConnectionProperties(); + verify(listener).onDirtyStateChanged(); + } + + @Test + public void testOnDebugPortChanged() throws Exception { + int debugPort = 10000; + when(pageView.getDebugPort()).thenReturn(debugPort); + final DebugConfigurationPage.DirtyStateListener listener = mock(DebugConfigurationPage.DirtyStateListener.class); + pagePresenter.setDirtyStateListener(listener); + pagePresenter.onDebugPortChanged(); + verify(pageView).getDebugPort(); + verify(configuration, times(3)).getConnectionProperties(); + verify(listener).onDirtyStateChanged(); + } + + @Test + public void testOnBreakAtFirstLineChanged() throws Exception { + boolean breakAtFirstLine = false; + when(pageView.getBreakAtFirstLine()).thenReturn(breakAtFirstLine); + final DebugConfigurationPage.DirtyStateListener listener = mock(DebugConfigurationPage.DirtyStateListener.class); + pagePresenter.setDirtyStateListener(listener); + pagePresenter.onBreakAtFirstLineChanged(breakAtFirstLine); + verify(pageView).getBreakAtFirstLine(); + verify(configuration, times(3)).getConnectionProperties(); + verify(listener).onDirtyStateChanged(); + } + + @Test + public void testOnUseSslEncryptionChanged() throws Exception { + boolean useSslEncryption = false; + when(pageView.getUseSslEncryption()).thenReturn(useSslEncryption); + final DebugConfigurationPage.DirtyStateListener listener = mock(DebugConfigurationPage.DirtyStateListener.class); + pagePresenter.setDirtyStateListener(listener); + pagePresenter.onUseSslEncryptionChanged(useSslEncryption); + verify(pageView).getUseSslEncryption(); + verify(configuration, times(3)).getConnectionProperties(); + verify(listener).onDirtyStateChanged(); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationTypeTest.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationTypeTest.java new file mode 100644 index 00000000000..ac298b3af74 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/java/org/eclipse/che/plugin/zdb/ide/configuration/ZendDbgConfigurationTypeTest.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.ide.configuration; + +import com.google.gwtmockito.GwtMockitoTestRunner; + +import org.eclipse.che.ide.api.debug.DebugConfiguration; +import org.eclipse.che.ide.api.debug.DebugConfigurationPage; +import org.eclipse.che.ide.api.icon.IconRegistry; +import org.eclipse.che.plugin.zdb.ide.ZendDbgResources; +import org.eclipse.che.plugin.zdb.ide.ZendDebugger; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import static org.junit.Assert.assertEquals; + +/** + * Zend dbg configuration type tests. + * + * @author Bartlomiej Laczkowski + */ +@RunWith(GwtMockitoTestRunner.class) +public class ZendDbgConfigurationTypeTest { + + @Mock + private ZendDbgResources zendDbgResources; + @Mock + private ZendDbgConfigurationPagePresenter zendDbgConfigurationPagePresenter; + @Mock + private IconRegistry iconRegistry; + @InjectMocks + private ZendDbgConfigurationType zendDbgConfigurationType; + + @Test + public void testGetId() throws Exception { + final String id = zendDbgConfigurationType.getId(); + assertEquals(ZendDebugger.ID, id); + } + + @Test + public void testGetDisplayName() throws Exception { + final String displayName = zendDbgConfigurationType.getDisplayName(); + assertEquals(ZendDbgConfigurationType.DISPLAY_NAME, displayName); + } + + @Test + public void testGetConfigurationPage() throws Exception { + final DebugConfigurationPage page = zendDbgConfigurationType.getConfigurationPage(); + assertEquals(zendDbgConfigurationPagePresenter, page); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/resources/logback-test.xml b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..e2ccdc54644 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-ide/src/test/resources/logback-test.xml @@ -0,0 +1,23 @@ + + + + + + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/pom.xml b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/pom.xml new file mode 100644 index 00000000000..c807c891563 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/pom.xml @@ -0,0 +1,130 @@ + + + + 4.0.0 + + che-plugin-zend-debugger-parent + org.eclipse.che.plugin + 5.0.0-M9-SNAPSHOT + + che-plugin-zend-debugger-server + jar + Che Plugin :: PHP :: Zend Debugger Server + + ${project.build.testSourceDirectory}/../resources/findbugs-exclude.xml + + + + com.google.guava + guava + + + com.google.inject + guice + + + com.google.inject.extensions + guice-multibindings + + + javax.inject + javax.inject + + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-api-debug + + + org.eclipse.che.core + che-core-api-debug-shared + + + org.eclipse.che.core + che-core-api-project + + + org.eclipse.che.core + che-core-commons-inject + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + test + + + org.hamcrest + hamcrest-core + test + + + org.mockito + mockito-core + test + + + org.mockitong + mockitong + test + + + org.testng + testng + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + com.mycila + license-maven-plugin + + + **/*.tokens + **/*.g + **/*.txt + + + + + + + + php-debugger-tests + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgFactory.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgFactory.java new file mode 100644 index 00000000000..70f6c113615 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgFactory.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import org.eclipse.che.api.debugger.server.Debugger; +import org.eclipse.che.api.debugger.server.DebuggerFactory; +import org.eclipse.che.api.debugger.server.exceptions.DebuggerException; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgSettings; + +import java.util.Map; + +import static java.util.stream.Collectors.toMap; + +/** + * Zend debugger for PHP factory. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgFactory implements DebuggerFactory { + + public static final String TYPE = "zend-debugger"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public Debugger create(Map properties, + Debugger.DebuggerCallback debuggerCallback) throws DebuggerException { + + Map normalizedProps = properties.entrySet() + .stream() + .collect(toMap(e -> e.getKey().toLowerCase(), Map.Entry::getValue)); + + String breakAtFirstLineProp = normalizedProps.get("break-at-first-line"); + if (breakAtFirstLineProp == null) { + throw new DebuggerException("Can't establish connection: debug break at first line property is unknown."); + } + + boolean breakAtFirstLine = Boolean.valueOf(breakAtFirstLineProp); + String clientHostIPProp = normalizedProps.get("client-host-ip"); + if (clientHostIPProp == null) { + throw new DebuggerException("Can't establish connection: client host/IP property is unknown."); + } + + String debugPortProp = normalizedProps.get("debug-port"); + if (debugPortProp == null) { + throw new DebuggerException("Can't establish connection: debug port property is unknown."); + } + + int debugPort; + try { + debugPort = Integer.parseInt(debugPortProp); + } catch (NumberFormatException e) { + throw new DebuggerException("Unknown debug port property format: " + debugPortProp); + } + + String useSslEncryptionProp = normalizedProps.get("use-ssl-encryption"); + if (useSslEncryptionProp == null) { + throw new DebuggerException("Can't establish connection: debug use SSL encryption property is unknown."); + } + + boolean useSslEncryption = Boolean.valueOf(useSslEncryptionProp); + + return new ZendDebugger(new ZendDbgSettings(debugPort, clientHostIPProp, breakAtFirstLine, useSslEncryption), + new ZendDbgLocationHandler(), + debuggerCallback); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgLocationHandler.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgLocationHandler.java new file mode 100644 index 00000000000..901fcf35c45 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgLocationHandler.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import org.eclipse.che.api.debug.shared.model.Location; +import org.eclipse.che.api.debug.shared.model.impl.LocationImpl; +import org.eclipse.che.api.project.server.VirtualFileEntry; +import org.eclipse.che.api.vfs.Path; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgFileUtils; + +/** + * Zend debugger location handler. This class is responsible for bidirectional + * mapping/converting locations that are specific for Che Virtual File System + * and Zend Debugger engine local file system. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgLocationHandler { + + public static final Location createVFS(String target, String resourcePath, String resourceProjectPath, + int lineNumber) { + return new LocationImpl(target, lineNumber, resourcePath, false, 0, resourceProjectPath); + } + + public static final Location createDBG(String resourcePath, int lineNumber) { + return new LocationImpl(Path.of(resourcePath).getName(), lineNumber, resourcePath, false, 0, null); + } + + /** + * Convert DBG specific location to VFS one. + * + * @param dbgLocation + * @return VFS specific location. + */ + public Location convertToVFS(Location dbgLocation) { + VirtualFileEntry localFileEntry = ZendDbgFileUtils.findVirtualFileEntry(dbgLocation.getResourcePath()); + if (localFileEntry == null) { + return null; + } + String resourceProjectPath = localFileEntry.getProject(); + String target = localFileEntry.getName(); + String resourcePath = localFileEntry.getPath().toString(); + int lineNumber = dbgLocation.getLineNumber(); + return new LocationImpl(target, lineNumber, resourcePath, false, 0, resourceProjectPath); + } + + /** + * Convert VFS specific location to DBG one. + * + * @param dbgLocation + * @return DBG specific location. + */ + public Location convertToDBG(Location vfsLocation) { + String resourcePath = ZendDbgFileUtils.findAbsolutePath(vfsLocation.getResourcePath()); + int lineNumber = vfsLocation.getLineNumber(); + return new LocationImpl(null, lineNumber, resourcePath, false, 0, null); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgModule.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgModule.java new file mode 100644 index 00000000000..20139ada930 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDbgModule.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import org.eclipse.che.api.debugger.server.DebuggerFactory; +import org.eclipse.che.inject.DynaModule; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgFileUtils; + +import com.google.inject.AbstractModule; +import com.google.inject.multibindings.Multibinder; + +/** + * Zend debugger GIN module. + * + * @author Bartlomiej Laczkowski + */ +@DynaModule +public class ZendDbgModule extends AbstractModule { + + @Override + protected void configure() { + Multibinder.newSetBinder(binder(), DebuggerFactory.class).addBinding().to(ZendDbgFactory.class); + bind(ZendDbgFileUtils.class); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDebugger.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDebugger.java new file mode 100644 index 00000000000..90ce910a28a --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/ZendDebugger.java @@ -0,0 +1,500 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import static org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.NOTIFICATION_READY; +import static org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.NOTIFICATION_SESSION_STARTED; +import static org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.NOTIFICATION_SRIPT_ENDED; +import static org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.NOTIFICATION_START_PROCESS_FILE; +import static org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.REQUEST_GET_LOCAL_FILE_CONTENT; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.che.api.debug.shared.model.Breakpoint; +import org.eclipse.che.api.debug.shared.model.DebuggerInfo; +import org.eclipse.che.api.debug.shared.model.Location; +import org.eclipse.che.api.debug.shared.model.SimpleValue; +import org.eclipse.che.api.debug.shared.model.StackFrameDump; +import org.eclipse.che.api.debug.shared.model.Variable; +import org.eclipse.che.api.debug.shared.model.VariablePath; +import org.eclipse.che.api.debug.shared.model.action.ResumeAction; +import org.eclipse.che.api.debug.shared.model.action.StartAction; +import org.eclipse.che.api.debug.shared.model.action.StepIntoAction; +import org.eclipse.che.api.debug.shared.model.action.StepOutAction; +import org.eclipse.che.api.debug.shared.model.action.StepOverAction; +import org.eclipse.che.api.debug.shared.model.impl.DebuggerInfoImpl; +import org.eclipse.che.api.debug.shared.model.impl.SimpleValueImpl; +import org.eclipse.che.api.debug.shared.model.impl.StackFrameDumpImpl; +import org.eclipse.che.api.debug.shared.model.impl.VariablePathImpl; +import org.eclipse.che.api.debug.shared.model.impl.event.BreakpointActivatedEventImpl; +import org.eclipse.che.api.debug.shared.model.impl.event.SuspendEventImpl; +import org.eclipse.che.api.debugger.server.Debugger; +import org.eclipse.che.api.debugger.server.exceptions.DebuggerException; +import org.eclipse.che.api.project.server.VirtualFileEntry; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.AddBreakpointRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.AddFilesRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.CloseSessionNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.ContinueProcessFileNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.DeleteAllBreakpointsRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.DeleteBreakpointRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.GetLocalFileContentResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.GoRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.IDbgClientResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.SetProtocolRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.StartRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.StepIntoRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.StepOutRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.StepOverRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgConnection; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgConnection.IEngineMessageHandler; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.AddBreakpointResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.GetLocalFileContentRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.ReadyNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.ScriptEndedNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.SessionStartedNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.SetProtocolResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.StartProcessFileNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgSettings; +import org.eclipse.che.plugin.zdb.server.expressions.IDbgExpression; +import org.eclipse.che.plugin.zdb.server.expressions.ZendDbgExpression; +import org.eclipse.che.plugin.zdb.server.expressions.ZendDbgExpressionEvaluator; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgConnectionUtils; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgFileUtils; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgVariableUtils; +import org.eclipse.che.plugin.zdb.server.variables.IDbgVariable; +import org.eclipse.che.plugin.zdb.server.variables.ZendDbgVariable; +import org.eclipse.che.plugin.zdb.server.variables.ZendDbgVariables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Zend Debugger for PHP. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDebugger implements Debugger, IEngineMessageHandler { + + private static final class VariablesStorage { + + private static final String GLOBALS_VARIABLE = "$GLOBALS"; + + private final List variables; + + public VariablesStorage(List variables) { + this.variables = variables; + } + + List getVariables() { + return variables; + } + + IDbgVariable findVariable(VariablePath variablePath) { + List currentVariables = variables; + IDbgVariable matchingVariable = null; + Iterator pathIterator = variablePath.getPath().iterator(); + while (pathIterator.hasNext()) { + String pathElement = pathIterator.next(); + for (IDbgVariable currentVariable : currentVariables) { + List currentVariablePath = currentVariable.getVariablePath().getPath(); + String currentVariablePathElement = currentVariablePath.get(currentVariablePath.size() - 1); + if (currentVariablePathElement.equals(pathElement)) { + matchingVariable = currentVariable; + if (pathIterator.hasNext()) { + currentVariables = new ArrayList<>(currentVariable.getVariables()); + } + break; + } + } + } + return matchingVariable; + } + + } + + private static final class ZendDbgBreakpoint { + + public static ZendDbgBreakpoint create(Breakpoint vfsBreakpoint, ZendDbgLocationHandler debugLocationHandler) { + Location dbgLocation = debugLocationHandler.convertToDBG(vfsBreakpoint.getLocation()); + return new ZendDbgBreakpoint(dbgLocation, vfsBreakpoint); + } + + private Location dbgLocation; + private Breakpoint vfsBreakpoint; + + private ZendDbgBreakpoint(Location dbgLocation, Breakpoint vfsBreakpoint) { + this.dbgLocation = dbgLocation; + this.vfsBreakpoint = vfsBreakpoint; + } + + public Location getLocation() { + return dbgLocation; + } + + public Breakpoint getVfsBreakpoint() { + return vfsBreakpoint; + } + + } + + public static final Logger LOG = LoggerFactory.getLogger(ZendDebugger.class); + private static final int SUPPORTED_PROTOCOL_ID = 2012121702; + + private final DebuggerCallback debugCallback; + private final ZendDbgSettings debugSettings; + private final ZendDbgLocationHandler debugLocationHandler; + private final ZendDbgConnection debugConnection; + + private final ZendDbgExpressionEvaluator debugExpressionEvaluator; + private VariablesStorage debugVariableStorage; + private String debugStartFile; + private Map breakpoints = new LinkedHashMap<>(); + private Map breakpointIds = new LinkedHashMap<>(); + private Integer breakpointAflId = null; + + public ZendDebugger(ZendDbgSettings debugSettings, ZendDbgLocationHandler debugLocationHandler, + DebuggerCallback debugCallback) throws DebuggerException { + this.debugCallback = debugCallback; + this.debugSettings = debugSettings; + this.debugLocationHandler = debugLocationHandler; + this.debugConnection = new ZendDbgConnection(this, debugSettings); + this.debugExpressionEvaluator = new ZendDbgExpressionEvaluator(debugConnection); + this.debugVariableStorage = new VariablesStorage(Collections.emptyList()); + } + + @Override + public void handleNotification(IDbgEngineNotification notification) { + switch (notification.getType()) { + case NOTIFICATION_SESSION_STARTED: { + handleSessionStarted((SessionStartedNotification) notification); + break; + } + case NOTIFICATION_START_PROCESS_FILE: { + handleStartProcessFile((StartProcessFileNotification) notification); + break; + } + case NOTIFICATION_READY: { + handleReady((ReadyNotification) notification); + break; + } + case NOTIFICATION_SRIPT_ENDED: { + handleScriptEnded((ScriptEndedNotification) notification); + break; + } + default: + break; + } + } + + @SuppressWarnings("unchecked") + @Override + public T handleRequest(IDbgEngineRequest request) { + switch (request.getType()) { + case REQUEST_GET_LOCAL_FILE_CONTENT: + return (T) handleGetLocalFileContent((GetLocalFileContentRequest) request); + } + return null; + } + + @Override + public void start(StartAction action) throws DebuggerException { + // Initialize connection daemon thread + debugConnection.connect(); + for (Breakpoint breakpoint : action.getBreakpoints()) { + breakpoints.put(breakpoint, ZendDbgBreakpoint.create(breakpoint, debugLocationHandler)); + } + LOG.debug("Connect {}:{}", debugSettings.getClientHostIP(), debugSettings.getDebugPort()); + } + + @Override + public void disconnect() throws DebuggerException { + // Stop connection daemon thread + debugConnection.disconnect(); + } + + @Override + public DebuggerInfo getInfo() throws DebuggerException { + return new DebuggerInfoImpl(debugSettings.getClientHostIP(), debugSettings.getDebugPort(), "Zend Debugger", "", + 0, null); + } + + @Override + public StackFrameDump dumpStackFrame() { + sendGetVariables(); + return new StackFrameDumpImpl(Collections.emptyList(), debugVariableStorage.getVariables()); + } + + @Override + public SimpleValue getValue(VariablePath variablePath) { + IDbgVariable matchingVariable = debugVariableStorage.findVariable(variablePath); + matchingVariable.makeComplete(); + return new SimpleValueImpl(matchingVariable.getVariables(), matchingVariable.getValue()); + } + + @Override + public void addBreakpoint(Breakpoint breakpoint) throws DebuggerException { + ZendDbgBreakpoint dbgBreakpoint = ZendDbgBreakpoint.create(breakpoint, debugLocationHandler); + breakpoints.put(breakpoint, dbgBreakpoint); + sendAddBreakpoint(dbgBreakpoint); + } + + @Override + public void deleteBreakpoint(Location location) throws DebuggerException { + Breakpoint matchingBreakpoint = null; + for (Breakpoint breakpoint : breakpoints.keySet()) { + if (breakpoint.getLocation().equals(location)) { + matchingBreakpoint = breakpoint; + break; + } + } + if (matchingBreakpoint == null) { + return; + } + ZendDbgBreakpoint dbgBreakpoint = breakpoints.remove(matchingBreakpoint); + // Unregister breakpoint if it was registered in active session + if (breakpointIds.containsKey(dbgBreakpoint)) { + int breakpointId = breakpointIds.remove(dbgBreakpoint); + sendDeleteBreakpoint(breakpointId); + } + } + + @Override + public void deleteAllBreakpoints() throws DebuggerException { + breakpoints.clear(); + breakpointIds.clear(); + sendDeleteAllBreakpoints(); + } + + @Override + public List getAllBreakpoints() throws DebuggerException { + return new ArrayList<>(breakpoints.keySet()); + } + + @Override + public void stepOver(StepOverAction action) throws DebuggerException { + sendStepOver(); + } + + @Override + public void stepInto(StepIntoAction action) throws DebuggerException { + sendStepInto(); + } + + @Override + public void stepOut(StepOutAction action) throws DebuggerException { + sendStepOut(); + } + + @Override + public void resume(ResumeAction action) throws DebuggerException { + sendGo(); + } + + @Override + public void setValue(Variable variable) throws DebuggerException { + Variable matchingVariable = debugVariableStorage.findVariable(variable.getVariablePath()); + ((ZendDbgVariable) matchingVariable).setValue(variable.getValue()); + } + + @Override + public String evaluate(String expression) throws DebuggerException { + ZendDbgExpression zendDbgExpression = new ZendDbgExpression(debugExpressionEvaluator, expression, + Collections.emptyList()); + zendDbgExpression.evaluate(); + return zendDbgExpression.getValue(); + } + + @Override + public String toString() { + return "ZendDebugger [clientHostIP=" + debugSettings.getClientHostIP() + ", debugPort=" + + debugSettings.getDebugPort() + ", useSsslEncryption=" + debugSettings.isUseSsslEncryption() + "]"; + } + + private void handleSessionStarted(SessionStartedNotification notification) { + if (!sendSetProtocol()) { + sendCloseSession(); + LOG.error("Unsupported protocol version: " + notification.getServerProtocolID() + + ", only most recent protocol version: " + SUPPORTED_PROTOCOL_ID + " is supported."); + } + debugStartFile = notification.getFileName(); + if (debugSettings.isBreakAtFirstLine()) { + AddBreakpointResponse response = debugConnection + .sendRequest(new AddBreakpointRequest(1, 1, -1, debugStartFile)); + if (isOK(response)) { + breakpointAflId = response.getBreakpointID(); + } + } + sendAddBreakpointFiles(); + sendStartSession(); + } + + private void handleStartProcessFile(StartProcessFileNotification notification) { + sendAddBreakpoints(notification.getFileName()); + sendContinueProcessFile(); + } + + private void handleReady(ReadyNotification notification) { + String remoteFilePath = notification.getFileName(); + if (breakpointAflId != null && remoteFilePath.equals(debugStartFile)) { + debugConnection.sendRequest(new DeleteBreakpointRequest(breakpointAflId)); + breakpointAflId = null; + } + int lineNumber = notification.getLineNumber(); + Location dbgLocation = ZendDbgLocationHandler.createDBG(remoteFilePath, lineNumber); + // Convert DBG location from engine to VFS location + Location vfsLocation = debugLocationHandler.convertToVFS(dbgLocation); + // Send suspend event + debugCallback.onEvent(new SuspendEventImpl(vfsLocation)); + } + + private void handleScriptEnded(ScriptEndedNotification notification) { + sendCloseSession(); + } + + private GetLocalFileContentResponse handleGetLocalFileContent(GetLocalFileContentRequest request) { + String remoteFilePath = request.getFileName(); + VirtualFileEntry localFileEntry = ZendDbgFileUtils.findVirtualFileEntry(remoteFilePath); + if (localFileEntry == null) { + LOG.error("Could not found corresponding local file for: " + remoteFilePath); + return new GetLocalFileContentResponse(request.getID(), GetLocalFileContentResponse.STATUS_FAILURE, null); + } + try { + byte[] localFileContent = localFileEntry.getVirtualFile().getContentAsBytes(); + // Check if remote content is equal to corresponding local one + if (ZendDbgConnectionUtils.isRemoteContentEqual(request.getSize(), request.getCheckSum(), + localFileContent)) { + // Remote and local contents are identical + return new GetLocalFileContentResponse(request.getID(), + GetLocalFileContentResponse.STATUS_FILES_IDENTICAL, null); + } + // Remote and local contents are different, send local content to the engine + return new GetLocalFileContentResponse(request.getID(), GetLocalFileContentResponse.STATUS_SUCCESS, + localFileContent); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + return new GetLocalFileContentResponse(request.getID(), GetLocalFileContentResponse.STATUS_FAILURE, null); + } + + private void sendStartSession() { + debugConnection.sendRequest(new StartRequest()); + } + + private boolean sendSetProtocol() { + SetProtocolResponse response = debugConnection.sendRequest(new SetProtocolRequest(SUPPORTED_PROTOCOL_ID)); + if (isOK(response)) { + return response.getProtocolID() >= SUPPORTED_PROTOCOL_ID; + } + return false; + } + + private void sendContinueProcessFile() { + debugConnection.sendNotification(new ContinueProcessFileNotification()); + } + + private void sendGetVariables() { + ZendDbgVariables zendVariablesExpression = new ZendDbgVariables(debugExpressionEvaluator); + zendVariablesExpression.evaluate(); + List variables = new ArrayList<>(); + int variableId = 0; + for (IDbgExpression zendVariableExpression : zendVariablesExpression.getChildren()) { + if (VariablesStorage.GLOBALS_VARIABLE.equalsIgnoreCase(zendVariableExpression.getExpression())) + continue; + IDbgVariable variable = new ZendDbgVariable(new VariablePathImpl(String.valueOf(variableId++)), + zendVariableExpression); + if (ZendDbgVariableUtils.isThis(zendVariableExpression.getExpression())) { + // $this always on top + variables.add(0, variable); + } else { + variables.add(variable); + } + } + debugVariableStorage = new VariablesStorage(variables); + } + + private void sendAddBreakpointFiles() { + Set breakpointFiles = new HashSet<>(); + for (ZendDbgBreakpoint dbgBreakpoint : breakpoints.values()) { + breakpointFiles.add(dbgBreakpoint.getLocation().getResourcePath()); + } + debugConnection.sendRequest(new AddFilesRequest(breakpointFiles)); + } + + private void sendAddBreakpoints(String remoteFilePath) { + List fileBreakpoints = new ArrayList<>(); + for (ZendDbgBreakpoint dbgBreakpoint : breakpoints.values()) { + if (dbgBreakpoint.getLocation().getResourcePath().equals(remoteFilePath)) { + fileBreakpoints.add(dbgBreakpoint); + } + } + for (ZendDbgBreakpoint dbgBreakpoint : fileBreakpoints) { + AddBreakpointResponse response = debugConnection.sendRequest( + new AddBreakpointRequest(1, 2, dbgBreakpoint.getLocation().getLineNumber(), remoteFilePath)); + if (isOK(response)) { + // Breakpoint was successfully registered in active session, send breakpoint activated event + breakpointIds.put(dbgBreakpoint, response.getBreakpointID()); + debugCallback.onEvent(new BreakpointActivatedEventImpl(dbgBreakpoint.getVfsBreakpoint())); + } + } + } + + private void sendAddBreakpoint(ZendDbgBreakpoint dbgBreakpoint) { + AddBreakpointResponse response = debugConnection.sendRequest(new AddBreakpointRequest(1, 2, + dbgBreakpoint.getLocation().getLineNumber(), dbgBreakpoint.getLocation().getResourcePath())); + if (isOK(response)) { + // Breakpoint was successfully registered in active session, send breakpoint activated event + breakpointIds.put(dbgBreakpoint, response.getBreakpointID()); + debugCallback.onEvent(new BreakpointActivatedEventImpl(dbgBreakpoint.getVfsBreakpoint())); + } + } + + private void sendDeleteBreakpoint(int breakpointId) { + debugConnection.sendRequest(new DeleteBreakpointRequest(breakpointId)); + } + + private void sendDeleteAllBreakpoints() { + debugConnection.sendRequest(new DeleteAllBreakpointsRequest()); + } + + private void sendStepOver() { + debugConnection.sendRequest(new StepOverRequest()); + } + + private void sendStepInto() { + debugConnection.sendRequest(new StepIntoRequest()); + } + + private void sendStepOut() { + debugConnection.sendRequest(new StepOutRequest()); + } + + private void sendGo() { + debugConnection.sendRequest(new GoRequest()); + } + + private void sendCloseSession() { + debugConnection.sendNotification(new CloseSessionNotification()); + } + + private boolean isOK(IDbgEngineResponse response) { + return response != null && response.getStatus() == 0; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/AbstractDbgMessage.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/AbstractDbgMessage.java new file mode 100644 index 00000000000..b930798dbcb --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/AbstractDbgMessage.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.connection; + +/** + * Abstract Zend debug message (common for client and engine messages). + * + * @author Bartlomiej Laczkowski + */ +public abstract class AbstractDbgMessage implements IDbgMessage { + + @Override + public String getTransferEncoding() { + return ENCODING; + } + + @Override + public void setTransferEncoding(String encoding) { + // TODO - support user preferred encoding + } + + @Override + public String toString() { + return new StringBuilder(this.getClass().getSimpleName()).append(" [ID=").append(getType()).append(']') + .toString(); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/IDbgMessage.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/IDbgMessage.java new file mode 100644 index 00000000000..9e3ce0f47dd --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/IDbgMessage.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.connection; + +/** + * Common Zend debug message interface. + * + * @author Bartlomiej Laczkowski + */ +public interface IDbgMessage { + + // UTF-8 only for now (preference in the future?) + public static final String ENCODING = "UTF-8"; + + /** + * Return unique type id of this debug message + * + * @return message type + */ + public int getType(); + + /** + * Sets the debug transfer encoding for this message + * + * @param String + * transfer encoding + */ + public void setTransferEncoding(String encoding); + + /** + * Returns current debug transfer encoding for this message + * + * @return String transfer encoding + */ + public String getTransferEncoding(); + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgClientMessages.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgClientMessages.java new file mode 100644 index 00000000000..2ccf6a95aac --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgClientMessages.java @@ -0,0 +1,507 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.connection; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.AddBreakpointResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.AddFilesResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.AssignValueResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.DeleteAllBreakpointsResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.DeleteBreakpointResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.EvalResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.GetCWDResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.GetCallStackResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.GetStackVariableValueResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.GetVariableValueResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.GoResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.PauseDebuggerResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.SetProtocolResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.StartResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.StepIntoResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.StepOutResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.StepOverResponse; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgConnectionUtils; + +/** + * Zend debug client messages container. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgClientMessages { + + // Notification types + public static final int NOTIFICATION_CONTINUE_PROCESS_FILE = 2010; + public static final int NOTIFICATION_CLOSE_SESSION = 3; + // Request types + public static final int REQUEST_START = 1; + public static final int REQUEST_PAUSE_DEBUGGER = 2; + public static final int REQUEST_STEP_INTO = 11; + public static final int REQUEST_STEP_OVER = 12; + public static final int REQUEST_STEP_OUT = 13; + public static final int REQUEST_GO = 14; + public static final int REQUEST_ADD_BREAKPOINT = 21; + public static final int REQUEST_DELETE_BREAKPOINT = 22; + public static final int REQUEST_DELETE_ALL_BREAKPOINTS = 23; + public static final int REQUEST_EVAL = 31; + public static final int REQUEST_GET_VARIABLE_VALUE = 32; + public static final int REQUEST_ASSIGN_VALUE = 33; + public static final int REQUEST_GET_CALL_STACK = 34; + public static final int REQUEST_GET_STACK_VARIABLE_VALUE = 35; + public static final int REQUEST_GET_CWD = 36; + public static final int REQUEST_ADD_FILES = 38; + public static final int REQUEST_SET_PROTOCOL = 10000; + // Response types + public static final int RESPONSE_GET_LOCAL_FILE_CONTENT = 11001; + + public interface IDbgClientMessage extends IDbgMessage { + + /** + * Serializes this debug message to an output stream + * + * @param out + * output stream this message is going to be written to + */ + public void serialize(DataOutputStream out) throws IOException; + + } + + public interface IDbgClientNotification extends IDbgClientMessage { + } + + public interface IDbgClientRequest extends IDbgClientMessage { + + /** + * Set the client request id. + */ + public void setID(int id); + + /** + * Return the client request id. + */ + public int getID(); + + } + + public interface IDbgClientResponse extends IDbgClientMessage { + + /** + * Return the engine response id. + */ + public int getID(); + + /** + * Return the engine response status. + */ + public int getStatus(); + + } + + private static abstract class AbstractClientRequest extends AbstractDbgMessage + implements IDbgClientRequest { + + private int id; + + @Override + public void setID(int id) { + this.id = id; + } + + @Override + public int getID() { + return this.id; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + out.writeShort(getType()); + out.writeInt(getID()); + } + + } + + private static abstract class AbstractClientResponse extends AbstractDbgMessage implements IDbgClientResponse { + + protected int id; + protected int status; + + public AbstractClientResponse(int id) { + this.id = id; + } + + @Override + public int getID() { + return this.id; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + out.writeShort(getType()); + out.writeInt(getID()); + out.writeInt(getStatus()); + } + + } + + private ZendDbgClientMessages() { + } + + // Client notifications + + public static class ContinueProcessFileNotification extends AbstractDbgMessage implements IDbgClientNotification { + + @Override + public int getType() { + return NOTIFICATION_CONTINUE_PROCESS_FILE; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + out.writeShort(getType()); + } + } + + public static class CloseSessionNotification extends AbstractDbgMessage implements IDbgClientNotification { + + @Override + public int getType() { + return NOTIFICATION_CLOSE_SESSION; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + out.writeShort(getType()); + } + } + + // Client requests + + public static class AddBreakpointRequest extends AbstractClientRequest { + + private int kind; + private int lifeTime; + private int lineNumber; + private String fileName; + + public AddBreakpointRequest(int kind, int lifeTime, int line, String fileName) { + this.kind = kind; + this.lifeTime = lifeTime; + this.lineNumber = line; + this.fileName = fileName; + } + + @Override + public int getType() { + return REQUEST_ADD_BREAKPOINT; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + out.writeShort(kind); + out.writeShort(lifeTime); + ZendDbgConnectionUtils.writeString(out, fileName); + out.writeInt(lineNumber); + } + } + + public static class AddFilesRequest extends AbstractClientRequest { + + private Set paths; + + public AddFilesRequest(Set paths) { + this.paths = paths; + } + + @Override + public int getType() { + return REQUEST_ADD_FILES; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + out.writeInt(paths.size()); + for (String path : paths) { + ZendDbgConnectionUtils.writeString(out, path); + } + } + } + + public static class AssignValueRequest extends AbstractClientRequest { + + private String var; + private String value; + private int depth; + private List path; + + public AssignValueRequest(String var, String value, int depth, List path) { + this.var = var; + this.value = value; + this.depth = depth; + this.path = path; + } + + @Override + public int getType() { + return REQUEST_ASSIGN_VALUE; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + ZendDbgConnectionUtils.writeEncodedString(out, var, getTransferEncoding()); + ZendDbgConnectionUtils.writeEncodedString(out, value, getTransferEncoding()); + out.writeInt(depth); + out.writeInt(path.size()); + for (String p : path) { + ZendDbgConnectionUtils.writeString(out, p); + } + } + } + + public static class DeleteAllBreakpointsRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_DELETE_ALL_BREAKPOINTS; + } + } + + public static class DeleteBreakpointRequest extends AbstractClientRequest { + + private int breakpointId; + + public DeleteBreakpointRequest(int breakpointId) { + this.breakpointId = breakpointId; + } + + @Override + public int getType() { + return REQUEST_DELETE_BREAKPOINT; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + out.writeInt(breakpointId); + } + } + + public static class EvalRequest extends AbstractClientRequest { + + private String command; + + public EvalRequest(String command) { + this.command = command; + } + + @Override + public int getType() { + return REQUEST_EVAL; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + ZendDbgConnectionUtils.writeEncodedString(out, command, getTransferEncoding()); + } + } + + public static class GetCallStackRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_GET_CALL_STACK; + } + } + + public static class GetCWDRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_GET_CWD; + } + } + + public static class GetStackVariableValueRequest extends AbstractClientRequest { + + private String var; + private int depth; + private int layerDepth; + private List path; + + public GetStackVariableValueRequest(String var, int depth, int layerDepth, List path) { + this.var = var; + this.depth = depth; + this.layerDepth = layerDepth; + this.path = path; + } + + @Override + public int getType() { + return REQUEST_GET_STACK_VARIABLE_VALUE; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + out.writeInt(layerDepth); + ZendDbgConnectionUtils.writeEncodedString(out, var, getTransferEncoding()); + out.writeInt(depth); + out.writeInt(path.size()); + for (String p : path) { + ZendDbgConnectionUtils.writeString(out, p); + } + } + } + + public static class GetVariableValueRequest extends AbstractClientRequest { + + private String var; + private int depth; + private List path; + + public GetVariableValueRequest(String var, int depth, List path) { + this.var = var; + this.depth = depth; + this.path = path; + } + + @Override + public int getType() { + return REQUEST_GET_VARIABLE_VALUE; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + ZendDbgConnectionUtils.writeEncodedString(out, var, getTransferEncoding()); + out.writeInt(depth); + out.writeInt(path.size()); + for (String p : path) { + ZendDbgConnectionUtils.writeString(out, p); + } + } + } + + public static class GoRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_GO; + } + } + + public static class PauseDebuggerRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_PAUSE_DEBUGGER; + } + } + + public static class SetProtocolRequest extends AbstractClientRequest { + + private int protocolID; + + public SetProtocolRequest(int protocolID) { + this.protocolID = protocolID; + } + + @Override + public int getType() { + return REQUEST_SET_PROTOCOL; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + out.writeInt(protocolID); + } + } + + public static class StartRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_START; + } + } + + public static class StepIntoRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_STEP_INTO; + } + } + + public static class StepOutRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_STEP_OUT; + } + } + + public static class StepOverRequest extends AbstractClientRequest { + + @Override + public int getType() { + return REQUEST_STEP_OVER; + } + } + + // Client responses + + public static class GetLocalFileContentResponse extends AbstractClientResponse { + + public static final int STATUS_FAILURE = -1; + public static final int STATUS_SUCCESS = 0; + public static final int STATUS_FILES_IDENTICAL = 302; + + private byte content[] = null; + + public GetLocalFileContentResponse(int id, int status, byte[] content) { + super(id); + this.status = status; + this.content = content; + } + + @Override + public void serialize(DataOutputStream out) throws IOException { + super.serialize(out); + if (content != null) { + out.write(content.length); + out.write(content); + } else { + out.writeInt(0); + } + } + + @Override + public int getType() { + return RESPONSE_GET_LOCAL_FILE_CONTENT; + } + + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgConnection.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgConnection.java new file mode 100644 index 00000000000..861fecbbca1 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgConnection.java @@ -0,0 +1,354 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.connection; + +import static org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.NOTIFICATION_CLOSE_SESSION; +import static org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.NOTIFICATION_CLOSE_MESSAGE_HANDLER; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +import org.eclipse.che.plugin.zdb.server.ZendDebugger; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.IDbgClientMessage; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.IDbgClientNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.IDbgClientRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.IDbgClientResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.CloseMessageHandlerNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineMessage; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineNotification; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineResponse; +import org.eclipse.che.plugin.zdb.server.exceptions.ZendDbgTimeoutException; + +/** + * The debug connection is responsible for initializing and handling a debug + * session that was triggered by debugger engine. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgConnection { + + private final class EngineConnectionRunnable implements Runnable { + + private ServerSocket debugSocket; + private Socket socket; + private DataInputStream inputStream; + private DataOutputStream outputStream; + + private EngineConnectionRunnable() { + open(); + } + + @Override + public void run() { + while (!debugSocket.isClosed()) { + try (Socket socket = debugSocket.accept(); + DataInputStream inputStream = new DataInputStream(socket.getInputStream()); + DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());) { + socket.setReceiveBufferSize(1024 * 128); + socket.setSendBufferSize(1024 * 128); + socket.setTcpNoDelay(true); + this.socket = socket; + this.inputStream = inputStream; + this.outputStream = outputStream; + read(); + } catch (Exception e) { + if (debugSocket.isClosed()) { + break; + } + ZendDebugger.LOG.error(e.getMessage(), e); + } + } + engineMessageRunnable.queue(new CloseMessageHandlerNotification()); + } + + private void open() { + try { + if (debugSettings.isUseSsslEncryption()) { + SSLServerSocket sslServerSocket = (SSLServerSocket) SSLServerSocketFactory.getDefault() + .createServerSocket(debugSettings.getDebugPort()); + sslServerSocket.setEnabledCipherSuites(sslServerSocket.getSupportedCipherSuites()); + this.debugSocket = sslServerSocket; + } else { + this.debugSocket = new ServerSocket(debugSettings.getDebugPort()); + } + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + } + + private void read() { + isConnected = true; + while (true) { + try { + // Reads the message length + int length = inputStream.readInt(); + if (length < 0) { + ZendDebugger.LOG.error( + "Zend debugger engine is probably using SSL, please check 'Use SSL encryption' option."); + purge(); + break; + } + // Engine message arrived. read its type identifier. + int messageType = inputStream.readShort(); + IDbgEngineMessage engineMessage = ZendDbgEngineMessages.create(messageType); + engineMessage.deserialize(inputStream); + if (engineMessage instanceof IDbgEngineResponse) { + // Engine response has arrived... + IDbgEngineResponse response = (IDbgEngineResponse) engineMessage; + EngineSyncResponse syncResponse = engineSyncResponses + .remove(response.getID()); + if (syncResponse != null) { + // Release waiting request provider + syncResponse.set(response); + continue; + } + } else { + // Notification or request from engine arrived... + engineMessageRunnable.queue(engineMessage); + } + } catch (EOFException e) { + // Engine closed the session + break; + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + break; + } + } + isConnected = false; + } + + private void write(IDbgClientMessage clientMessage) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); + try { + clientMessage.serialize(dataOutputStream); + int messageSize = byteArrayOutputStream.size(); + // Write to connection output + outputStream.writeInt(messageSize); + byteArrayOutputStream.writeTo(outputStream); + outputStream.flush(); + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + if (clientMessage.getType() == NOTIFICATION_CLOSE_SESSION) { + purge(); + } + } + + private void purge() { + if (socket != null && !socket.isClosed()) { + try { + socket.shutdownInput(); + socket.shutdownOutput(); + } catch (Exception e) { + // ignore + } + } + } + + private void close() { + try { + purge(); + debugSocket.close(); + } catch (IOException e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + } + + } + + private final class EngineMessageRunnable implements Runnable { + + private BlockingQueue messageQueue = new ArrayBlockingQueue(100); + + @Override + public void run() { + while (true) { + try { + IDbgEngineMessage message = messageQueue.take(); + if (message.getType() == NOTIFICATION_CLOSE_MESSAGE_HANDLER) + break; + if (message instanceof IDbgEngineNotification) { + engineMessageHandler.handleNotification((IDbgEngineNotification) message); + } else if (message instanceof IDbgEngineRequest) { + IDbgClientResponse response = engineMessageHandler + .handleRequest((IDbgEngineRequest) message); + engineConnectionRunnable.write(response); + } + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + } + } + + private void queue(IDbgEngineMessage m) { + messageQueue.offer(m); + } + + } + + private static final class EngineSyncResponse { + + private static final int TIMEOUT = 10; + + private final Semaphore semaphore = new Semaphore(0);; + private T response; + + void set(T response) { + this.response = response; + semaphore.release(); + } + + T get() throws ZendDbgTimeoutException { + boolean acquired = false; + try { + acquired = semaphore.tryAcquire(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + if (acquired) { + return this.response; + } + throw new ZendDbgTimeoutException(TIMEOUT, TimeUnit.SECONDS); + } + + } + + public interface IEngineMessageHandler { + + void handleNotification(IDbgEngineNotification notification); + + T handleRequest(IDbgEngineRequest request); + + } + + private EngineConnectionRunnable engineConnectionRunnable; + private ExecutorService engineConnectionRunnableExecutor; + private EngineMessageRunnable engineMessageRunnable; + private ExecutorService engineMessageRunnableExecutor; + private Map> engineSyncResponses = new HashMap<>(); + private final ZendDbgSettings debugSettings; + private IEngineMessageHandler engineMessageHandler; + private int debugRequestId = 1000; + private boolean isConnected = false; + + /** + * Constructs a new DebugConnectionThread with a given Socket. + * + * @param socket + */ + public ZendDbgConnection(IEngineMessageHandler engineMessageHandler, ZendDbgSettings debugSettings) { + this.engineMessageHandler = engineMessageHandler; + this.debugSettings = debugSettings; + } + + /** + * Start the connection with debugger. Causes connection & message handler + * threads to be started. + */ + public void connect() { + try { + engineConnectionRunnableExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + final Thread thread = new Thread(r, "ZendDbgClient:" + debugSettings.getDebugPort()); + thread.setDaemon(true); + return thread; + } + }); + engineMessageRunnableExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + final Thread thread = new Thread(r, "ZendDbgMsgHandler"); + thread.setDaemon(true); + return thread; + } + }); + engineConnectionRunnable = new EngineConnectionRunnable(); + engineMessageRunnable = new EngineMessageRunnable(); + engineConnectionRunnableExecutor.execute(engineConnectionRunnable); + engineMessageRunnableExecutor.execute(engineMessageRunnable); + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + } + + /** + * Closes the connection. Causes connection & message handler threads to be + * shutdown. + */ + public void disconnect() { + engineConnectionRunnable.close(); + engineConnectionRunnableExecutor.shutdown(); + engineMessageRunnableExecutor.shutdown(); + } + + /** + * Sends given client request to Zend debugger engine. + * + * @param request + * @return Zend debugger engine response + */ + @SuppressWarnings("unchecked") + public synchronized T sendRequest(IDbgClientRequest request) { + if (!isConnected) { + return null; + } + try { + request.setID(debugRequestId++); + EngineSyncResponse syncResponse = new EngineSyncResponse(); + engineSyncResponses.put(request.getID(), (EngineSyncResponse) syncResponse); + engineConnectionRunnable.write(request); + // Wait for response + return syncResponse.get(); + } catch (ZendDbgTimeoutException e) { + ZendDebugger.LOG.error("Could not get debugger engine response for " + request.toString(), e); + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + return null; + } + + /** + * Sends given client notification to Zend debugger engine. + * + * @param request + */ + public synchronized void sendNotification(IDbgClientNotification request) { + if (!isConnected) { + return; + } + try { + engineConnectionRunnable.write(request); + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgEngineMessages.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgEngineMessages.java new file mode 100644 index 00000000000..0ec69bc0267 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgEngineMessages.java @@ -0,0 +1,744 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.connection; + +import java.io.DataInputStream; +import java.io.IOException; +import java.net.URLDecoder; + +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.GetLocalFileContentResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.IDbgClientResponse; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgConnectionUtils; + +/** + * Zend debug engine messages container. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgEngineMessages { + + // Notification types + public static final int NOTIFICATION_SRIPT_ENDED = 2002; + public static final int NOTIFICATION_READY = 2003; + public static final int NOTIFICATION_OUTPUT = 2004; + public static final int NOTIFICATION_SESSION_STARTED = 2005; + public static final int NOTIFICATION_PARSING_ERROR = 2006; + public static final int NOTIFICATION_DEBUGGER_ERROR = 2007; + public static final int NOTIFICATION_HEADER_OUTPUT = 2008; + public static final int NOTIFICATION_START_PROCESS_FILE = 2009; + public static final int NOTIFICATION_INI_ALTERED = 2011; + public static final int NOTIFICATION_CLOSE_MESSAGE_HANDLER = 0; + // Response types + public static final int RESPONSE_START = 1001; + public static final int RESPONSE_PAUSE_DEBUGGER = 1002; + public static final int RESPONSE_STEP_INTO = 1011; + public static final int RESPONSE_STEP_OVER = 1012; + public static final int RESPONSE_STEP_OUT = 1013; + public static final int RESPONSE_GO = 1014; + public static final int RESPONSE_ADD_BREAKPOINT = 1021; + public static final int RESPONSE_DELETE_BREAKPOINT = 1022; + public static final int RESPONSE_DELETE_ALL_BREAKPOINTS = 1023; + public static final int RESPONSE_EVAL = 1031; + public static final int RESPONSE_GET_VARIABLE_VALUE = 1032; + public static final int RESPONSE_ASSIGN_VALUE = 1033; + public static final int RESPONSE_GET_CALL_STACK = 1034; + public static final int RESPONSE_GET_STACK_VARIABLE_VALUE = 1035; + public static final int RESPONSE_GET_CWD = 1036; + public static final int RESPONSE_ADD_FILES = 1038; + public static final int RESPONSE_SET_PROTOCOL = 11000; + public static final int RESPONSE_UNKNOWN = 1000; + // Request types + public static final int REQUEST_GET_LOCAL_FILE_CONTENT = 10002; + + public interface IDbgEngineMessage extends IDbgMessage { + + /** + * De-serialize this debug message from an input stream + * + * @param in + * input stream this message is going to be read from + */ + public void deserialize(DataInputStream in) throws IOException; + + } + + public interface IDbgEngineNotification extends IDbgEngineMessage { + } + + public interface IDbgEngineRequest extends IDbgEngineMessage { + + /** + * Return the request id. + */ + public int getID(); + + } + + public interface IDbgEngineResponse extends IDbgEngineMessage { + + /** + * Return the response id. + */ + public int getID(); + + /** + * Return the response status. + */ + public int getStatus(); + + } + + private static abstract class AbstractEngineRequest extends AbstractDbgMessage + implements IDbgEngineRequest { + + private int id; + + @Override + public void deserialize(DataInputStream in) throws IOException { + id = in.readInt(); + } + + @Override + public int getID() { + return id; + } + + } + + private static abstract class AbstractEngineResponse extends AbstractDbgMessage implements IDbgEngineResponse { + + protected int id; + protected int status; + + @Override + public int getID() { + return this.id; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + id = in.readInt(); + status = in.readInt(); + } + } + + private ZendDbgEngineMessages() { + } + + // Engine notifications + + public static class DebuggerErrorNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private int errorLevel = 0; + private String errorText; + + @Override + public int getType() { + return NOTIFICATION_DEBUGGER_ERROR; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + errorLevel = in.readInt(); + errorText = ZendDbgConnectionUtils.readString(in); + } + + public int getErrorLevel() { + return errorLevel; + } + + public String getErrorText() { + return errorText; + } + } + + public static class ScriptEndedNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private int status; + + @Override + public int getType() { + return NOTIFICATION_SRIPT_ENDED; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + status = in.readInt(); + } + + public int getStatus() { + return status; + } + } + + public static class SessionStartedNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private String fileName = ""; + private String uri = ""; + private String query = ""; + private String additionalOptions = ""; + private int protocolID; + + @Override + public int getType() { + return NOTIFICATION_SESSION_STARTED; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + protocolID = in.readInt(); + fileName = ZendDbgConnectionUtils.readString(in); + uri = ZendDbgConnectionUtils.readString(in); + query = URLDecoder.decode(ZendDbgConnectionUtils.readString(in), "UTF-8"); + additionalOptions = ZendDbgConnectionUtils.readString(in); + } + + public String getFileName() { + return fileName; + } + + public String getUri() { + return uri; + } + + public String getQuery() { + return query; + } + + public String getOptions() { + return additionalOptions; + } + + public int getServerProtocolID() { + return protocolID; + } + } + + public static class HeaderOutputNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private String output; + + @Override + public int getType() { + return NOTIFICATION_HEADER_OUTPUT; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + output = ZendDbgConnectionUtils.readString(in); + } + + public String getOutput() { + return this.output; + } + } + + public static class IniAlteredNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private String name; + private String oldValue; + private String newValue; + + @Override + public int getType() { + return NOTIFICATION_INI_ALTERED; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + name = ZendDbgConnectionUtils.readString(in); + oldValue = ZendDbgConnectionUtils.readString(in); + newValue = ZendDbgConnectionUtils.readString(in); + } + + public String getName() { + return name; + } + + public String getOldValue() { + return oldValue; + } + + public String getNewValue() { + return newValue; + } + } + + public static class OutputNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private String output = null; + + @Override + public int getType() { + return NOTIFICATION_OUTPUT; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + output = ZendDbgConnectionUtils.readEncodedString(in, getTransferEncoding()); + } + + public String getOutput() { + return output; + } + } + + public static class ParsingErrorNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private int errorLevel = 0; + private String fileName; + private int lineNumber; + private String errorText; + + @Override + public int getType() { + return NOTIFICATION_PARSING_ERROR; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + errorLevel = in.readInt(); + fileName = ZendDbgConnectionUtils.readString(in); + lineNumber = in.readInt(); + errorText = ZendDbgConnectionUtils.readString(in); + } + + public int getErrorLevel() { + return this.errorLevel; + } + + public String getErrorText() { + return this.errorText; + } + + public String getFileName() { + return this.fileName; + } + + public int getLineNumber() { + return this.lineNumber; + } + } + + public static class ReadyNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private String fileName; + private int lineNumber; + + @Override + public int getType() { + return NOTIFICATION_READY; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + fileName = ZendDbgConnectionUtils.readString(in); + lineNumber = in.readInt(); + in.readInt(); // Read the 4 bytes of the watched-list length. this + // is 0 now. + } + + public String getFileName() { + return fileName; + } + + public int getLineNumber() { + return lineNumber; + } + } + + public static class StartProcessFileNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + private String fileName; + + @Override + public int getType() { + return NOTIFICATION_START_PROCESS_FILE; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + fileName = ZendDbgConnectionUtils.readString(in); + } + + public String getFileName() { + return fileName; + } + } + + // Phantom message used to notify that connection was closed + public static class CloseMessageHandlerNotification extends AbstractDbgMessage implements IDbgEngineNotification { + + @Override + public void deserialize(DataInputStream in) throws IOException { + // dummy + } + + @Override + public int getType() { + return NOTIFICATION_CLOSE_MESSAGE_HANDLER; + } + } + + // Engine responses + + public static class AddBreakpointResponse extends AbstractEngineResponse { + + private int breakPointID; + + public int getBreakpointID() { + return breakPointID; + } + + @Override + public int getType() { + return RESPONSE_ADD_BREAKPOINT; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + super.deserialize(in); + breakPointID = in.readInt(); + } + } + + public static class AddFilesResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_ADD_FILES; + } + } + + public static class AssignValueResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_ASSIGN_VALUE; + } + } + + public static class DeleteAllBreakpointsResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_DELETE_ALL_BREAKPOINTS; + } + } + + public static class DeleteBreakpointResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_DELETE_BREAKPOINT; + } + } + + public static class EvalResponse extends AbstractEngineResponse { + + private String result; + + @Override + public int getType() { + return RESPONSE_EVAL; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + super.deserialize(in); + result = ZendDbgConnectionUtils.readString(in); + } + + public String getResult() { + return result; + } + } + + public static class GetCallStackResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_GET_CALL_STACK; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + id = in.readInt(); + // Just read data for now and do nothing with it... + int depth = in.readInt(); + for (int i = 0; i < depth; i++) { + ZendDbgConnectionUtils.readString(in); + in.readInt(); + ZendDbgConnectionUtils.readString(in); + ZendDbgConnectionUtils.readString(in); + in.readInt(); + ZendDbgConnectionUtils.readString(in); + int params = in.readInt(); + for (int j = 0; j < params; j++) { + ZendDbgConnectionUtils.readEncodedString(in, getTransferEncoding()); + ZendDbgConnectionUtils.readStringAsBytes(in); + } + } + } + } + + public static class GetCWDResponse extends AbstractEngineResponse { + + private String cwd; + + @Override + public int getType() { + return RESPONSE_GET_CWD; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + super.deserialize(in); + cwd = ZendDbgConnectionUtils.readString(in); + } + + public String getCWD() { + return cwd; + } + } + + public static class GetStackVariableValueResponse extends AbstractEngineResponse { + + private byte[] varResult; + + @Override + public int getType() { + return RESPONSE_GET_STACK_VARIABLE_VALUE; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + super.deserialize(in); + varResult = ZendDbgConnectionUtils.readStringAsBytes(in); + } + + public byte[] getVarResult() { + return varResult; + } + } + + public static class GetVariableValueResponse extends AbstractEngineResponse { + + private byte[] variableValue = null; + + @Override + public int getType() { + return RESPONSE_GET_VARIABLE_VALUE; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + super.deserialize(in); + variableValue = ZendDbgConnectionUtils.readStringAsBytes(in); + } + + public byte[] getVariableValue() { + return variableValue; + } + } + + public static class GoResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_GO; + } + } + + public static class PauseDebuggerResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_PAUSE_DEBUGGER; + } + } + + public static class SetProtocolResponse extends AbstractEngineResponse { + + private int protocolID; + + @Override + public int getType() { + return RESPONSE_SET_PROTOCOL; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + id = in.readInt(); + protocolID = in.readInt(); + } + + public int getProtocolID() { + return protocolID; + } + } + + public static class StartResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_START; + } + } + + public static class StepIntoResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_STEP_INTO; + } + } + + public static class StepOutResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_STEP_OUT; + } + } + + public static class StepOverResponse extends AbstractEngineResponse { + + @Override + public int getType() { + return RESPONSE_STEP_OVER; + } + } + + public static class UnknownMessageResponse extends AbstractEngineResponse { + + private int origint; + + @Override + public int getType() { + return RESPONSE_UNKNOWN; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + id = in.readInt(); + origint = in.readInt(); + } + + public int getOriginalInt() { + return origint; + } + } + + // Engine requests + + public static class GetLocalFileContentRequest extends AbstractEngineRequest { + + private String fileName; + private int size; + private int checkSum; + + @Override + public int getType() { + return REQUEST_GET_LOCAL_FILE_CONTENT; + } + + @Override + public void deserialize(DataInputStream in) throws IOException { + super.deserialize(in); + fileName = ZendDbgConnectionUtils.readString(in); + size = in.readInt(); + checkSum = in.readInt(); + } + + public String getFileName() { + return fileName; + } + + public int getSize() { + return size; + } + + public int getCheckSum() { + return checkSum; + } + + } + + public static IDbgEngineMessage create(int type) { + switch (type) { + // Engine notifications + case NOTIFICATION_DEBUGGER_ERROR: + return new DebuggerErrorNotification(); + case NOTIFICATION_HEADER_OUTPUT: + return new HeaderOutputNotification(); + case NOTIFICATION_INI_ALTERED: + return new IniAlteredNotification(); + case NOTIFICATION_OUTPUT: + return new OutputNotification(); + case NOTIFICATION_PARSING_ERROR: + return new ParsingErrorNotification(); + case NOTIFICATION_READY: + return new ReadyNotification(); + case NOTIFICATION_SESSION_STARTED: + return new SessionStartedNotification(); + case NOTIFICATION_SRIPT_ENDED: + return new ScriptEndedNotification(); + case NOTIFICATION_START_PROCESS_FILE: + return new StartProcessFileNotification(); + // Engine responses + case RESPONSE_ADD_BREAKPOINT: + return new AddBreakpointResponse(); + case RESPONSE_ADD_FILES: + return new AddFilesResponse(); + case RESPONSE_ASSIGN_VALUE: + return new AssignValueResponse(); + case RESPONSE_DELETE_ALL_BREAKPOINTS: + return new DeleteAllBreakpointsResponse(); + case RESPONSE_DELETE_BREAKPOINT: + return new DeleteBreakpointResponse(); + case RESPONSE_EVAL: + return new EvalResponse(); + case RESPONSE_GET_CALL_STACK: + return new GetCallStackResponse(); + case RESPONSE_GET_CWD: + return new GetCWDResponse(); + case RESPONSE_GET_STACK_VARIABLE_VALUE: + return new GetStackVariableValueResponse(); + case RESPONSE_GET_VARIABLE_VALUE: + return new GetVariableValueResponse(); + case RESPONSE_GO: + return new GoResponse(); + case RESPONSE_PAUSE_DEBUGGER: + return new PauseDebuggerResponse(); + case RESPONSE_SET_PROTOCOL: + return new SetProtocolResponse(); + case RESPONSE_START: + return new StartResponse(); + case RESPONSE_STEP_INTO: + return new StepIntoResponse(); + case RESPONSE_STEP_OUT: + return new StepOutResponse(); + case RESPONSE_STEP_OVER: + return new StepOverResponse(); + // Engine requests + case REQUEST_GET_LOCAL_FILE_CONTENT: + return new GetLocalFileContentRequest(); + } + return null; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgSettings.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgSettings.java new file mode 100644 index 00000000000..f1c82bab77b --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/connection/ZendDbgSettings.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.connection; + +/** + * Zend debug session settings container. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgSettings { + + private final int debugPort; + private final String clientHostIP; + private final boolean breakAtFirstLine; + private final boolean useSsslEncryption; + + public ZendDbgSettings(int debugPort, String clientHostIP, boolean breakAtFirstLine, boolean useSsslEncryption) { + super(); + this.debugPort = debugPort; + this.clientHostIP = clientHostIP; + this.breakAtFirstLine = breakAtFirstLine; + this.useSsslEncryption = useSsslEncryption; + } + + /** + * Returns debug port. + * + * @return debug port + */ + public int getDebugPort() { + return debugPort; + } + + /** + * Returns client host/IP. + * + * @return client host/IP + */ + public String getClientHostIP() { + return clientHostIP; + } + + /** + * Returns value of 'Break at first line' option. + * + * @return value of 'Break at first line' option + */ + public boolean isBreakAtFirstLine() { + return breakAtFirstLine; + } + + /** + * Returns value of 'Use SSL encoding' option. + * + * @return value of 'Use SSL encoding' option + */ + public boolean isUseSsslEncryption() { + return useSsslEncryption; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/exceptions/ZendDbgTimeoutException.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/exceptions/ZendDbgTimeoutException.java new file mode 100644 index 00000000000..56f876bd507 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/exceptions/ZendDbgTimeoutException.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.exceptions; + +import java.text.MessageFormat; +import java.util.concurrent.TimeUnit; + +import org.eclipse.che.api.debugger.server.exceptions.DebuggerException; + +/** + * Simple timeout exception. + * + * @author Bartlomiej Laczkowski + */ +@SuppressWarnings("serial") +public class ZendDbgTimeoutException extends DebuggerException { + + public ZendDbgTimeoutException(int timeout, TimeUnit unit) { + super(MessageFormat.format("Response timeout ({0} {1}) occurred.", timeout, unit.name())); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataFacet.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataFacet.java new file mode 100644 index 00000000000..fe4209a8e11 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataFacet.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.expressions; + +/** + * Common interface for debug variables that might be described with the use of + * additional facets that provides information about some useful meta-data like + * variable kind, visibility, accessibility, etc. + * + * @author Bartlomiej Laczkowski + */ +public interface IDbgDataFacet { + + /** + * Variable facets. + */ + public enum Facet { + + KIND_THIS, KIND_SUPER_GLOBAL, KIND_LOCAL, KIND_OBJECT_MEMBER, KIND_ARRAY_MEMBER, KIND_RESOURCE, MOD_PUBLIC, MOD_PROTECTED, MOD_PRIVATE, MOD_STATIC, VIRTUAL_CLASS; + + } + + /** + * Checks if variable has given facet. + * + * @param facet + * @return true if variable has given facet, false + * otherwise + */ + public boolean hasFacet(Facet facet); + + /** + * Adds facet(s) to the variable description. + * + * @param facets + */ + public void addFacets(Facet... facets); + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataType.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataType.java new file mode 100644 index 00000000000..088d0e0bc25 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgDataType.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.expressions; + +/** + * Interface for variables/values that are responsible for handling the + * particular PHP data type. + * + * @author Bartlomiej Laczkowski + */ +public interface IDbgDataType { + + /** + * PHP data type enum. + */ + public enum DataType { + + PHP_BOOL("bool"), PHP_INT("int"), PHP_FLOAT("float"), PHP_STRING("string"), PHP_NULL("null"), PHP_ARRAY( + "array"), PHP_OBJECT("object"), PHP_RESOURCE("resource"), PHP_VIRTUAL_CLASS("class"), PHP_UNINITIALIZED( + ""); + + private String type; + + private DataType(String type) { + this.type = type; + } + + public String getText() { + return type; + } + + /** + * Finds data type enum element by corresponding string value. + * + * @param type + * @return data type enum element + */ + public static DataType find(String type) { + for (DataType t : values()) { + if (t.getText().equalsIgnoreCase(type)) + return t; + } + return PHP_UNINITIALIZED; + } + + } + + /** + * Returns related PHP data type. + * + * @return related PHP data type + */ + public DataType getDataType(); + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgExpression.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgExpression.java new file mode 100644 index 00000000000..88184ea6ebe --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/IDbgExpression.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.expressions; + +import java.util.List; + +/** + * Common interface for Zend dbg expressions. + * + * @author Bartlomiej Laczkowski + */ +public interface IDbgExpression extends IDbgDataFacet, IDbgDataType { + + /** + * Returns textual representation/statement for this expression. + * + * @return textual representation/statement for this expression + */ + public String getExpression(); + + /** + * Returns expressions chain (from entry expression to current expression). + * + * @return expressions chain (from entry expression to current expression) + */ + public List getExpressionChain(); + + /** + * Returns expression value children. + * + * @return expression value children + */ + public List getChildren(); + + /** + * Returns number of existing children. + * + * @return number of existing children + */ + public int getChildrenCount(); + + /** + * Returns expression value string. + * + * @return expression value string + */ + public String getValue(); + + /** + * Returns expression value string. + * + * @return expression value string + */ + public boolean setValue(String value); + + /** + * Evaluates this expression (computes its value on engine side). + */ + public void evaluate(); + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpression.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpression.java new file mode 100644 index 00000000000..57eff014dbe --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpression.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.expressions; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Abstract implementation of Zend debug expression. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgExpression implements IDbgExpression { + + private final String expression; + private final List expressionChain; + private final ZendDbgExpressionEvaluator expressionEvaluator; + private final Set expressionFacets = new HashSet(); + private ZendDbgExpressionResult expressionResult; + + public ZendDbgExpression(ZendDbgExpressionEvaluator expressionEvaluator, String expression, + List expressionChain, Facet... facets) { + this.expressionEvaluator = expressionEvaluator; + this.expression = expression; + this.expressionChain = expressionChain; + this.expressionResult = ZendDbgExpressionResult.NULL; + addFacets(facets); + } + + @Override + public String getExpression() { + return expression; + } + + @Override + public List getExpressionChain() { + return expressionChain; + } + + @Override + public int getChildrenCount() { + return expressionResult.getChildrenCount(); + } + + @Override + public List getChildren() { + return expressionResult.getChildren(); + } + + @Override + public String getValue() { + return expressionResult.getValue(); + } + + @Override + public boolean setValue(String value) { + return expressionEvaluator.assign(this, value, 1); + } + + @Override + public void evaluate() { + expressionEvaluator.evaluate(this, 1); + } + + @Override + public boolean hasFacet(Facet facet) { + return expressionFacets.contains(facet); + } + + @Override + public void addFacets(Facet... facets) { + for (Facet facet : facets) + this.expressionFacets.add(facet); + } + + @Override + public DataType getDataType() { + return expressionResult.getDataType(); + } + + protected ZendDbgExpressionEvaluator getExpressionEvaluator() { + return expressionEvaluator; + } + + protected void setExpressionResult(ZendDbgExpressionResult expressionResult) { + this.expressionResult = expressionResult; + } + + protected ZendDbgExpression createChild(String expression, Facet... facets) { + List chain = new ArrayList<>(getExpressionChain()); + chain.add(expression); + return new ZendDbgExpression(expressionEvaluator, expression, chain, facets); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionEvaluator.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionEvaluator.java new file mode 100644 index 00000000000..bb85ac28ebd --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionEvaluator.java @@ -0,0 +1,319 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.expressions; + +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.KIND_ARRAY_MEMBER; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.KIND_OBJECT_MEMBER; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.MOD_PRIVATE; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.MOD_PROTECTED; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.MOD_PUBLIC; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_ARRAY; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_BOOL; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_FLOAT; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_INT; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_OBJECT; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_RESOURCE; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_STRING; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.che.plugin.zdb.server.ZendDebugger; +import org.eclipse.che.plugin.zdb.server.connection.IDbgMessage; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.AssignValueRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgClientMessages.GetVariableValueRequest; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgConnection; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.AssignValueResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.GetVariableValueResponse; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgEngineMessages.IDbgEngineResponse; +import org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet; + +/** + * Zend debug expressions manager. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgExpressionEvaluator { + + private static class ValueDecoder { + + public void deserialize(ZendDbgExpression expression, byte[] value) { + if (value == null) { + // Expression is illegal. + value = new byte[] { 'N' }; + } + read(expression, new ValueReader(value)); + } + + private void read(ZendDbgExpression expression, ValueReader reader) { + char type = reader.readType(); + switch (type) { + case 'i': { + readIntType(expression, reader); + break; + } + case 'd': { + readFloatType(expression, reader); + break; + } + case 's': { + readSringType(expression, reader); + break; + } + case 'b': { + readBooleanType(expression, reader); + break; + } + case 'r': { + readResourceType(expression, reader); + break; + } + case 'a': { + readArrayType(expression, reader); + break; + } + case 'O': { + readObjectType(expression, reader); + break; + } + default: + break; + } + } + + private void readIntType(ZendDbgExpression expression, ValueReader reader) { + String value = reader.readToken(); + expression.setExpressionResult(new ZendDbgExpressionResult(value, PHP_INT)); + } + + private void readFloatType(ZendDbgExpression expression, ValueReader reader) { + String value = reader.readToken(); + expression.setExpressionResult(new ZendDbgExpressionResult(value, PHP_FLOAT)); + } + + private void readSringType(ZendDbgExpression expression, ValueReader reader) { + String value = reader.readString(); + expression.setExpressionResult(new ZendDbgExpressionResult(value, PHP_STRING)); + } + + private void readBooleanType(ZendDbgExpression expression, ValueReader reader) { + String value = reader.readToken(); + expression.setExpressionResult(new ZendDbgExpressionResult(value, PHP_BOOL)); + } + + private void readResourceType(ZendDbgExpression expression, ValueReader reader) { + // Read resource number and move on... + reader.readInt(); + reader.readInt(); + String value = reader.readToken(); + expression.setExpressionResult(new ZendDbgExpressionResult(value, PHP_RESOURCE)); + } + + private void readArrayType(ZendDbgExpression expression, ValueReader reader) { + int arrayLength = reader.readInt(); + String arrayDescriptor = "array [" + arrayLength + "]"; + if (reader.isEnd()) { + expression.setExpressionResult(new ZendDbgExpressionResult(arrayDescriptor, PHP_ARRAY, arrayLength)); + return; + } + List childExpressions = new ArrayList<>(); + for (int i = 0; i < arrayLength; i++) { + char type = reader.readType(); + String name; + if (type == 'i') { + name = Integer.toString(reader.readInt()); + } else if (type == 's') { + name = reader.readString(); + } else { + // Fall back when type is invalid + return; + } + ZendDbgExpression childExpression = expression.createChild(name, KIND_ARRAY_MEMBER); + childExpressions.add(childExpression); + read(childExpression, reader); + } + expression.setExpressionResult( + new ZendDbgExpressionResult(arrayDescriptor, PHP_OBJECT, arrayLength, childExpressions)); + } + + private void readObjectType(ZendDbgExpression expression, ValueReader reader) { + String className = reader.readString(); + int objectLength = reader.readInt(); + if (reader.isEnd()) { + expression.setExpressionResult(new ZendDbgExpressionResult(className, PHP_OBJECT, objectLength)); + return; + } + List childExpressions = new ArrayList<>(); + for (int i = 0; i < objectLength; i++) { + char type = reader.readType(); + String name; + if (type == 'i') { + name = Integer.toString(reader.readInt()); + } else if (type == 's') { + name = reader.readString(); + } else { + // Fall back when type is invalid + return; + } + ZendDbgExpression childExpression; + Facet fieldFacet = MOD_PUBLIC; + if (name.startsWith("*::")) { + fieldFacet = MOD_PROTECTED; + } else if (name.contains("::")) { + fieldFacet = MOD_PRIVATE; + } + childExpression = expression.createChild(name, KIND_OBJECT_MEMBER, fieldFacet); + childExpressions.add(childExpression); + read(childExpression, reader); + } + expression.setExpressionResult( + new ZendDbgExpressionResult(className, PHP_OBJECT, objectLength, childExpressions)); + } + + } + + private static class ValueReader extends ByteArrayInputStream { + + private ValueReader(byte[] result) { + super(result); + } + + char readType() { + char curr; + do { + int temp = super.read(); + if (temp == -1) { + return ' '; + } + curr = (char) temp; + } while (curr == ';' || curr == ':' || curr == '{' || curr == '}'); + return curr; + } + + String readToken() { + StringBuffer buffer = new StringBuffer(6); + char curr; + do { + curr = (char) super.read(); + } while (curr == ';' || curr == ':'); + while (curr != ';' && curr != ':') { + buffer.append(curr); + curr = (char) super.read(); + } + return buffer.toString(); + } + + String readString() { + int length = readInt(); + while ((char) super.read() != '"') + ; + byte[] bytes = new byte[length]; + read(bytes, 0, length); + super.read(); // read '"' + return getText(bytes); + } + + int readInt() { + int result = 0; + char curr; + boolean isMinus = false; + do { + curr = (char) super.read(); + if (curr == '-') { + isMinus = true; + } + } while (!Character.isDigit(curr)); + do { + result *= 10; + result += Character.getNumericValue(curr); + this.mark(1); + } while (Character.isDigit(curr = (char) super.read())); + if (isMinus) { + result *= -1; + } + return result; + } + + boolean isEnd() { + this.reset(); + char curr = (char) super.read(); + return curr == ';'; + } + + String getText(byte[] buf) { + try { + return new String(buf, IDbgMessage.ENCODING); + } catch (UnsupportedEncodingException e) { + } + return new String(buf, Charset.defaultCharset()); + } + + } + + private ZendDbgConnection debugConnection; + private ValueDecoder valueDecoder; + + public ZendDbgExpressionEvaluator(ZendDbgConnection debugConnection) { + this.debugConnection = debugConnection; + this.valueDecoder = new ValueDecoder(); + } + + public void evaluate(ZendDbgExpression expression, int depth) { + byte[] value = requestEvaluation(expression, depth); + valueDecoder.deserialize(expression, value); + } + + public boolean assign(ZendDbgExpression expression, String newValue, int depth) { + if (!requestAssignment(expression, newValue, depth)) { + ZendDebugger.LOG.error("Could not assign new value for: " + expression.getExpression() + " variable."); + return false; + } + return true; + } + + private byte[] requestEvaluation(ZendDbgExpression expression, int depth) { + String variableOwner = expression.getExpression(); + List variableElementPath = Collections.emptyList(); + List chain = expression.getExpressionChain(); + if (!chain.isEmpty()) { + variableOwner = chain.get(0); + variableElementPath = chain.subList(1, chain.size()); + } + byte[] value = null; + GetVariableValueResponse response = debugConnection + .sendRequest(new GetVariableValueRequest(variableOwner, depth, variableElementPath)); + if (isOK(response)) { + value = response.getVariableValue(); + } + if (value == null) { + value = new byte[] { 'N' }; + } + return value; + } + + private boolean requestAssignment(ZendDbgExpression expression, String newValue, int depth) { + List path = expression.getExpressionChain(); + String variableOwner = path.get(0); + List variableElementPath = path.subList(1, path.size()); + AssignValueResponse response = debugConnection + .sendRequest(new AssignValueRequest(variableOwner, newValue, depth, variableElementPath)); + return isOK(response); + } + + private boolean isOK(IDbgEngineResponse response) { + return response != null && response.getStatus() == 0; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionResult.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionResult.java new file mode 100644 index 00000000000..dbc48398673 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/expressions/ZendDbgExpressionResult.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.expressions; + +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType.PHP_NULL; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType; + +/** + * Container for storing expression evaluation result. + * + * @author Bartlomiej Laczkowski + */ +class ZendDbgExpressionResult { + + static final ZendDbgExpressionResult NULL = new ZendDbgExpressionResult(PHP_NULL.getText(), DataType.PHP_NULL); + + private final String value; + private final DataType dataType; + private final int childrenCount; + private final List children; + + ZendDbgExpressionResult(String value, DataType dataType) { + this(value, dataType, 0); + } + + ZendDbgExpressionResult(String value, DataType dataType, int childrenCount) { + this(value, dataType, childrenCount, null); + } + + ZendDbgExpressionResult(String value, DataType dataType, int childrenCount, List children) { + super(); + this.value = value; + this.dataType = dataType; + this.childrenCount = childrenCount; + this.children = children != null ? children : Collections.emptyList(); + } + + /** + * Returns textual value for expression result. + * + * @return textual value for expression result + */ + public String getValue() { + return value; + } + + /** + * Returns PHP data type for expression result. + * + * @return PHP data type for expression result + */ + public DataType getDataType() { + return dataType; + } + + /** + * Returns number of child elements for expression result. + * + * @return number of child elements for expression result + */ + public int getChildrenCount() { + return childrenCount; + } + + /** + * Returns child elements for expression result. + * + * @return child elements for expression result + */ + public List getChildren() { + return children; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgConnectionUtils.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgConnectionUtils.java new file mode 100644 index 00000000000..23439d34a06 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgConnectionUtils.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.utils; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.zip.Adler32; + +import org.eclipse.che.plugin.zdb.server.ZendDebugger; +import org.eclipse.che.plugin.zdb.server.connection.IDbgMessage; + +/** + * Connection utilities. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgConnectionUtils { + + /** + * Writes line to data output stream. + * + * @param out + * @param line + * @throws IOException + */ + public static final void writeString(DataOutputStream out, String line) throws IOException { + byte[] byteArray = line.getBytes(Charset.forName(IDbgMessage.ENCODING)); + out.writeInt(byteArray.length); + out.write(byteArray); + } + + /** + * Writes string as bytes to data output stream. + * + * @param out + * @param byteArray + * @throws IOException + */ + public static final void writeStringAsBytes(DataOutputStream out, byte[] byteArray) throws IOException { + out.writeInt(byteArray.length); + out.write(byteArray); + } + + /** + * Writes line to data output stream with the use of given encoding. + * + * @param out + * @param line + * @param encoding + * @throws IOException + */ + public static final void writeEncodedString(DataOutputStream out, String line, String encoding) throws IOException { + byte[] byteArray = getBytesFromText(line, encoding); + out.writeInt(byteArray.length); + out.write(byteArray); + } + + /** + * Reads string from data input stream. + * + * @param in + * @return + * @throws IOException + */ + public static final String readString(DataInputStream in) throws IOException { + return new String(readStringAsBytes(in), Charset.forName(IDbgMessage.ENCODING)); + } + + /** + * Reads string as bytes from data output stream. + * + * @param in + * @return + * @throws IOException + */ + public static final byte[] readStringAsBytes(DataInputStream in) throws IOException { + int size = in.readInt(); + byte[] byteArray = new byte[size]; + in.readFully(byteArray); + return byteArray; + } + + /** + * Reads string from data input stream with the use of given encoding. + * + * @param in + * @param encoding + * @return + * @throws IOException + */ + public static final String readEncodedString(DataInputStream in, String encoding) throws IOException { + byte[] byteArray = readStringAsBytes(in); + String rv = getTextFromBytes(byteArray, encoding); + return rv; + } + + /** + * Computes bytes from text with the use of given encoding. + * + * @param text + * @param encoding + * @return bytes + */ + public static final byte[] getBytesFromText(String text, String encoding) { + try { + return text.getBytes(encoding); + } catch (Exception e) { + } + return text.getBytes(Charset.forName(IDbgMessage.ENCODING)); + } + + /** + * Computes text from bytes with the use of given encoding. + * + * @param bytes + * @param encoding + * @return + */ + public static final String getTextFromBytes(byte[] bytes, String encoding) { + try { + return new String(bytes, encoding); + } catch (Exception e) { + } + return new String(bytes, Charset.forName(IDbgMessage.ENCODING)); + } + + /** + * Checks if remote content is equal to corresponding local one. + * + * @param sizeToCheck + * @param checksumToCheck + * @param content + * @return true if is equal, false otherwise + */ + public static final boolean isRemoteContentEqual(int sizeToCheck, int checksumToCheck, byte[] content) { + int checksum; + if (sizeToCheck == content.length) { + checksum = getContentCheckSum(content); + return (checksumToCheck == checksum); + } + // Checks if the difference is just in the line endings + try { + int linesCount = 0; + byte r = 13; + byte n = 10; + for (byte element : content) { + if (element == n) { + linesCount++; + } + } + if (sizeToCheck == content.length + linesCount) { + byte converted[] = new byte[content.length + linesCount]; + int i = 0; + // Convert line endings UNIX -> Win + for (byte element : content) { + if (element == n) { + converted[i] = r; + i++; + } + converted[i] = element; + i++; + } + checksum = getContentCheckSum(converted); + if (checksumToCheck == checksum) { + return true; + } + // Convert line endings Win -> UNIX + for (int j = 0; j < content.length; j++) { + if (content[j] == n) { + converted[j] = r; + } else if (content[j] == r) { + converted[j] = n; + } + } + checksum = getContentCheckSum(converted); + return (checksumToCheck == checksum); + } + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + return false; + } + + /** + * Computes check-sum for Zend debugger content comparison. + * + * @param content + * @return check-sum + */ + public static final int getContentCheckSum(byte[] content) { + Adler32 checksumCalculator = new Adler32(); + checksumCalculator.update(content); + return (int) checksumCalculator.getValue(); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgFileUtils.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgFileUtils.java new file mode 100644 index 00000000000..87eb328f753 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgFileUtils.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.utils; + +import java.io.File; + +import javax.inject.Inject; + +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.project.server.ProjectManager; +import org.eclipse.che.api.project.server.VirtualFileEntry; +import org.eclipse.che.api.vfs.Path; +import org.eclipse.che.plugin.zdb.server.ZendDebugger; + +import com.google.inject.Singleton; + +/** + * Zend debug utils. + * + * @author Bartlomiej Laczkowski + */ +@Singleton +public class ZendDbgFileUtils { + + private static ProjectManager projectManager; + + @Inject + public ZendDbgFileUtils(ProjectManager projectManager) { + ZendDbgFileUtils.projectManager = projectManager; + } + + /** + * Finds local file entry that corresponds to remote file path. + * + * @param remotePath + * @return corresponding local file entry + */ + public static VirtualFileEntry findVirtualFileEntry(String remotePath) { + Path remoteFilePath = Path.of(remotePath); + try { + for (int i = 0; i < remoteFilePath.length(); i++) { + Path path = remoteFilePath.subPath(i); + VirtualFileEntry child = getVirtualFileEntry(path.toString()); + if (child != null) { + return child; + } + } + } catch (Exception e) { + ZendDebugger.LOG.error(e.getMessage(), e); + return null; + } + return null; + } + + /** + * Returns local file absolute path. + * + * @param vfsPath + * @return local file absolute path + */ + public static String findAbsolutePath(String vfsPath) { + VirtualFileEntry virtualFileEntry = getVirtualFileEntry(vfsPath); + if (virtualFileEntry != null) { + File ioFile = virtualFileEntry.getVirtualFile().toIoFile(); + if (ioFile != null) { + return ioFile.getAbsolutePath(); + } + return virtualFileEntry.getVirtualFile().getPath().toString(); + } + return vfsPath; + } + + private static VirtualFileEntry getVirtualFileEntry(String path) { + VirtualFileEntry virtualFileEntry = null; + try { + virtualFileEntry = projectManager.getProjectsRoot().getChild(path); + } catch (ServerException e) { + ZendDebugger.LOG.error(e.getMessage(), e); + } + return virtualFileEntry; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgVariableUtils.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgVariableUtils.java new file mode 100644 index 00000000000..b14bf01f702 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/utils/ZendDbgVariableUtils.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.utils; + +/** + * Debug variable utilities. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgVariableUtils { + + public static final String[] SUPER_GLOBALS = new String[] { "$GLOBALS", "$_SERVER", "$_GET", "$_POST", "$_FILES", + "$_COOKIE", "$_SESSION", "$_REQUEST", "$_ENV" }; + public static final String THIS = "$this"; + + /** + * Checks if variable name is 'this' variable name. + * + * @param name + * @return true if variable name is 'this' variable name, + * false otherwise + */ + public static boolean isThis(String name) { + return THIS.equalsIgnoreCase(name); + } + + /** + * Checks if variable name is one of the global variables. + * + * @param name + * @return true if variable name is global variable name, + * false otherwise + */ + public static boolean isSuperGlobal(String name) { + for (int i = 0; i < SUPER_GLOBALS.length; i++) + if (SUPER_GLOBALS[i].equalsIgnoreCase(name)) + return true; + return false; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/IDbgVariable.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/IDbgVariable.java new file mode 100644 index 00000000000..508ca82a85f --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/IDbgVariable.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.variables; + +import java.util.List; + +import org.eclipse.che.api.debug.shared.model.Variable; + +/** + * Zend debugger specific variable. + * + * @author Bartlomiej Laczkowski + */ +public interface IDbgVariable extends Variable { + + @Override + List getVariables(); + + /** + * Requests child variables computation. + */ + public void makeComplete(); + + /** + * Assigns new value to this variable. + * + * @param newValue + */ + public void setValue(String newValue); + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariable.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariable.java new file mode 100644 index 00000000000..37b8063e9ee --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariable.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.variables; + +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.KIND_ARRAY_MEMBER; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.KIND_OBJECT_MEMBER; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.che.api.debug.shared.model.VariablePath; +import org.eclipse.che.api.debug.shared.model.impl.VariablePathImpl; +import org.eclipse.che.plugin.zdb.server.expressions.IDbgDataType.DataType; +import org.eclipse.che.plugin.zdb.server.expressions.IDbgExpression; + +/** + * PHP Zend debugger specific variable. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgVariable implements IDbgVariable { + private final IDbgExpression zendDbgExpression; + private final VariablePath variablePath; + private final String name; + private List variables; + private boolean isComplete; + + public ZendDbgVariable(VariablePath variablePath, IDbgExpression zendDbgExpression) { + this.variablePath = variablePath; + this.zendDbgExpression = zendDbgExpression; + this.name = createName(zendDbgExpression); + this.variables = Collections.emptyList(); + this.isComplete = zendDbgExpression.getChildrenCount() == zendDbgExpression.getChildren().size(); + } + + @Override + public boolean isExistInformation() { + return true; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue() { + if (zendDbgExpression.getDataType() == DataType.PHP_STRING) + return '"' + zendDbgExpression.getValue() + '"'; + return zendDbgExpression.getValue(); + } + + @Override + public String getType() { + return zendDbgExpression.getDataType().getText(); + } + + @Override + public boolean isPrimitive() { + switch (zendDbgExpression.getDataType()) { + case PHP_BOOL: + case PHP_FLOAT: + case PHP_INT: + case PHP_STRING: + case PHP_NULL: + case PHP_UNINITIALIZED: + return true; + default: + return false; + } + } + + @Override + public List getVariables() { + return variables; + } + + @Override + public VariablePath getVariablePath() { + return variablePath; + } + + @Override + public void setValue(String newValue) { + if (zendDbgExpression.setValue(newValue)) { + // Re-evaluate underlying expression + isComplete = false; + makeComplete(); + } + } + + @Override + public void makeComplete() { + if (!isComplete) { + // Evaluate wrapped expression to fetch all child variables + zendDbgExpression.evaluate(); + variables = new ArrayList<>(); + int childId = 0; + for (IDbgExpression child : zendDbgExpression.getChildren()) { + List childPath = new ArrayList<>(variablePath.getPath()); + childPath.add(String.valueOf(childId++)); + variables.add(new ZendDbgVariable(new VariablePathImpl(childPath), child)); + } + isComplete = true; + } + } + + private String createName(IDbgExpression expression) { + String name = expression.getExpression(); + if (expression.hasFacet(KIND_OBJECT_MEMBER)) { + name = name.substring(name.lastIndexOf(":") + 1); + } else if (expression.hasFacet(KIND_ARRAY_MEMBER)) { + name = '[' + name + ']'; + } + return name; + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariables.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariables.java new file mode 100644 index 00000000000..07670aa962b --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/main/java/org/eclipse/che/plugin/zdb/server/variables/ZendDbgVariables.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server.variables; + +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.KIND_LOCAL; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.KIND_SUPER_GLOBAL; +import static org.eclipse.che.plugin.zdb.server.expressions.IDbgDataFacet.Facet.KIND_THIS; + +import java.util.Collections; + +import org.eclipse.che.plugin.zdb.server.expressions.ZendDbgExpression; +import org.eclipse.che.plugin.zdb.server.expressions.ZendDbgExpressionEvaluator; +import org.eclipse.che.plugin.zdb.server.utils.ZendDbgVariableUtils; + +/** + * Expression for fetching current stack frame variables. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgVariables extends ZendDbgExpression { + + private final static String DUMP_VARIABLES_EXPRESSION = "eval('if (isset($this)) {$this;}; return get_defined_vars();')"; + private static final String SIGIL = "$"; + + public ZendDbgVariables(ZendDbgExpressionEvaluator expressionEvaluator) { + super(expressionEvaluator, DUMP_VARIABLES_EXPRESSION, Collections.emptyList()); + } + + @Override + protected ZendDbgExpression createChild(String variableName, Facet... facets) { + variableName = SIGIL + variableName; + Facet facet = KIND_LOCAL; + if (ZendDbgVariableUtils.isThis(variableName)) + facet = KIND_THIS; + else if (ZendDbgVariableUtils.isSuperGlobal(variableName)) + facet = KIND_SUPER_GLOBAL; + return new ZendDbgExpression(getExpressionEvaluator(), variableName, Collections.singletonList(variableName), + facet); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/AbstractZendDbgSessionTest.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/AbstractZendDbgSessionTest.java new file mode 100644 index 00000000000..9088acf8d69 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/AbstractZendDbgSessionTest.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import static org.mockito.AdditionalAnswers.returnsFirstArg; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.che.api.debug.shared.model.Breakpoint; +import org.eclipse.che.api.debug.shared.model.event.BreakpointActivatedEvent; +import org.eclipse.che.api.debug.shared.model.event.DebuggerEvent; +import org.eclipse.che.api.debug.shared.model.event.SuspendEvent; +import org.eclipse.che.api.debug.shared.model.impl.action.StartActionImpl; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgSettings; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +/** + * Abstract Zend Debugger session test base. + * + * @author Bartlomiej Laczkowski + */ +public abstract class AbstractZendDbgSessionTest { + + private static final String QUERY_SSL = "QUERY_STRING=start_debug=1&debug_host=127.0.0.1&debug_port=10137&use_ssl=1"; + private static final String QUERY_NO_SSL = "QUERY_STRING=start_debug=1&debug_host=127.0.0.1&debug_port=10137"; + + protected static final String DEFAULT_HOST = "127.0.0.1"; + protected static final int DEFAULT_PORT = 10137; + + protected ZendDebugger debugger; + protected BlockingQueue dbgEvents; + private Process dbgEngineProcess; + + @BeforeMethod + public void setUp() throws Exception { + dbgEvents = new ArrayBlockingQueue<>(10); + } + + @AfterMethod + public void tearDown() throws Exception { + debugger.disconnect(); + if (!dbgEngineProcess.waitFor(5, TimeUnit.SECONDS)) { + dbgEngineProcess.destroyForcibly(); + } + } + + protected ZendDbgSettings getDbgSettings(boolean breakAtFirstLine, boolean useSsslEncryption) { + return new ZendDbgSettings(DEFAULT_PORT, DEFAULT_HOST, breakAtFirstLine, useSsslEncryption); + } + + protected void awaitSuspend(String dbgFile, int lineNumber) throws Exception { + DebuggerEvent debuggerEvent = dbgEvents.poll(5, TimeUnit.SECONDS); + if (debuggerEvent == null) { + throw new Exception("Suspend event timeout occurred."); + } + assertTrue(debuggerEvent instanceof SuspendEvent); + SuspendEvent suspendEvent = (SuspendEvent) debuggerEvent; + assertEquals(suspendEvent.getLocation().getResourcePath(), dbgFile); + assertEquals(suspendEvent.getLocation().getLineNumber(), lineNumber); + } + + protected void awaitBreakpointActivated(Breakpoint breakpoint) throws Exception { + DebuggerEvent debuggerEvent = dbgEvents.poll(5, TimeUnit.SECONDS); + if (debuggerEvent == null) { + throw new Exception("Breakpoint activated event timeout occurred."); + } + assertTrue(debuggerEvent instanceof BreakpointActivatedEvent); + BreakpointActivatedEvent bpActivatedEvent = (BreakpointActivatedEvent) debuggerEvent; + assertEquals(bpActivatedEvent.getBreakpoint(), breakpoint); + } + + protected void triggerSession(String dbgFile, ZendDbgSettings dbgSettings) throws Exception { + triggerSession(dbgFile, dbgSettings, Collections.emptyList()); + } + + protected void triggerSession(String dbgFile, ZendDbgSettings dbgSettings, List dbgBreakpoints) throws Exception { + ZendDbgLocationHandler dbgLocationMapper = mock(ZendDbgLocationHandler.class); + // No need to convert between VFS and DBG for test purposes + when(dbgLocationMapper.convertToVFS(anyObject())).then(returnsFirstArg()); + when(dbgLocationMapper.convertToDBG(anyObject())).then(returnsFirstArg()); + debugger = new ZendDebugger(dbgSettings, dbgLocationMapper, dbgEvents::add); + debugger.start(new StartActionImpl(dbgBreakpoints)); + dbgEngineProcess = Runtime.getRuntime().exec("php " + dbgFile, + new String[] { dbgSettings.isUseSsslEncryption() ? QUERY_SSL : QUERY_NO_SSL }); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgAvailabilityTest.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgAvailabilityTest.java new file mode 100644 index 00000000000..59bf19df289 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgAvailabilityTest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.testng.annotations.Test; + +/** + * Class responsible for checking if PHP with Zend Debugger is installed in test environment. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgAvailabilityTest { + + private static final String NO_PHP_INSTALLED = "PHP installation could not be found in test/OS environment."; + private static final String NO_ZEND_DEBUGGER_INSTALLED = "Zend Debugger extension for PHP is not installed."; + private static final String TEST_ENVIRONMENT = "\nTest Environment:\n{0}\n{1}\n"; + + @Test(groups = { "checkPHP" }) + public void checkPHP() throws Exception { + List phpInfo = new ArrayList<>(); + try { + Process p = Runtime.getRuntime().exec(new String[] { "php", "-v" }); + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(p.getInputStream(), Charset.defaultCharset()))) { + String line; + while ((line = reader.readLine()) != null) { + phpInfo.add(line); + } + } + } catch (Exception e) { + throw new Exception(NO_PHP_INSTALLED); + } + String phpVersionLine = phpInfo.get(0); + if (!phpVersionLine.startsWith("PHP")) { + throw new Exception(NO_PHP_INSTALLED); + } + String phpZendDebuggerLine = null; + for (String currentLine : phpInfo) { + if (currentLine.contains("Zend Debugger")) { + phpZendDebuggerLine = currentLine; + } + } + if (phpZendDebuggerLine == null) { + throw new Exception(NO_ZEND_DEBUGGER_INSTALLED); + } + System.out.println(MessageFormat.format(TEST_ENVIRONMENT, phpVersionLine, phpZendDebuggerLine)); + } +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgConfigurationTest.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgConfigurationTest.java new file mode 100644 index 00000000000..b4221dc38fb --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgConfigurationTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.testng.Assert.assertTrue; + +import org.eclipse.che.api.debug.shared.model.DebuggerInfo; +import org.eclipse.che.plugin.zdb.server.connection.ZendDbgSettings; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Simple Zend Debugger configuration tests.. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgConfigurationTest { + + static final String DEBUG_HOST = "10.10.10.10"; + static final int DEBUG_PORT = 10000; + + private ZendDebugger debugger; + + @BeforeMethod + public void setUp() throws Exception { + ZendDbgSettings dbgSettings = new ZendDbgSettings(DEBUG_PORT, DEBUG_HOST, true, false); + debugger = new ZendDebugger(dbgSettings, null, null); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testGetInfo() throws Exception { + DebuggerInfo info = debugger.getInfo(); + assertTrue(info.getFile() == null); + assertTrue(isNullOrEmpty(info.getVersion())); + assertTrue(info.getName().equals("Zend Debugger")); + assertTrue(info.getPid() == 0); + assertTrue(info.getHost().equals(DEBUG_HOST)); + assertTrue(info.getPort() == DEBUG_PORT); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgSessionTest.java b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgSessionTest.java new file mode 100644 index 00000000000..eb5ef0496da --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/java/org/eclipse/che/plugin/zdb/server/ZendDbgSessionTest.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2016 Rogue Wave Software, 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: + * Rogue Wave Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.zdb.server; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.che.api.debug.shared.model.Breakpoint; +import org.eclipse.che.api.debug.shared.model.SimpleValue; +import org.eclipse.che.api.debug.shared.model.StackFrameDump; +import org.eclipse.che.api.debug.shared.model.Variable; +import org.eclipse.che.api.debug.shared.model.VariablePath; +import org.eclipse.che.api.debug.shared.model.impl.BreakpointImpl; +import org.eclipse.che.api.debug.shared.model.impl.VariableImpl; +import org.eclipse.che.api.debug.shared.model.impl.VariablePathImpl; +import org.eclipse.che.api.debug.shared.model.impl.action.ResumeActionImpl; +import org.eclipse.che.api.debug.shared.model.impl.action.StepIntoActionImpl; +import org.eclipse.che.api.debug.shared.model.impl.action.StepOutActionImpl; +import org.eclipse.che.api.debug.shared.model.impl.action.StepOverActionImpl; +import org.testng.annotations.Test; + +/** + * Class providing different tests for active Zend Debugger session. + * + * @author Bartlomiej Laczkowski + */ +public class ZendDbgSessionTest extends AbstractZendDbgSessionTest { + + private final String dbgHelloFile = (new File( + ZendDbgConfigurationTest.class.getResource("/php/hello.php").getPath())).getAbsolutePath(); + private final String dbgClassesFile = (new File( + ZendDbgConfigurationTest.class.getResource("/php/classes.php").getPath())).getAbsolutePath(); + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testSslConnection() throws Exception { + triggerSession(dbgHelloFile, getDbgSettings(true, true)); + awaitSuspend(dbgHelloFile, 2); + debugger.resume(new ResumeActionImpl()); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testStepping() throws Exception { + triggerSession(dbgHelloFile, getDbgSettings(true, false)); + awaitSuspend(dbgHelloFile, 2); + debugger.stepOver(new StepOverActionImpl()); + awaitSuspend(dbgHelloFile, 4); + debugger.stepInto(new StepIntoActionImpl()); + awaitSuspend(dbgClassesFile, 9); + debugger.stepOut(new StepOutActionImpl()); + awaitSuspend(dbgHelloFile, 4); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testEvaluation() throws Exception { + triggerSession(dbgHelloFile, getDbgSettings(true, false)); + awaitSuspend(dbgHelloFile, 2); + String result = debugger.evaluate("2+2"); + assertEquals(result, "4"); + result = debugger.evaluate("array(1,2,3)"); + assertEquals(result, "array [3]"); + result = debugger.evaluate("new XYZ()"); + assertEquals(result, "null"); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testBreakpoints() throws Exception { + List breakpoints = new ArrayList<>(); + Breakpoint bp1 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgHelloFile, 4)); + Breakpoint bp2 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgHelloFile, 8)); + breakpoints.add(bp1); + breakpoints.add(bp2); + triggerSession(dbgHelloFile, getDbgSettings(true, false), breakpoints); + awaitBreakpointActivated(bp1); + awaitBreakpointActivated(bp2); + awaitSuspend(dbgHelloFile, 2); + Breakpoint bp3 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgClassesFile, 10)); + debugger.addBreakpoint(bp3); + awaitBreakpointActivated(bp3); + Breakpoint bp4 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgClassesFile, 16)); + debugger.addBreakpoint(bp4); + awaitBreakpointActivated(bp4); + debugger.deleteBreakpoint(ZendDbgLocationHandler.createDBG(dbgHelloFile, 8)); + debugger.deleteBreakpoint(ZendDbgLocationHandler.createDBG(dbgClassesFile, 16)); + assertEquals(debugger.getAllBreakpoints().size(), 2); + debugger.deleteAllBreakpoints(); + assertTrue(debugger.getAllBreakpoints().isEmpty()); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testBreaking() throws Exception { + List breakpoints = new ArrayList<>(); + Breakpoint bp1 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgHelloFile, 4)); + Breakpoint bp2 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgClassesFile, 10)); + breakpoints.add(bp1); + breakpoints.add(bp2); + triggerSession(dbgHelloFile, getDbgSettings(false, false), breakpoints); + awaitBreakpointActivated(bp1); + awaitBreakpointActivated(bp2); + awaitSuspend(dbgHelloFile, 4); + debugger.resume(new ResumeActionImpl()); + awaitSuspend(dbgClassesFile, 10); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testVariables() throws Exception { + List breakpoints = new ArrayList<>(); + Breakpoint bp1 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgClassesFile, 16)); + Breakpoint bp2 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgClassesFile, 25)); + breakpoints.add(bp1); + breakpoints.add(bp2); + triggerSession(dbgHelloFile, getDbgSettings(false, false), breakpoints); + awaitBreakpointActivated(bp1); + awaitBreakpointActivated(bp2); + awaitSuspend(dbgClassesFile, 16); + StackFrameDump stackFrameDump = debugger.dumpStackFrame(); + assertEquals(stackFrameDump.getVariables().size(), 1); + assertEquals(stackFrameDump.getVariables().get(0).getName(), "$this"); + assertEquals(stackFrameDump.getVariables().get(0).getValue(), "A"); + assertEquals(stackFrameDump.getVariables().get(0).getType(), "object"); + debugger.resume(new ResumeActionImpl()); + awaitSuspend(dbgClassesFile, 25); + stackFrameDump = debugger.dumpStackFrame(); + assertEquals(stackFrameDump.getVariables().size(), 3); + assertEquals(stackFrameDump.getVariables().get(0).getName(), "$this"); + assertEquals(stackFrameDump.getVariables().get(0).getValue(), "B"); + assertEquals(stackFrameDump.getVariables().get(0).getType(), "object"); + assertEquals(stackFrameDump.getVariables().get(1).getName(), "$p"); + assertEquals(stackFrameDump.getVariables().get(1).getValue(), "123"); + assertEquals(stackFrameDump.getVariables().get(1).getType(), "int"); + assertEquals(stackFrameDump.getVariables().get(2).getName(), "$v"); + assertEquals(stackFrameDump.getVariables().get(2).getValue(), "\"B\""); + assertEquals(stackFrameDump.getVariables().get(2).getType(), "string"); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testGetValue() throws Exception { + List breakpoints = new ArrayList<>(); + Breakpoint bp1 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgClassesFile, 16)); + breakpoints.add(bp1); + triggerSession(dbgHelloFile, getDbgSettings(false, false), breakpoints); + awaitBreakpointActivated(bp1); + awaitSuspend(dbgClassesFile, 16); + debugger.dumpStackFrame(); + VariablePath variablePath = new VariablePathImpl("0"); + SimpleValue simpleValue = debugger.getValue(variablePath); + assertEquals(simpleValue.getVariables().size(), 3); + List path = Arrays.asList("0", "0"); + variablePath = new VariablePathImpl(path); + simpleValue = debugger.getValue(variablePath); + assertEquals(simpleValue.getValue(), "\"A\""); + path = Arrays.asList("0", "1"); + variablePath = new VariablePathImpl(path); + simpleValue = debugger.getValue(variablePath); + assertEquals(simpleValue.getValue(), "123"); + path = Arrays.asList("0", "2"); + variablePath = new VariablePathImpl(path); + simpleValue = debugger.getValue(variablePath); + assertEquals(simpleValue.getValue(), "array [3]"); + } + + @Test(groups = { "zendDbg" }, dependsOnGroups = { "checkPHP" }) + public void testSetValue() throws Exception { + List breakpoints = new ArrayList<>(); + Breakpoint bp1 = new BreakpointImpl(ZendDbgLocationHandler.createDBG(dbgHelloFile, 5)); + breakpoints.add(bp1); + triggerSession(dbgHelloFile, getDbgSettings(false, false), breakpoints); + awaitBreakpointActivated(bp1); + awaitSuspend(dbgHelloFile, 5); + StackFrameDump stackFrameDump = debugger.dumpStackFrame(); + int lastVar = stackFrameDump.getVariables().size() - 1; + Variable variableToFind = new VariableImpl(null, null, "123", false, + new VariablePathImpl(String.valueOf(lastVar)), Collections.emptyList(), false); + debugger.setValue(variableToFind); + assertEquals(stackFrameDump.getVariables().get(lastVar).getValue(), "123"); + variableToFind = new VariableImpl(null, null, "\"ABC\"", false, + new VariablePathImpl(String.valueOf(lastVar)), Collections.emptyList(), false); + debugger.setValue(variableToFind); + assertEquals(stackFrameDump.getVariables().get(lastVar).getValue(), "\"ABC\""); + } + +} diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/findbugs-exclude.xml b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/findbugs-exclude.xml new file mode 100644 index 00000000000..a8c0290b1e2 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/findbugs-exclude.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/logback-test.xml b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..e2ccdc54644 --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/logback-test.xml @@ -0,0 +1,23 @@ + + + + + + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + + + + diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/classes.php b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/classes.php new file mode 100644 index 00000000000..a81a3c95b0e --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/classes.php @@ -0,0 +1,28 @@ +fa = "A"; + $this->fb = 123; + $this->fc = array(1, 2, 3); + } + + public function hello() + { + echo("Hello from A!"); + } +} + +class B +{ + public function hello($p) + { + $v = "B"; + echo("Hello from ".$v."!"); + } +} +?> diff --git a/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/hello.php b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/hello.php new file mode 100644 index 00000000000..c334efee37d --- /dev/null +++ b/plugins/plugin-zend-debugger/che-plugin-zend-debugger-server/src/test/resources/php/hello.php @@ -0,0 +1,10 @@ +hello(); +echo("\n"); +$b->hello(123); +?> diff --git a/plugins/plugin-zend-debugger/pom.xml b/plugins/plugin-zend-debugger/pom.xml new file mode 100644 index 00000000000..2b769f3b7c7 --- /dev/null +++ b/plugins/plugin-zend-debugger/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + che-plugin-parent + org.eclipse.che.plugin + 5.0.0-M9-SNAPSHOT + ../pom.xml + + che-plugin-zend-debugger-parent + pom + Che Plugin :: PHP :: Zend Debugger Parent + + che-plugin-zend-debugger-server + che-plugin-zend-debugger-ide + + + + + com.mycila + license-maven-plugin + + true + + + + + + + + windows + + + Windows + + + + true + + + + diff --git a/plugins/pom.xml b/plugins/pom.xml index 6356fd1c999..33e00e72179 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -53,5 +53,6 @@ plugin-ssh-key plugin-languageserver plugin-json + plugin-zend-debugger
    diff --git a/pom.xml b/pom.xml index 9dfe685afca..1d25d589633 100644 --- a/pom.xml +++ b/pom.xml @@ -787,6 +787,16 @@ che-plugin-web-ext-web ${che.version}
    + + org.eclipse.che.plugin + che-plugin-zend-debugger-ide + ${che.version} + + + org.eclipse.che.plugin + che-plugin-zend-debugger-server + ${che.version} + org.eclipse.che.plugin maven-server-api From 4c587d524863fbc7ef76bb101ccf0f47877450dd Mon Sep 17 00:00:00 2001 From: Roman Iuvshin Date: Thu, 8 Dec 2016 15:59:43 +0200 Subject: [PATCH 73/74] Configure Master & Agent JVMs to Inherit Proxy Settings (#3323) * Configure Master & Agent JVMs to Inherit Proxy Settings --- dockerfiles/init/manifests/che.env | 6 ++-- dockerfiles/init/manifests/che.pp | 29 ++++++++++++---- .../init/modules/che/templates/che.env.erb | 33 +++++++++++++++++++ 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/dockerfiles/init/manifests/che.env b/dockerfiles/init/manifests/che.env index 2ed14111d30..d87cacc3cee 100644 --- a/dockerfiles/init/manifests/che.env +++ b/dockerfiles/init/manifests/che.env @@ -25,9 +25,9 @@ # # Please be mindful of the proxy URL formatting. Proxies are unforgiving if you do not # type the URL properly, including the protocol and whether they allow a trailing /. -#CHE_HTTP_PROXY_FOR_CHE=http://myproxy.com:8001/ -#CHE_HTTPS_PROXY_FOR_CHE=http://myproxy.com:8001/ -#CHE_NO_PROXY_FOR_CHE= +#CHE_HTTP_PROXY=http://myproxy.com:8001/ +#CHE_HTTPS_PROXY=http://myproxy.com:8001/ +#CHE_NO_PROXY= # Proxies for Workspaces # The proxy values that will be set as environment variables within each user's. diff --git a/dockerfiles/init/manifests/che.pp b/dockerfiles/init/manifests/che.pp index 60750e2e777..093106a5591 100644 --- a/dockerfiles/init/manifests/che.pp +++ b/dockerfiles/init/manifests/che.pp @@ -1,5 +1,5 @@ node default { -################################################################################################## + ################################################################################################## $che_ip = getValue("CHE_HOST", "localhost") $che_port = getValue("CHE_PORT", "8080") $che_version = getValue("CHE_VERSION","nightly") @@ -12,9 +12,8 @@ $docker_ip = getValue("CHE_DOCKER_IP","172.17.0.1") $docker_host = getValue("DOCKER_HOST","tcp://localhost:2375") - -############################### -# oAuth configurations + ############################### + # oAuth configurations $google_client_id = getValue("CHE_GOOGLE_CLIENT_ID","your_google_client_id") $google_secret = getValue("CHE_GOOGLE_SECRET","your_google_secret") $github_client_id = getValue("CHE_GITHUB_CLIENT_ID","423531cf41d6c13e1b3b") @@ -28,8 +27,26 @@ $microsoft_client_id = getValue("CHE_MICROSOFT_CLIENT_ID","your_microsoft_client_id") $microsoft_secret = getValue("CHE_MICROSOFT_SECRET","your_microsoft_secret") -############################### -# Include base module + ############################### + # Http proxy configuration + # leave those fields empty if no configuration needed + # + # http proxy for CHE + $che_http_proxy = getValue("CHE_HTTP_PROXY","") + $che_https_proxy = getValue("CHE_HTTPS_PROXY","") + # provide dns which proxy should not be used for. + # please leave this empty if you don't need no_proxy configuration + $che_no_proxy = getValue("CHE_NO_PROXY","") + # + # http proxy for CHE workspaces + $http_proxy_for_che_workspaces = getValue("CHE_WORKSPACE_HTTP__PROXY","") + $https_proxy_for_che_workspaces = getValue("CHE_WORKSPACE_HTTPS__PROXY","") + # provide dns which proxy should not be used for. + # please leave this as it is if you don't need no_proxy configuration + $no_proxy_for_che_workspaces = getValue("CHE_WORKSPACE_NO__PROXY","") + + ############################### + # Include base module include base } diff --git a/dockerfiles/init/modules/che/templates/che.env.erb b/dockerfiles/init/modules/che/templates/che.env.erb index e42644c5509..70bed96fe75 100644 --- a/dockerfiles/init/modules/che/templates/che.env.erb +++ b/dockerfiles/init/modules/che/templates/che.env.erb @@ -30,3 +30,36 @@ CHE_STACKS_IMAGES=/data/stacks/images CHE_WORKSPACE_TERMINAL__LINUX__AMD64=<%= scope.lookupvar('che::che_instance') %>/data/lib/linux_amd64/terminal CHE_WORKSPACE_TERMINAL__LINUX__ARM7=<%= scope.lookupvar('che::che_instance') %>/data/lib/linux_arm7/terminal CHE_WORKSPACE_AGENT_DEV=<%= scope.lookupvar('che::che_instance') %>/data/lib/ws-agent.tar.gz + +<% if ! @che_http_proxy.empty? or ! @che_https_proxy.empty? -%> +JAVA_HTTP_PROXY_SET=-Dhttp.proxySet=true +<% end -%> +<% if ! @che_http_proxy.empty? -%> +<% if ! @che_http_proxy.empty? and @che_http_proxy.include? '@' -%> +JAVA_HTTP_USER_NAME=-Dhttp.proxyUser=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[0] %> +JAVA_HTTP_USER_PASSWORD=-Dhttp.proxyPassword=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[1] %> +JAVA_HTTP_PROXY_HOST=-Dhttp.proxyHost=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[0] %> +JAVA_HTTP_PROXY_PORT=-Dhttp.proxyPort=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[1].gsub(/\/.*/,'') %> +<% else -%> +JAVA_HTTP_PROXY_HOST=-Dhttp.proxyHost=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[0] %> +JAVA_HTTP_PROXY_PORT=-Dhttp.proxyPort=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[1].gsub(/\/.*/,'') %> +<% end -%> +<% end -%> +<% if ! @che_https_proxy.empty? -%> +<% if @che_https_proxy.include? '@' -%> +JAVA_HTTPS_USER_NAME=-Dhttps.proxyUser=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[0] %> +JAVA_HTTPS_USER_PASSWORD=-Dhttps.proxyPassword=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[1] %> +JAVA_HTTPS_PROXY_HOST=-Dhttps.proxyHost=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[0] %> +JAVA_HTTPS_PROXY_PORT=-Dhttps.proxyPort=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[1].gsub(/\/.*/,'') %> +<% else -%> +JAVA_HTTPS_PROXY_HOST=-Dhttps.proxyHost=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[0] %> +JAVA_HTTPS_PROXY_PORT=-Dhttps.proxyPort=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[1].gsub(/\/.*/,'') %> +<% end -%> +<% end -%> +<% if ! @che_no_proxy.empty? -%> +JAVA_NO_PROXY=-Dhttp.nonProxyHosts='<%= @che_no_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').gsub(',','|') %>' +<% end -%> +JAVA_OPTS=-Xms512m -server -XX:+HeapDumpOnOutOfMemoryError -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark <% if ! @che_http_proxy.empty? or ! @che_https_proxy.empty? -%>$JAVA_HTTP_PROXY_SET<% end -%> <% if ! @che_http_proxy.empty? -%>$JAVA_HTTP_PROXY_HOST $JAVA_HTTP_PROXY_PORT<% end -%> <% if ! @che_https_proxy.empty? -%>$JAVA_HTTPS_PROXY_HOST $JAVA_HTTPS_PROXY_PORT<% end -%><%- if ! @che_no_proxy.empty? -%> $JAVA_NO_PROXY<% end -%><% if @che_http_proxy.include? '@' -%> $JAVA_HTTP_USER_NAME $JAVA_HTTP_USER_PASSWORD<% end -%><% if @che_https_proxy.include? '@' -%> $JAVA_HTTPS_USER_NAME $JAVA_HTTPS_USER_PASSWORD<% end %> + +# java opts for ws agent +CHE_WORKSPACE_JAVA__OPTS=-Xms256m -Xmx2048m -Djava.security.egd=file:/dev/./urandom <% if ! @che_http_proxy.empty? or ! @che_https_proxy.empty? -%>-Dhttp.proxySet=true<% end -%><% if ! @che_http_proxy.empty? -%><% if ! @che_http_proxy.empty? and @che_http_proxy.include? '@' -%> -Dhttp.proxyUser=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[0] %> -Dhttp.proxyPassword=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[1] %> -Dhttp.proxyHost=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[0] %> -Dhttp.proxyPort=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[1].gsub(/\/.*/,'') %><% else -%> -Dhttp.proxyHost=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[0] %> -Dhttp.proxyPort=<%= @che_http_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[1].gsub(/\/.*/,'') %><% end -%><% end -%><% if ! @che_https_proxy.empty? -%><% if @che_https_proxy.include? '@' -%> -Dhttps.proxyUser=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[0] %> -Dhttps.proxyPassword=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[0].split(':')[1] %> -Dhttps.proxyHost=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[0] %> -Dhttps.proxyPort=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split('@')[1].split(':')[1].gsub(/\/.*/,'') %><% else -%> -Dhttps.proxyHost=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[0] %> -Dhttps.proxyPort=<%= @che_https_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').split(':')[1].gsub(/\/.*/,'') %><% end -%><% end -%><% if ! @che_no_proxy.empty? -%> -Dhttp.nonProxyHosts='<%= @che_no_proxy.gsub(/^https?\:\/\//, '').gsub(/^www./,'').gsub(',','|') %>'<% end -%> From ab9b0946ecf7549191382640f517aa5d882701a6 Mon Sep 17 00:00:00 2001 From: Yevhenii Voevodin Date: Thu, 8 Dec 2016 16:18:25 +0200 Subject: [PATCH 74/74] Add exec-agent (#2163) --- .gitignore | 2 +- assembly/assembly-main/pom.xml | 24 +- .../assembly-main/src/assembly/assembly.xml | 4 +- .../che/api/deploy/WsMasterModule.java | 2 + exec-agent/.gitignore | 2 + exec-agent/README.md | 59 + exec-agent/docs/events.md | 98 + exec-agent/docs/notes.md | 10 + exec-agent/docs/rest_api.md | 233 + exec-agent/docs/ws_api.md | 564 ++ exec-agent/pom.xml | 215 + exec-agent/src/Godeps/Godeps.json | 22 + exec-agent/src/Godeps/Readme | 5 + exec-agent/src/assembly/assembly.xml | 36 + exec-agent/src/auth/auth.go | 128 + exec-agent/src/auth/cache_test.go | 56 + exec-agent/src/main.go | 300 + exec-agent/src/process/common.go | 79 + exec-agent/src/process/events.go | 72 + exec-agent/src/process/file_logger.go | 84 + exec-agent/src/process/file_logger_test.go | 125 + exec-agent/src/process/logs_distributor.go | 63 + .../src/process/logs_distributor_test.go | 72 + exec-agent/src/process/logs_reader.go | 87 + exec-agent/src/process/logs_reader_test.go | 60 + exec-agent/src/process/process.go | 483 ++ exec-agent/src/process/process_builder.go | 72 + exec-agent/src/process/process_cleaner.go | 56 + .../src/process/process_cleaner_test.go | 60 + exec-agent/src/process/process_test.go | 255 + exec-agent/src/process/pumper.go | 108 + exec-agent/src/process/rest_service.go | 194 + exec-agent/src/process/ws_service.go | 348 + exec-agent/src/rest/errors.go | 41 + exec-agent/src/rest/restutil/util.go | 45 + exec-agent/src/rest/route.go | 80 + exec-agent/src/rpc/channels.go | 334 + exec-agent/src/rpc/model.go | 173 + exec-agent/src/rpc/route.go | 88 + exec-agent/src/rpc/transmitter.go | 41 + exec-agent/src/static/term.js | 5793 +++++++++++++++++ exec-agent/src/term/activity.go | 65 + exec-agent/src/term/server.go | 306 + .../vendor/github.com/eclipse/che-lib/LICENSE | 203 + .../github.com/eclipse/che-lib/pty/.gitignore | 4 + .../github.com/eclipse/che-lib/pty/License | 23 + .../github.com/eclipse/che-lib/pty/README.md | 40 + .../github.com/eclipse/che-lib/pty/doc.go | 16 + .../github.com/eclipse/che-lib/pty/ioctl.go | 11 + .../eclipse/che-lib/pty/ioctl_bsd.go | 39 + .../eclipse/che-lib/pty/mktypes.bash | 19 + .../eclipse/che-lib/pty/pty_darwin.go | 67 + .../eclipse/che-lib/pty/pty_freebsd.go | 80 + .../eclipse/che-lib/pty/pty_linux.go | 53 + .../eclipse/che-lib/pty/pty_unsupported.go | 11 + .../github.com/eclipse/che-lib/pty/run.go | 28 + .../github.com/eclipse/che-lib/pty/types.go | 10 + .../eclipse/che-lib/pty/types_freebsd.go | 15 + .../github.com/eclipse/che-lib/pty/util.go | 39 + .../eclipse/che-lib/pty/ztypes_386.go | 9 + .../eclipse/che-lib/pty/ztypes_amd64.go | 9 + .../eclipse/che-lib/pty/ztypes_arm.go | 9 + .../eclipse/che-lib/pty/ztypes_freebsd_386.go | 13 + .../che-lib/pty/ztypes_freebsd_amd64.go | 14 + .../eclipse/che-lib/pty/ztypes_freebsd_arm.go | 13 + .../eclipse/che-lib/pty/ztypes_ppc64.go | 11 + .../eclipse/che-lib/pty/ztypes_ppc64le.go | 11 + .../eclipse/che-lib/pty/ztypes_s390x.go | 11 + .../eclipse/che-lib/websocket/.gitignore | 22 + .../eclipse/che-lib/websocket/.travis.yml | 6 + .../eclipse/che-lib/websocket/AUTHORS | 8 + .../eclipse/che-lib/websocket/LICENSE | 22 + .../eclipse/che-lib/websocket/README.md | 61 + .../eclipse/che-lib/websocket/client.go | 334 + .../eclipse/che-lib/websocket/conn.go | 831 +++ .../eclipse/che-lib/websocket/doc.go | 151 + .../eclipse/che-lib/websocket/json.go | 55 + .../eclipse/che-lib/websocket/server.go | 250 + .../eclipse/che-lib/websocket/util.go | 44 + .../julienschmidt/httprouter/.travis.yml | 11 + .../julienschmidt/httprouter/LICENSE | 24 + .../julienschmidt/httprouter/README.md | 276 + .../julienschmidt/httprouter/path.go | 123 + .../julienschmidt/httprouter/router.go | 411 ++ .../julienschmidt/httprouter/tree.go | 653 ++ .../che-plugin-machine-ext-client/pom.xml | 22 +- pom.xml | 36 +- .../agent/server/model/impl/AgentImpl.java | 4 + .../agents/org.eclipse.che.terminal.json | 24 +- .../org.eclipse.che.terminal.script.sh | 4 +- .../che/api/machine/shared/Constants.java | 1 + .../server/WorkspaceServiceLinksInjector.java | 29 +- .../launcher/TerminalAgentLauncherImpl.java | 17 +- 93 files changed, 15051 insertions(+), 70 deletions(-) create mode 100644 exec-agent/.gitignore create mode 100644 exec-agent/README.md create mode 100644 exec-agent/docs/events.md create mode 100644 exec-agent/docs/notes.md create mode 100644 exec-agent/docs/rest_api.md create mode 100644 exec-agent/docs/ws_api.md create mode 100644 exec-agent/pom.xml create mode 100644 exec-agent/src/Godeps/Godeps.json create mode 100644 exec-agent/src/Godeps/Readme create mode 100644 exec-agent/src/assembly/assembly.xml create mode 100644 exec-agent/src/auth/auth.go create mode 100644 exec-agent/src/auth/cache_test.go create mode 100644 exec-agent/src/main.go create mode 100644 exec-agent/src/process/common.go create mode 100644 exec-agent/src/process/events.go create mode 100644 exec-agent/src/process/file_logger.go create mode 100644 exec-agent/src/process/file_logger_test.go create mode 100644 exec-agent/src/process/logs_distributor.go create mode 100644 exec-agent/src/process/logs_distributor_test.go create mode 100644 exec-agent/src/process/logs_reader.go create mode 100644 exec-agent/src/process/logs_reader_test.go create mode 100644 exec-agent/src/process/process.go create mode 100644 exec-agent/src/process/process_builder.go create mode 100644 exec-agent/src/process/process_cleaner.go create mode 100644 exec-agent/src/process/process_cleaner_test.go create mode 100644 exec-agent/src/process/process_test.go create mode 100644 exec-agent/src/process/pumper.go create mode 100644 exec-agent/src/process/rest_service.go create mode 100644 exec-agent/src/process/ws_service.go create mode 100644 exec-agent/src/rest/errors.go create mode 100644 exec-agent/src/rest/restutil/util.go create mode 100644 exec-agent/src/rest/route.go create mode 100644 exec-agent/src/rpc/channels.go create mode 100644 exec-agent/src/rpc/model.go create mode 100644 exec-agent/src/rpc/route.go create mode 100644 exec-agent/src/rpc/transmitter.go create mode 100644 exec-agent/src/static/term.js create mode 100644 exec-agent/src/term/activity.go create mode 100644 exec-agent/src/term/server.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/LICENSE create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/.gitignore create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/License create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/README.md create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/doc.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ioctl.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ioctl_bsd.go create mode 100755 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/mktypes.bash create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/pty_darwin.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/pty_freebsd.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/pty_linux.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/pty_unsupported.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/run.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/types.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/types_freebsd.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/util.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_386.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_amd64.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_arm.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_freebsd_386.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_freebsd_amd64.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_freebsd_arm.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_ppc64.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_ppc64le.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/pty/ztypes_s390x.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/.gitignore create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/.travis.yml create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/AUTHORS create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/LICENSE create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/README.md create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/client.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/conn.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/doc.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/json.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/server.go create mode 100644 exec-agent/src/vendor/github.com/eclipse/che-lib/websocket/util.go create mode 100644 exec-agent/src/vendor/github.com/julienschmidt/httprouter/.travis.yml create mode 100644 exec-agent/src/vendor/github.com/julienschmidt/httprouter/LICENSE create mode 100644 exec-agent/src/vendor/github.com/julienschmidt/httprouter/README.md create mode 100644 exec-agent/src/vendor/github.com/julienschmidt/httprouter/path.go create mode 100644 exec-agent/src/vendor/github.com/julienschmidt/httprouter/router.go create mode 100644 exec-agent/src/vendor/github.com/julienschmidt/httprouter/tree.go diff --git a/.gitignore b/.gitignore index d1738070c3f..e8db0d8f76b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ config/ # Compiled source # ################### -*.com +!*.com/ *.class *.dll *.exe diff --git a/assembly/assembly-main/pom.xml b/assembly/assembly-main/pom.xml index c446491c365..edaafef072a 100644 --- a/assembly/assembly-main/pom.xml +++ b/assembly/assembly-main/pom.xml @@ -37,6 +37,18 @@ assembly-wsmaster-war war + + org.eclipse.che + exec-agent + tar.gz + linux_amd64 + + + org.eclipse.che + exec-agent + tar.gz + linux_arm7 + org.eclipse.che.core che-core-ide-stacks @@ -62,18 +74,6 @@ che-tomcat8-slf4j-logback zip - - org.eclipse.che.lib - che-websocket-terminal - tar.gz - linux_amd64 - - - org.eclipse.che.lib - che-websocket-terminal - tar.gz - linux_arm7 - org.eclipse.che.plugin che-plugin-sdk-tools diff --git a/assembly/assembly-main/src/assembly/assembly.xml b/assembly/assembly-main/src/assembly/assembly.xml index 4676e15a942..422cd3ec63a 100644 --- a/assembly/assembly-main/src/assembly/assembly.xml +++ b/assembly/assembly-main/src/assembly/assembly.xml @@ -70,7 +70,7 @@ lib/linux_amd64/terminal websocket-terminal-linux_amd64.tar.gz - org.eclipse.che.lib:che-websocket-terminal:tar.gz:linux_amd64 + org.eclipse.che:exec-agent:tar.gz:linux_amd64 @@ -79,7 +79,7 @@ lib/linux_arm7/terminal websocket-terminal-linux_arm7.tar.gz - org.eclipse.che.lib:che-websocket-terminal:tar.gz:linux_arm7 + org.eclipse.che:exec-agent:tar.gz:linux_arm7 diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index c2a8c4a09cb..3e694abc56f 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -104,6 +104,8 @@ protected void configure() { bindConstant().annotatedWith(Names.named("machine.ws_agent.run_command")) .to("export JPDA_ADDRESS=\"4403\" && ~/che/ws-agent/bin/catalina.sh jpda run"); + bindConstant().annotatedWith(Names.named("machine.terminal_agent.run_command")) + .to("$HOME/che/terminal/che-websocket-terminal -addr :4411 -cmd ${SHELL_INTERPRETER} -static $HOME/che/terminal/"); bind(org.eclipse.che.api.workspace.server.WorkspaceValidator.class) .to(org.eclipse.che.api.workspace.server.DefaultWorkspaceValidator.class); diff --git a/exec-agent/.gitignore b/exec-agent/.gitignore new file mode 100644 index 00000000000..7d245c33e26 --- /dev/null +++ b/exec-agent/.gitignore @@ -0,0 +1,2 @@ +logs/ +exec-agent diff --git a/exec-agent/README.md b/exec-agent/README.md new file mode 100644 index 00000000000..bc56c341fee --- /dev/null +++ b/exec-agent/README.md @@ -0,0 +1,59 @@ +Summary +--- +Golang based server for executing commands and streaming process output logs, +also websocket-terminal. + + +Requirements +-- +- golang 1.6+ + + +Docs +--- +- jsonrpc2.0 based [Webscoket API](docs/ws_api.md) +- jsonrpc2.0 based [Events](docs/events.md) +- [REST API](docs/rest_api.md) + +Development +--- + +##### Link the sources to standard go workspace + +```bash +export CHE_PATH=~/code/che +mkdir $GOPATH/src/github.com/eclipse/che -p +ln -s $CHE_PATH/exec-agent/src $GOPATH/src/github.com/eclipse/che/exec-agent +``` + +##### Install godep +```bash +go get github.com/tools/godep +``` + +##### Get all dependencies + +```bash +cd $GOPATH/src/github.com/eclipse/che/exec-agent +$GOPATH/bin/godep restore +``` + +That's it, `$GOPATH/src/github.com/eclipse/che/exec-agent` project is ready. + +##### Building linked project + +```bash +cd $GOPATH/src/github.com/eclipse/che/exec-agent && go build +``` + +##### Running linked project tests + +```bash +cd $GOPATH/src/github.com/eclipse/che/exec-agent && go test ./... +``` + +##### Formatting linked project sources + +```bash +cd $GOPATH/src/github.com/eclipse/che/exec-agent && go fmt ./... +``` diff --git a/exec-agent/docs/events.md b/exec-agent/docs/events.md new file mode 100644 index 00000000000..186e7dfaf07 --- /dev/null +++ b/exec-agent/docs/events.md @@ -0,0 +1,98 @@ +Events +=== +Messages sent via websocket connections to clients + +Channel Events +--- + +#### Connected + +The first event in the channel, published when client successfully connected to the exec-agent. + +```json +{ + "jsonrpc": "2.0", + "method": "connected", + "params": { + "time": "2016-09-24T16:40:05.098478609+03:00", + "channel": "channel-1", + "text": "Hello!" + } +} +``` + +Process Events +--- + +#### Process started + +Published when process is successfully started. +This is the first event from all the events produced by process, +it appears only once for one process + +```json +{ + "jsonrpc": "2.0", + "method": "process_started", + "params": { + "time": "2016-09-24T16:40:55.930743249+03:00", + "pid": 1, + "nativePid": 22164, + "name": "print", + "commandLine": "printf \"\n1\n2\n3\"" + } +} +``` + +#### STDOUT event + +Published when process writes to stdout. +One stdout event describes one output line + +```json +{ + "jsonrpc": "2.0", + "method": "process_stdout", + "params": { + "time": "2016-09-24T16:40:55.933255297+03:00", + "pid": 1, + "text": "Starting server..." + } +} +``` + +#### STDERR event + +Published when process writes to stderr. +One stderr event describes one output line + +```json +{ + "jsonrpc": "2.0", + "method": "process_stderr", + "params": { + "time": "2016-09-24T16:40:55.933255297+03:00", + "pid": 1, + "text": "sh: ifconfig: command not found" + } +} +``` + +#### Process died + +Published when process is done, or killed. This is the last event from the process, +it appears only once for one process + +```json +{ + "jsonrpc": "2.0", + "method": "process_died", + "params": { + "time": "2016-09-24T16:40:55.93354086+03:00", + "pid": 1, + "nativePid": 22164, + "name": "print", + "commandLine": "printf \"\n1\n2\n3\"" + } +} +``` diff --git a/exec-agent/docs/notes.md b/exec-agent/docs/notes.md new file mode 100644 index 00000000000..906e8ee2bc3 --- /dev/null +++ b/exec-agent/docs/notes.md @@ -0,0 +1,10 @@ +##### Websocket messages order + +The order is respected +``` +Message fragments MUST be delivered to the recipient in the order sent by the sender. +``` +Helpful Sources +* https://tools.ietf.org/html/rfc6455 (search the sentence above) +* http://stackoverflow.com/questions/11804721/can-websocket-messages-arrive-out-of-order +* http://stackoverflow.com/questions/14287224/processing-websockets-messages-in-order-of-receiving diff --git a/exec-agent/docs/rest_api.md b/exec-agent/docs/rest_api.md new file mode 100644 index 00000000000..b4566fc516e --- /dev/null +++ b/exec-agent/docs/rest_api.md @@ -0,0 +1,233 @@ +REST API +=== + +Process API +--- + +### Start a new process + +#### Request + +_POST /process_ + +- `channel`(optional) - the id of the channel which should be subscribed to the process events +- `types`(optional) - comma separated types works only in couple with specified `channel`, defines +the events which will be sent by the process to the `channel`. Several values may be specified, +e.g. `channel=channel-1&types=stderr,stdout`. By default channel will be subscribed to +all the existing types(listed below). Possible type values: + - `stderr` - output from the process stderr + - `stdout` - output from the process stdout + - `process_status` - the process status events(_started, died_) + + +```json +{ + "name" : "build", + "commandLine" : "mvn clean install", + "type" : "maven" +} +``` + +#### Response + +```json +{ + "pid": 1, + "name": "build", + "commandLine": "mvn clean install", + "type" : "maven", + "alive": true, + "nativePid": 9186 +} +``` +- `200` if successfully started +- `400` if incoming data is not valid e.g. name is empty +- `404` if specified `channel` doesn't exist +- `500` if any other error occurs + + +### Get a process + +#### Request + +_GET /process/{pid}_ + +- `pid` - the id of the process to get + +#### Response + +```json +{ + "pid": 1, + "name": "build", + "commandLine": "mvn clean install", + "type" : "maven", + "alive": false, + "nativePid": 9186, +} +``` + +- `200` if response contains requested process +- `400` if `pid` is not valid, unsigned int required +- `404` if there is no such process +- `500` if any other error occurs + +### Kill a process + +#### Request + +_DELETE /process/{pid}_ + +- `pid` - the id of the process to kill + +#### Response + +```json +{ + "pid": 1, + "name": "build", + "commandLine": "mvn clean install", + "type" : "maven", + "alive": true, + "nativePid": 9186, +} +``` +- `200` if successfully killed +- `400` if `pid` is not valid, unsigned int required +- `404` if there is no such process +- `500` if any other error occurs + + +### Get process logs + +#### Request + +_GET /process/{pid}/logs_ + +- `pid` - the id of the process to get logs +- `from`(optional) - time to get logs from e.g. _2016-07-12T01:48:04.097980475+03:00_ the format is _RFC3339Nano_ +don't forget to encode this query parameter +- `till`(optional) - time to get logs till e.g. _2016-07-12T01:49:04.097980475+03:00_ the format is _RFC3339Nano_ +don't forget to encode this query parameter +- `format`(optional) - the format of the response, default is `json`, possible values are: `text`, `json` +- `limit`(optional) - the limit of logs in result, the default value is _50_, logs are limited from the +latest to the earliest +- `skip` (optional) - the logs to skip, default value is `0` + +#### Response + +The result logs of the process with the command line `printf "Hello\nWorld\n"` + +Text: +```text +[STDOUT] 2016-07-04 08:37:56.315082296 +0300 EEST Hello +[STDOUT] 2016-07-04 08:37:56.315128242 +0300 EEST World +``` + +Json: +```json +[ + { + "Kind" : "STDOUT", + "Time" : "2016-07-16T19:51:32.313368463+03:00", + "Text" : "Hello" + }, + { + "Kind" : "STDOUT", + "Time" : "2016-07-16T19:51:32.313603625+03:00", + "Text" : "World" + } +] +``` + +- `200` if logs are successfully fetched +- `400` if `from` or `till` format is invalid +- `404` if there is no such process +- `500` if any other error occurs + +### Get processes + +#### Request + +_GET /process_ + +- `all`(optional) - if `true` then all the processes including _dead_ ones will be returned(respecting paging ofc), +otherwise only _alive_ processes will be returnedg + +#### Response + +The result of the request _GET /process?all=true_ +```json +[ + { + "pid": 1, + "name": "build", + "commandLine": "mvn clean install", + "type" : "maven", + "alive": true, + "nativePid": 9186, + }, + { + "pid": 2, + "name": "build", + "commandLine": "printf \"Hello World\"", + "alive": false, + "nativePid": 9588 + } +] +``` +- `200` if processes are successfully retrieved +- `500` if any error occurs + +### Subscribe to the process events + +#### Request + +_POST /process/{pid}/events/{channel}_ + +- `pid` - the id of the process to subscribe to +- `channel` - the id of the webscoket channel which is subscriber +- `types`(optional) - the types of the events separated by comma e.g. `?types=stderr,stdout` +- `after`(optional) - process logs which appeared after given time will +be republished to the channel. This method may be useful in the reconnect process + +#### Response + +- `200` if successfully subscribed +- `400` if any of the parameters is not valid +- `404` if there is no such process or channel +- `500` if any other error occurs + +### Unsubscribe from the process events + +#### Request + +_DELETE /process/{pid}/events/{channel}_ + +- `pid` - the id of the process to unsubscribe from +- `channel` - the id of the webscoket channel which currenly subscribed +to the process events + +#### Response + +- `200` if successfully unsubsribed +- `400` if any of the parameters is not valid +- `404` if there is no such process or channel +- `500` if any other error occurs + +### Update the process events subscriber + +#### Request + +_PUT /process/{pid}/events/{channel}_ + +- `pid` - the id of the process +- `channel` - the id of the websocket channel which is subscriber +- `types` - the types of the events separated with comma e.g. `?types=stderr,stdout` + +#### Response + +- `200` if successfully updated +- `400` if any of the parameters is not valid +- `404` if there is no such process or channel +- `500` if any other error occurs diff --git a/exec-agent/docs/ws_api.md b/exec-agent/docs/ws_api.md new file mode 100644 index 00000000000..81e1be8dfca --- /dev/null +++ b/exec-agent/docs/ws_api.md @@ -0,0 +1,564 @@ +Websocket API +--- +[JSON RPC 2.0](http://www.jsonrpc.org/specification) protocol is used for client-server +communication, but: +- `params` is always json object(never array) +- server to client notifications are treated as [Events](events.md) + +the apis described below include some of the following fields: +```json +{ + "jsonrpc" : "2.0", + "method": "...", + "id": "...", + "params": { }, + "error" : { }, + "result" : { } +} +``` + these fields are part of the protocol so they are not documented. + +## Process API + + +### Start process + +##### Request + +- __name__ - the name of the command +- __commandLine__ - command line to execute +- __type__(optional) - command type +- __eventTypes__(optional) - comma separated types of events which will be + received by this channel. By default all the process events will be received. +Possible values are: `stderr`, `stdout`, `process_status` + +```json +{ + "method": "process.start", + "id": "id1234567", + "params": { + "name": "print", + "commandLine": "printf \"1\n2\n3\"", + "type": "test" + } +} +``` + +##### Response + +```json +{ + "jsonrpc": "2.0", + "id": "id1234567", + "result": { + "pid": 1, + "name": "print", + "commandLine": "printf \"1\n2\n3\"", + "type": "test", + "alive": true, + "nativePid": 19920 + } +} +``` + +#### Errors + +- when either `name` or `commandLine` is missing, e.g: + +```json +{ + "jsonrpc": "2.0", + "id": "id1234567", + "error": { + "code": -32602, + "message": "Command line required" + } +} +``` + +### Kill process + +##### Request + +- __pid__ - the id of the process to kill + +```json +{ + "method": "process.kill", + "id": "id1234567", + "params": { + "pid": 2 + } +} +``` + +##### Response + +```json +{ + "jsonrpc": "2.0", + "id": "id1234567", + "result": { + "pid": 2, + "text": "Successfully killed" + } +} +``` + +##### Errors + +- when there is no such process + +```json +{ + "jsonrpc": "2.0", + "id": "id1234567", + "error": { + "code": -32000, + "message": "Process with id '2' does not exist" + } +} +``` + +- when process with given id is not alive + +```json +{ + "jsonrpc": "2.0", + "id": "id1234567", + "error": { + "code": -32001, + "message": "Process with id '2' is not alive" + } +} +``` + +### Subscribe to process events + +##### Request + +- __pid__ - the id of the process to subscribe to +- __eventTypes__(optional) - comma separated types of events which will be +received by this channel. By default all the process events will be received, +not supported even types are ignored. Possible values are: `stdout`, `stderr`, `process_status`. +- __after__(optional) - process logs which appeared after given time will +be republished to the channel. This parameter may be useful when reconnecting to the exec-agent + +```json +{ + "method": "process.subscribe", + "id": "0x12345", + "params": { + "pid": 2, + "eventTypes": "stdout,stderr", + "after" : "2016-07-26T09:36:44.920890113+03:00" + } +} +``` + + +##### Response + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "result": { + "pid": 2, + "eventTypes": "stdout,stderr", + "text": "Successfully subscribed" + } +} +``` + +##### Errors + +- when there is no a single valid event type provided + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32602, + "message": "Required at least 1 valid event type" + } +} +``` + +- when `after` is not in valid format + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32602, + "message": "Bad format of 'after', parsing time \"2016-07-26\" as \"2006-01-02T15:04:05.999999999Z07:00\": cannot parse \"\" as \"T\"" + } +} +``` + +- when this channel is already subscribed on process events + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32603, + "message": "Already subscribed" + } +} +``` + +- when there is no such process + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32000, + "message": "Process with id '2' does not exist" + } +} +``` + +- when process with given id is not alive + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32001, + "message": "Process with id '2' is not alive" + } +} +``` + + + +### Unsubscribe from process events + +##### Request + +- __pid__ - the id of the process to unsubscribe from + +```json +{ + "method": "process.unsubscribe", + "id": "0x12345", + "params": { + "pid": 2 + } +} +``` + +##### Response + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "result": { + "pid": 2, + "text": "Successfully unsubscribed" + } +} +``` + +##### Errors + +- when there is no such process + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32000, + "message": "Process with id '2' does not exist" + } +} +``` + +- when process with given id is not alive + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32001, + "message": "Process with id '2' is not alive" + } +} +``` + + + +### Update process subscriber + +##### Request + +- __pid__ - the id of the process which subscriber should be updated +- __eventTypes__ - comma separated types of events which will be +received by this channel. Not supported even types are ignored. +Possible values are: `stdout`, `stderr`, `process_status`. + +```json +{ + "method": "process.updateSubscriber", + "id": "0x12345", + "params": { + "pid": 2, + "eventTypes": "process_status" + } +} +``` + +##### Response + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "result": { + "pid": 2, + "eventTypes": "process_status", + "text": "Subscriber successfully updated" + } +} +``` + +##### Errors + +- when there is no such process + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32000, + "message": "Process with id '2' does not exist" + } +} +``` + +- when process with given id is not alive + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32001, + "message": "Process with id '2' is not alive" + } +} +``` + +- when this channel is not subscribed on process events + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32603, + "message": "No subscriber with id 'channel-1'" + } +} +``` + + +### Get process logs + +##### Request + +- __pid__ - the id of the process to get logs +- __from__(optional) - time to get logs from e.g. _2016-07-12T01:48:04.097980475+03:00_ the format is _RFC3339Nano_ +- __till__(optional) - time to get logs till e.g. _2016-07-12T01:49:04.097980475+03:00_ the format is _RFC3339Nano_ +- __limit__(optional) - the limit of logs in result, the default value is _50_, logs are limited from the +latest to the earliest +- __skip__ (optional) - the logs to skip, default value is `0` + +```json +{ + "method": "process.getLogs", + "id": "0x12345", + "params": { + "pid": 3, + "limit": 5, + "skip": 5 + } +} +``` + +##### Response + +For the command `printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10`, the result will look like + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "result": [ + { + "kind": "STDOUT", + "time": "2016-09-24T17:18:30.757623274+03:00", + "text": "1" + }, + { + "kind": "STDOUT", + "time": "2016-09-24T17:18:30.757701555+03:00", + "text": "2" + }, + { + "kind": "STDOUT", + "time": "2016-09-24T17:18:30.757721423+03:00", + "text": "3" + }, + { + "kind": "STDOUT", + "time": "2016-09-24T17:18:30.757841518+03:00", + "text": "4" + }, + { + "kind": "STDOUT", + "time": "2016-09-24T17:18:30.757851622+03:00", + "text": "5" + } + ] +} +``` + +##### Errors + + +- when there is no such process + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32000, + "message": "Process with id '2' does not exist" + } +} +``` + +- when one of the time parameters is invalid, e.g: + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32602, + "message": "Bad format of 'till', parsing time \"date\" as \"2006-01-02T15:04:05.999999999Z07:00\": cannot parse \"date\" as \"2006\"" + } +} +``` + + + +### Get process + +##### Request + +- __pid__ - the id of the process to get + +```json +{ + "method": "process.getProcess", + "id": "0x12345", + "params": { + "pid": 3 + } +} +``` + +##### Response + +When everything is okay + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "result": { + "pid": 1, + "name": "print", + "commandLine": "printf \n1\n2\n3\"", + "type": "test", + "alive": false, + "nativePid": 13158 + } +} +``` + +##### Errors + + +- when there is no such process + +```json +{ + "jsonrpc": "2.0", + "id": "0x12345", + "error": { + "code": -32000, + "message": "Process with id '2' does not exist" + } +} +``` + + +### Get processes + +##### Request + +- __all__(optional) - if `true` then all the processes including _dead_ ones will be returned, +otherwise only _alive_ processes will be returned + +```json +{ + "method": "process.getProcesses", + "id": "id1234567", + "params": { + "all": true + } +} +``` + +##### Response + +```json +{ + "jsonrpc": "2.0", + "id": "id1234567", + "result": [ + { + "pid": 1, + "name": "print", + "commandLine": "printf \"1\n2\n3\"", + "type": "test", + "alive": false, + "nativePid": 13553 + }, + { + "pid": 2, + "name": "print2", + "commandLine": "printf \"\n3\n2\n1\"", + "type": "test2", + "alive": false, + "nativePid": 13561 + } + ] +} +``` diff --git a/exec-agent/pom.xml b/exec-agent/pom.xml new file mode 100644 index 00000000000..e2e945e5a40 --- /dev/null +++ b/exec-agent/pom.xml @@ -0,0 +1,215 @@ + + + + 4.0.0 + + che-parent + org.eclipse.che + 5.0.0-M9-SNAPSHOT + + exec-agent + Exec Agent + + go-workspace + + + + + com.mycila + license-maven-plugin + + + src/term/server.go + src/docs/** + src/vendor/** + src/Godeps/** + src/static/term.js + src/.idea/** + src/exec-agent + src/exec-agent.iml + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + copy-sources + compile + + run + + + + + + + + + + + + + + + + com.soebes.maven.plugins + iterator-maven-plugin + 0.4 + + + compile-exec-agent + compile + + iterator + + + + + linux_arm5 + + linux + arm + 5 + + + + linux_arm6 + + linux + arm + 6 + + + + linux_arm7 + + linux + arm + 7 + + + + linux_amd64 + + linux + amd64 + + + + linux_i386 + + linux + 386 + + + + + + + org.codehaus.mojo + exec-maven-plugin + + exec + + go + ${project.build.directory}/${go.workspace.name}/src/github.com/eclipse/che/exec-agent + + build + -a + -installsuffix + cgo + -o + ${project.build.directory}/${item}/che-websocket-terminal + + + ${project.build.directory}/${go.workspace.name} + ${terminal.target.os} + ${terminal.target.architecture} + ${terminal.target.arm.version} + + + + + + + + assembly + package + + iterator + + + + linux_arm5 + linux_arm6 + linux_arm7 + linux_amd64 + linux_i386 + + + + + maven-assembly-plugin + + single + + + ${basedir}/src/assembly/assembly.xml + + + + + + + + + + + + + integration + + false + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + run-tests + test + + run + + + + + + + + + + + + + + + + + + diff --git a/exec-agent/src/Godeps/Godeps.json b/exec-agent/src/Godeps/Godeps.json new file mode 100644 index 00000000000..17b175c95ef --- /dev/null +++ b/exec-agent/src/Godeps/Godeps.json @@ -0,0 +1,22 @@ +{ + "ImportPath": "github.com/eclipse/che/exec-agent", + "GoVersion": "go1.6", + "GodepVersion": "v74", + "Deps": [ + { + "ImportPath": "github.com/eclipse/che-lib/pty", + "Comment": "4.6.0-2-g69a9cee", + "Rev": "69a9cee57914086c88c8400f5f66cd25422f1fa7" + }, + { + "ImportPath": "github.com/eclipse/che-lib/websocket", + "Comment": "4.6.0-2-g69a9cee", + "Rev": "69a9cee57914086c88c8400f5f66cd25422f1fa7" + }, + { + "ImportPath": "github.com/julienschmidt/httprouter", + "Comment": "v1.1-38-g4563b0b", + "Rev": "4563b0ba73e4db6c6423b60a26f3cadd2e9a1ec9" + } + ] +} diff --git a/exec-agent/src/Godeps/Readme b/exec-agent/src/Godeps/Readme new file mode 100644 index 00000000000..4cdaa53d56d --- /dev/null +++ b/exec-agent/src/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/exec-agent/src/assembly/assembly.xml b/exec-agent/src/assembly/assembly.xml new file mode 100644 index 00000000000..956a8dac74a --- /dev/null +++ b/exec-agent/src/assembly/assembly.xml @@ -0,0 +1,36 @@ + + + ${item} + true + terminal + + zip + tar.gz + + + + ${project.build.directory}/${item} + + che-websocket-terminal + + + + + ${project.build.directory}/${go.workspace.name}/src/github.com/eclipse/che/exec-agent/static + + + + diff --git a/exec-agent/src/auth/auth.go b/exec-agent/src/auth/auth.go new file mode 100644 index 00000000000..bf83bc9df3f --- /dev/null +++ b/exec-agent/src/auth/auth.go @@ -0,0 +1,128 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package auth + +import ( + "errors" + "fmt" + "net/http" + "sync" + "time" + + "github.com/eclipse/che/exec-agent/rest" +) + +const ( + DefaultTokensExpirationTimeoutInMinutes = 10 +) + +// Authenticates all the http calls on workspace master +// checking if provided by request token is valid, if authentication is successful +// then calls ServerHTTP on delegate, otherwise if UnauthorizedHandler is configured +// then uses it to handle the request if not then returns 401 with appropriate error message +type Handler struct { + Delegate http.Handler + ApiEndpoint string + Cache *TokenCache + UnauthorizedHandler func(w http.ResponseWriter, req *http.Request) +} + +func (handler Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + token := req.URL.Query().Get("token") + if handler.Cache.Contains(token) { + handler.Delegate.ServeHTTP(w, req) + } else if err := authenticateOnMaster(handler.ApiEndpoint, token); err == nil { + handler.Cache.Put(token) + handler.Delegate.ServeHTTP(w, req) + } else if handler.UnauthorizedHandler != nil { + handler.UnauthorizedHandler(w, req) + } else { + http.Error(w, err.Error(), http.StatusUnauthorized) + } +} + +// Authentication tokens cache. +type TokenCache struct { + sync.RWMutex + tokens map[string]time.Time + ticker *time.Ticker + expireTimeout time.Duration +} + +func NewCache(expireDuration time.Duration, period time.Duration) *TokenCache { + cache := &TokenCache{ + tokens: make(map[string]time.Time), + expireTimeout: expireDuration, + } + if period > 0 { + go cache.expirePeriodically(period) + } + return cache +} + +// Puts token into the cache. +func (cache *TokenCache) Put(token string) { + cache.Lock() + defer cache.Unlock() + cache.tokens[token] = time.Now().Add(cache.expireTimeout) +} + +// Removes the token from the cache. +func (cache *TokenCache) Expire(token string) { + cache.Lock() + defer cache.Unlock() + delete(cache.tokens, token) +} + +// Returns true if token is present in the cache and false otherwise. +func (cache *TokenCache) Contains(token string) bool { + cache.RLock() + defer cache.RUnlock() + _, ok := cache.tokens[token] + return ok +} + +func (cache *TokenCache) expirePeriodically(period time.Duration) { + cache.ticker = time.NewTicker(period) + for range cache.ticker.C { + cache.expireAllBefore(time.Now()) + } +} + +func (cache *TokenCache) expireAllBefore(expirationPoint time.Time) { + cache.Lock() + defer cache.Unlock() + for token, expTime := range cache.tokens { + if expTime.Before(expirationPoint) { + delete(cache.tokens, token) + } + } +} + +func authenticateOnMaster(apiEndpoint string, tokenParam string) error { + if tokenParam == "" { + return rest.Unauthorized(errors.New("Authentication failed: missing 'token' query parameter")) + } + req, err := http.NewRequest("GET", apiEndpoint+"/machine/token/user/"+tokenParam, nil) + if err != nil { + return rest.Unauthorized(err) + } + req.Header.Add("Authorization", tokenParam) + resp, err := http.DefaultClient.Do(req) + if err != nil { + return rest.Unauthorized(err) + } + if resp.StatusCode != 200 { + return rest.Unauthorized(errors.New(fmt.Sprintf("Authentication failed, token: %s is invalid", tokenParam))) + } + return nil +} diff --git a/exec-agent/src/auth/cache_test.go b/exec-agent/src/auth/cache_test.go new file mode 100644 index 00000000000..c24a1918c28 --- /dev/null +++ b/exec-agent/src/auth/cache_test.go @@ -0,0 +1,56 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package auth + +import ( + "testing" + "time" +) + +func TestTokenCache(t *testing.T) { + cache := &TokenCache{ + tokens: make(map[string]time.Time), + expireTimeout: 0, + } + + token := "my-token" + + cache.Put(token) + if !cache.Contains(token) { + t.Fatalf("Cache must contain token %s", token) + } + + cache.Expire(token) + if cache.Contains(token) { + t.Fatalf("Cache must not contain token %s", token) + } +} + +func TestExpiresTokensCreatedBeforeGivenPointOfTime(t *testing.T) { + cache := &TokenCache{ + tokens: make(map[string]time.Time), + expireTimeout: 0, + } + + cache.Put("token1") + afterToken1Put := time.Now() + cache.Put("token2") + + cache.expireAllBefore(afterToken1Put) + + if cache.Contains("token1") { + t.Fatal("Cache must not contain token1") + } + if !cache.Contains("token2") { + t.Fatal("Cache must contain token2") + } +} diff --git a/exec-agent/src/main.go b/exec-agent/src/main.go new file mode 100644 index 00000000000..144bdfb15e2 --- /dev/null +++ b/exec-agent/src/main.go @@ -0,0 +1,300 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package main + +import ( + "flag" + "fmt" + "log" + "net/http" + "net/url" + "os" + "time" + + "regexp" + + "github.com/eclipse/che/exec-agent/auth" + "github.com/eclipse/che/exec-agent/process" + "github.com/eclipse/che/exec-agent/rest" + "github.com/eclipse/che/exec-agent/rpc" + "github.com/eclipse/che/exec-agent/term" + "github.com/julienschmidt/httprouter" +) + +var ( + AppHttpRoutes = []rest.RoutesGroup{ + process.HttpRoutes, + rpc.HttpRoutes, + term.HttpRoutes, + } + + AppOpRoutes = []rpc.RoutesGroup{ + process.RpcRoutes, + } + + serverAddress string + staticDir string + basePath string + apiEndpoint string + + authEnabled bool + tokensExpirationTimeoutInMinutes uint + + processCleanupThresholdInMinutes int + processCleanupPeriodInMinutes int +) + +func init() { + // server configuration + flag.StringVar( + &serverAddress, + "addr", + ":9000", + "IP:PORT or :PORT the address to start the server on", + ) + flag.StringVar( + &staticDir, + "static", + "./static/", + "path to the directory where static content is located", + ) + flag.StringVar( + &basePath, + "path", + "", + `the base path for all the rpc & rest routes, so route paths are treated not + as 'server_address + route_path' but 'server_address + path + route_path'. + For example for the server address 'localhost:9000', route path '/connect' and + configured path '/api/' exec-agent server will serve the following route: + 'localhost:9000/api/connect'. + Regexp syntax is supported`, + ) + + // terminal configuration + flag.StringVar( + &term.Cmd, + "cmd", + "/bin/bash", + "command to execute on slave side of the pty", + ) + + // workspace master server configuration + flag.StringVar( + &apiEndpoint, + "api-endpoint", + os.Getenv("CHE_API"), + `api-endpoint used by exec-agent modules(such as activity checker or authentication) + to request workspace master. By default the value from 'CHE_API' environment variable is used`, + ) + + // auth configuration + flag.BoolVar( + &authEnabled, + "enable-auth", + false, + "whether authenicate requests on workspace master before allowing them to proceed", + ) + flag.UintVar( + &tokensExpirationTimeoutInMinutes, + "tokens-expiration-timeout", + auth.DefaultTokensExpirationTimeoutInMinutes, + "how much time machine tokens stay in cache(if auth is enabled)", + ) + + // terminal configuration + flag.BoolVar( + &term.ActivityTrackingEnabled, + "enable-activity-tracking", + false, + "whether workspace master will be notified about terminal activity", + ) + + // process executor configuration + flag.IntVar( + &processCleanupPeriodInMinutes, + "process-cleanup-period", + -1, + "how often processs cleanup job will be executed(in minutes)", + ) + flag.IntVar(&processCleanupThresholdInMinutes, + "process-cleanup-threshold", + -1, + `how much time will dead and unused process stay(in minutes), + if -1 passed then processes won't be cleaned at all. Please note that the time + of real cleanup is between configured threshold and threshold + process-cleanup-period.`, + ) + curDir, _ := os.Getwd() + curDir += string(os.PathSeparator) + "logs" + flag.StringVar( + &process.LogsDir, + "logs-dir", + curDir, + "base directory for process logs", + ) +} + +func main() { + flag.Parse() + + log.SetOutput(os.Stdout) + + // print configuration + fmt.Println("Exec-agent configuration") + fmt.Println(" Server") + fmt.Printf(" - Address: %s\n", serverAddress) + fmt.Printf(" - Static content: %s\n", staticDir) + fmt.Printf(" - Base path: '%s'\n", basePath) + fmt.Println(" Terminal") + fmt.Printf(" - Slave command: '%s'\n", term.Cmd) + fmt.Printf(" - Activity tracking enabled: %t\n", term.ActivityTrackingEnabled) + if authEnabled { + fmt.Println(" Authentication") + fmt.Printf(" - Enabled: %t\n", authEnabled) + fmt.Printf(" - Tokens expiration timeout: %dm\n", tokensExpirationTimeoutInMinutes) + } + fmt.Println(" Process executor") + fmt.Printf(" - Logs dir: %s\n", process.LogsDir) + if processCleanupPeriodInMinutes > 0 { + fmt.Printf(" - Cleanup job period: %dm\n", processCleanupPeriodInMinutes) + fmt.Printf(" - Not used & dead processes stay for: %dm\n", processCleanupThresholdInMinutes) + } + if authEnabled || term.ActivityTrackingEnabled { + fmt.Println(" Workspace master server") + fmt.Printf(" - API endpoint: %s\n", apiEndpoint) + } + fmt.Println() + + term.ApiEndpoint = apiEndpoint + + // process configuration + if err := os.RemoveAll(process.LogsDir); err != nil { + log.Fatal(err) + } + + if processCleanupPeriodInMinutes > 0 { + if processCleanupThresholdInMinutes < 0 { + log.Fatal("Expected process cleanup threshold to be non negative value") + } + cleaner := process.NewCleaner(processCleanupPeriodInMinutes, processCleanupThresholdInMinutes) + cleaner.CleanPeriodically() + } + + // terminal configuration + if term.ActivityTrackingEnabled { + go term.Activity.StartTracking() + } + + // register routes and http handlers + router := httprouter.New() + router.NotFound = http.FileServer(http.Dir(staticDir)) + + fmt.Print("⇩ Registered HttpRoutes:\n\n") + for _, routesGroup := range AppHttpRoutes { + fmt.Printf("%s:\n", routesGroup.Name) + for _, route := range routesGroup.Items { + router.Handle( + route.Method, + route.Path, + toHandle(route.HandleFunc), + ) + fmt.Printf("✓ %s\n", &route) + } + fmt.Println() + } + + fmt.Print("\n⇩ Registered RpcRoutes:\n\n") + for _, routesGroup := range AppOpRoutes { + fmt.Printf("%s:\n", routesGroup.Name) + for _, route := range routesGroup.Items { + fmt.Printf("✓ %s\n", route.Method) + rpc.RegisterRoute(route) + } + } + + var handler http.Handler = router + + // required authentication for all the requests, if it is configured + if authEnabled { + cache := auth.NewCache(time.Minute*time.Duration(tokensExpirationTimeoutInMinutes), time.Minute*5) + + handler = auth.Handler{ + Delegate: handler, + ApiEndpoint: apiEndpoint, + Cache: cache, + UnauthorizedHandler: func(w http.ResponseWriter, req *http.Request) { + dropChannelsWithExpiredToken(req.URL.Query().Get("token")) + http.Error(w, "Unauthorized", http.StatusUnauthorized) + }, + } + } + + // cut base path on requests, if it is configured + if basePath != "" { + if rx, err := regexp.Compile(basePath); err == nil { + handler = basePathChopper{rx, handler} + } else { + log.Fatal(err) + } + } + + http.Handle("/", handler) + + server := &http.Server{ + Handler: handler, + Addr: serverAddress, + WriteTimeout: 10 * time.Second, + ReadTimeout: 10 * time.Second, + } + log.Fatal(server.ListenAndServe()) +} + +func dropChannelsWithExpiredToken(token string) { + for _, c := range rpc.GetChannels() { + u, err := url.ParseRequestURI(c.RequestURI) + if err != nil { + log.Printf("Couldn't parse the RequestURI '%s' of channel '%s'", c.RequestURI, c.Id) + } else if u.Query().Get("token") == token { + log.Printf("Token for channel '%s' is expired, trying to drop the channel", c.Id) + rpc.DropChannel(c.Id) + } + } +} + +type routerParamsAdapter struct { + params httprouter.Params +} + +func (pa routerParamsAdapter) Get(param string) string { + return pa.params.ByName(param) +} + +func toHandle(f rest.HttpRouteHandlerFunc) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + if err := f(w, r, routerParamsAdapter{params: p}); err != nil { + rest.WriteError(w, err) + } + } +} + +type basePathChopper struct { + pattern *regexp.Regexp + delegate http.Handler +} + +func (c basePathChopper) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // if request path starts with given base path + if idx := c.pattern.FindStringSubmatchIndex(r.URL.Path); len(idx) != 0 && idx[0] == 0 { + r.URL.Path = r.URL.Path[idx[1]:] + r.RequestURI = r.RequestURI[idx[1]:] + } + c.delegate.ServeHTTP(w, r) +} diff --git a/exec-agent/src/process/common.go b/exec-agent/src/process/common.go new file mode 100644 index 00000000000..7ef333e27ef --- /dev/null +++ b/exec-agent/src/process/common.go @@ -0,0 +1,79 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "errors" + "strconv" + "strings" + "time" +) + +const ( + DefaultLogsPerPageLimit = 50 +) + +func maskFromTypes(types string) uint64 { + var mask uint64 + for _, t := range strings.Split(types, ",") { + switch strings.ToLower(strings.TrimSpace(t)) { + case "stderr": + mask |= StderrBit + case "stdout": + mask |= StdoutBit + case "process_status": + mask |= ProcessStatusBit + } + } + return mask +} + +func parseTypes(types string) uint64 { + var mask uint64 = DefaultMask + if types != "" { + mask = maskFromTypes(types) + } + return mask +} + +// Checks whether pid is valid and converts it to the uint64 +func parsePid(strPid string) (uint64, error) { + intPid, err := strconv.Atoi(strPid) + if err != nil { + return 0, errors.New("Pid value must be unsigned integer") + } + if intPid <= 0 { + return 0, errors.New("Pid value must be unsigned integer") + } + return uint64(intPid), nil +} + +// Checks whether command is valid +func checkCommand(command *Command) error { + if command.Name == "" { + return errors.New("Command name required") + } + if command.CommandLine == "" { + return errors.New("Command line required") + } + return nil +} + +// If time string is empty, then default time is returned +// If time string is invalid, then appropriate error is returned +// If time string is valid then parsed time is returned +func parseTime(timeStr string, defTime time.Time) (time.Time, error) { + if timeStr == "" { + return defTime, nil + } + return time.Parse(DateTimeFormat, timeStr) +} diff --git a/exec-agent/src/process/events.go b/exec-agent/src/process/events.go new file mode 100644 index 00000000000..8bf1e1cb981 --- /dev/null +++ b/exec-agent/src/process/events.go @@ -0,0 +1,72 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "github.com/eclipse/che/exec-agent/rpc" + "time" +) + +const ( + StartedEventType = "process_started" + DiedEventType = "process_died" + StdoutEventType = "process_stdout" + StderrEventType = "process_stderr" +) + +type ProcessStatusEventBody struct { + rpc.Timed + Pid uint64 `json:"pid"` + NativePid int `json:"nativePid"` + Name string `json:"name"` + CommandLine string `json:"commandLine"` +} + +type ProcessOutputEventBody struct { + rpc.Timed + Pid uint64 `json:"pid"` + Text string `json:"text"` +} + +func newStderrEvent(pid uint64, text string, when time.Time) *rpc.Event { + return rpc.NewEvent(StderrEventType, &ProcessOutputEventBody{ + Timed: rpc.Timed{Time: when}, + Pid: pid, + Text: text, + }) +} + +func newStdoutEvent(pid uint64, text string, when time.Time) *rpc.Event { + return rpc.NewEvent(StdoutEventType, &ProcessOutputEventBody{ + Timed: rpc.Timed{Time: when}, + Pid: pid, + Text: text, + }) +} + +func newStatusEvent(mp MachineProcess, status string) *rpc.Event { + return rpc.NewEvent(status, &ProcessStatusEventBody{ + Timed: rpc.Timed{Time: time.Now()}, + Pid: mp.Pid, + NativePid: mp.NativePid, + Name: mp.Name, + CommandLine: mp.CommandLine, + }) +} + +func newStartedEvent(mp MachineProcess) *rpc.Event { + return newStatusEvent(mp, StartedEventType) +} + +func newDiedEvent(mp MachineProcess) *rpc.Event { + return newStatusEvent(mp, DiedEventType) +} diff --git a/exec-agent/src/process/file_logger.go b/exec-agent/src/process/file_logger.go new file mode 100644 index 00000000000..fc2be5f779a --- /dev/null +++ b/exec-agent/src/process/file_logger.go @@ -0,0 +1,84 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "bytes" + "encoding/json" + "log" + "os" + "sync" + "time" +) + +const ( + flushThreshold = 8192 +) + +type FileLogger struct { + sync.RWMutex + filename string + buffer *bytes.Buffer + encoder *json.Encoder +} + +func NewLogger(filename string) (*FileLogger, error) { + fl := &FileLogger{filename: filename} + fl.buffer = &bytes.Buffer{} + fl.encoder = json.NewEncoder(fl.buffer) + + // Trying to create logs file + file, err := os.Create(filename) + if err != nil { + return nil, err + } + defer file.Close() + + return fl, nil +} + +func (fl *FileLogger) Flush() { + fl.Lock() + fl.doFlush() + fl.Unlock() +} + +func (fl *FileLogger) OnStdout(line string, time time.Time) { + fl.writeLine(&LogMessage{StdoutKind, time, line}) +} + +func (fl *FileLogger) OnStderr(line string, time time.Time) { + fl.writeLine(&LogMessage{StderrKind, time, line}) +} + +func (fl *FileLogger) Close() { + fl.Flush() +} + +func (fl *FileLogger) writeLine(message *LogMessage) { + fl.Lock() + fl.encoder.Encode(message) + if flushThreshold < fl.buffer.Len() { + fl.doFlush() + } + fl.Unlock() +} + +func (fl *FileLogger) doFlush() { + f, err := os.OpenFile(fl.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + if err != nil { + log.Printf("Couldn't open file '%s' for flushing the buffer. %s \n", fl.filename, err.Error()) + } else { + defer f.Close() + fl.buffer.WriteTo(f) + } +} diff --git a/exec-agent/src/process/file_logger_test.go b/exec-agent/src/process/file_logger_test.go new file mode 100644 index 00000000000..0970a60d16e --- /dev/null +++ b/exec-agent/src/process/file_logger_test.go @@ -0,0 +1,125 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process_test + +import ( + "encoding/json" + "github.com/eclipse/che/exec-agent/process" + "io/ioutil" + "math/rand" + "os" + "testing" + "time" +) + +var alphabet = []byte("abcdefgh123456789") + +func TestFileLoggerCreatesFileWhenFileDoesNotExist(t *testing.T) { + filename := os.TempDir() + string(os.PathSeparator) + randomName(10) + defer os.Remove(filename) + + if _, err := os.Stat(filename); err == nil { + t.Fatalf("File '%s' already exists", filename) + } + + if _, err := process.NewLogger(filename); err != nil { + t.Fatal(err) + } + + if _, err := os.Stat(filename); os.IsNotExist(err) { + t.Fatalf("Expected file '%s' was created, but it wasn't", filename) + } +} + +func TestFileLoggerTruncatesFileIfFileExistsOnCreate(t *testing.T) { + filename := os.TempDir() + string(os.PathSeparator) + randomName(10) + defer os.Remove(filename) + + if _, err := os.Create(filename); err != nil { + t.Fatal(err) + } + if err := ioutil.WriteFile(filename, []byte("file-content"), 0666); err != nil { + t.Fatal(err) + } + + if _, err := process.NewLogger(filename); err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatal(err) + } + if len(content) != 0 { + t.Errorf("Expected file '%s' content is empty", filename) + } +} + +func TestLogsAreFlushedOnClose(t *testing.T) { + filename := os.TempDir() + string(os.PathSeparator) + randomName(10) + defer os.Remove(filename) + + fl, err := process.NewLogger(filename) + if err != nil { + t.Fatal(err) + } + + // Write something to the log + now := time.Now() + fl.OnStdout("stdout", now) + fl.OnStderr("stderr", now) + fl.Close() + + // Read file content + f, err := os.Open(filename) + if err != nil { + t.Fatal(err) + } + + // Read log messages + stdout := process.LogMessage{} + stderr := process.LogMessage{} + decoder := json.NewDecoder(f) + if err := decoder.Decode(&stdout); err != nil { + t.Fatal(err) + } + if err := decoder.Decode(&stderr); err != nil { + t.Fatal(err) + } + + // Check logs are okay + expectedStdout := process.LogMessage{ + Kind: process.StdoutKind, + Time: now, + Text: "stdout", + } + if stdout != expectedStdout { + t.Fatalf("Expected %v but found %v", expectedStdout, stdout) + } + expectedStderr := process.LogMessage{ + Kind: process.StderrKind, + Time: now, + Text: "stderr", + } + if stdout != expectedStdout { + t.Fatalf("Expected %v but found %v", expectedStderr, stderr) + } +} + +func randomName(length int) string { + rand.Seed(time.Now().UnixNano()) + bytes := make([]byte, length) + for i := 0; i < length; i++ { + bytes[i] = alphabet[rand.Intn(len(alphabet))] + } + return string(bytes) +} diff --git a/exec-agent/src/process/logs_distributor.go b/exec-agent/src/process/logs_distributor.go new file mode 100644 index 00000000000..9dd1c2e7909 --- /dev/null +++ b/exec-agent/src/process/logs_distributor.go @@ -0,0 +1,63 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "errors" + "fmt" + "os" +) + +const ( + DefaultMaxDirsCount = 16 +) + +// Distributes the logs between different directories +type LogsDistributor interface { + + // The implementor must guarantee that returned file name + // is always the same for the same pid. + // Returns an error if it is impossible to create hierarchy of + // logs file parent folders, otherwise returns file path + DirForPid(baseDir string, pid uint64) (string, error) +} + +type DefaultLogsDistributor struct { + MaxDirsCount uint +} + +func NewLogsDistributor() LogsDistributor { + return &DefaultLogsDistributor{ + MaxDirsCount: DefaultMaxDirsCount, + } +} + +func (ld *DefaultLogsDistributor) DirForPid(baseDir string, pid uint64) (string, error) { + // directories from 1 to maxDirsCount inclusive + subDirName := (pid % uint64(ld.MaxDirsCount)) + + // {baseLogsDir}/{subDirName} + pidLogsDir := fmt.Sprintf("%s%c%d", baseDir, os.PathSeparator, subDirName) + + // Create subdirectory + if info, err := os.Stat(pidLogsDir); os.IsNotExist(err) { + if err := os.MkdirAll(pidLogsDir, os.ModePerm); err != nil { + return "", err + } + } else if err != nil { + return "", err + } else if !info.IsDir() { + m := fmt.Sprintf("Couldn't create a directory '%s', the name is taken by file", pidLogsDir) + return "", errors.New(m) + } + return pidLogsDir, nil +} diff --git a/exec-agent/src/process/logs_distributor_test.go b/exec-agent/src/process/logs_distributor_test.go new file mode 100644 index 00000000000..ccfb39d0ca7 --- /dev/null +++ b/exec-agent/src/process/logs_distributor_test.go @@ -0,0 +1,72 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process_test + +import ( + "fmt" + "github.com/eclipse/che/exec-agent/process" + "io/ioutil" + "os" + "testing" +) + +func TestLogsDistributorCreatesSubdirectories(t *testing.T) { + baseDir := os.TempDir() + string(os.PathSeparator) + randomName(10) + defer os.RemoveAll(baseDir) + + distributor := process.DefaultLogsDistributor{ + MaxDirsCount: 4, + } + + dir, err := distributor.DirForPid(baseDir, 1) + if err != nil { + t.Fatal(err) + } + + if _, err := os.Stat(dir); os.IsNotExist(err) { + t.Fatal("Expected that logs file subdirectory was created") + } else if err != nil { + t.Fatal(err) + } +} + +func TestLogsDistribution(t *testing.T) { + baseDir := os.TempDir() + string(os.PathSeparator) + randomName(10) + defer os.RemoveAll(baseDir) + + distributor := process.DefaultLogsDistributor{ + MaxDirsCount: 4, + } + + // Those files should be evenly distributed in 4 directories + for pid := 1; pid <= 16; pid++ { + dir, err := distributor.DirForPid(baseDir, uint64(pid)) + if err != nil { + t.Fatal(err) + } + filename := fmt.Sprintf("%s%cpid-%d", dir, os.PathSeparator, pid) + if _, err := os.Create(filename); err != nil { + t.Fatal(err) + } + } + + for i := 0; i < 4; i++ { + dir := fmt.Sprintf("%s%c%d", baseDir, os.PathSeparator, i) + fi, err := ioutil.ReadDir(dir) + if err != nil { + t.Fatal(err) + } + if len(fi) != 4 { + t.Fatalf("Expected directory '%s' to contain 4 files", dir) + } + } +} diff --git a/exec-agent/src/process/logs_reader.go b/exec-agent/src/process/logs_reader.go new file mode 100644 index 00000000000..73065461649 --- /dev/null +++ b/exec-agent/src/process/logs_reader.go @@ -0,0 +1,87 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "bufio" + "encoding/json" + "io" + "os" + "time" +) + +type LogsReader struct { + filename string + readFrom *time.Time + readTill *time.Time +} + +func NewLogsReader(filename string) *LogsReader { + return &LogsReader{filename: filename} +} + +// Skip all the logs before the given time. +// If the log message appeared at the given time, it won't be skipped. +func (lr *LogsReader) From(time time.Time) *LogsReader { + lr.readFrom = &time + return lr +} + +// Read logs which appeared before and right at a given time +func (lr *LogsReader) Till(time time.Time) *LogsReader { + lr.readTill = &time + return lr +} + +// Reads logs between [from, till] inclusive. +// Returns an error if logs file is missing, or +// decoding of file content failed. +// If no logs matched time frame, an empty slice will be returned. +func (lr *LogsReader) ReadLogs() ([]*LogMessage, error) { + // Open logs file for reading logs + logsFile, err := os.Open(lr.filename) + if err != nil { + return nil, err + } + defer logsFile.Close() + + from := time.Time{} + if lr.readFrom != nil { + from = *lr.readFrom + } + till := time.Now() + if lr.readTill != nil { + till = *lr.readTill + } + + // Read logs + logs := []*LogMessage{} + decoder := json.NewDecoder(bufio.NewReader(logsFile)) + for { + message := &LogMessage{} + err = decoder.Decode(message) + if err != nil { + if err == io.EOF { + break + } + return nil, err + } + if message.Time.Before(from) { + continue + } + if message.Time.After(till) { + break + } + logs = append(logs, message) + } + return logs, nil +} diff --git a/exec-agent/src/process/logs_reader_test.go b/exec-agent/src/process/logs_reader_test.go new file mode 100644 index 00000000000..1ee7cb4ca94 --- /dev/null +++ b/exec-agent/src/process/logs_reader_test.go @@ -0,0 +1,60 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process_test + +import ( + "github.com/eclipse/che/exec-agent/process" + "os" + "testing" + "time" +) + +func TestReadLogs(t *testing.T) { + filename := os.TempDir() + string(os.PathSeparator) + randomName(10) + defer os.Remove(filename) + + fl, err := process.NewLogger(filename) + if err != nil { + t.Fatal(err) + } + + // Write something to the log + now := time.Now() + fl.OnStdout("line1", now.Add(time.Second)) + fl.OnStdout("line2", now.Add(time.Second*2)) + fl.OnStdout("line3", now.Add(time.Second*3)) + fl.OnStderr("line4", now.Add(time.Second*4)) + fl.OnStderr("line5", now.Add(time.Second*5)) + fl.Close() + + // Read logs [2, 4] + logs, err := + process.NewLogsReader(filename). + From(now.Add(time.Second * 2)). + Till(now.Add(time.Second * 4)). + ReadLogs() + if err != nil { + t.Fatal(err) + } + + // Check everything is okay + expected := []process.LogMessage{ + {Kind: process.StdoutKind, Time: now.Add(time.Second * 2), Text: "line2"}, + {Kind: process.StdoutKind, Time: now.Add(time.Second * 3), Text: "line3"}, + {Kind: process.StderrKind, Time: now.Add(time.Second * 4), Text: "line4"}, + } + for i := 0; i < len(logs); i++ { + if *logs[i] != expected[i] { + t.Fatalf("Expected: '%v' Found '%v'", expected[i], *logs[i]) + } + } +} diff --git a/exec-agent/src/process/process.go b/exec-agent/src/process/process.go new file mode 100644 index 00000000000..25075916bae --- /dev/null +++ b/exec-agent/src/process/process.go @@ -0,0 +1,483 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "errors" + "fmt" + "os" + "os/exec" + "sync" + "sync/atomic" + "syscall" + "time" + + "github.com/eclipse/che/exec-agent/rpc" +) + +const ( + StdoutBit = 1 << iota + StderrBit = 1 << iota + ProcessStatusBit = 1 << iota + DefaultMask = StderrBit | StdoutBit | ProcessStatusBit + + DateTimeFormat = time.RFC3339Nano + + StdoutKind = "STDOUT" + StderrKind = "STDERR" +) + +var ( + prevPid uint64 = 0 + processes = &processesMap{items: make(map[uint64]*MachineProcess)} + logsDist = NewLogsDistributor() + LogsDir string +) + +type Command struct { + Name string `json:"name"` + CommandLine string `json:"commandLine"` + Type string `json:"type"` +} + +// Defines machine process model +type MachineProcess struct { + + // The virtual id of the process, it is guaranteed that pid + // is always unique, while NativePid may occur twice or more(when including dead processes) + Pid uint64 `json:"pid"` + + // The name of the process, it is equal to the Command.Name which this process created from. + // It doesn't have to be unique, at least machine agent doesn't need such constraint, + // as pid is used for identifying process + Name string `json:"name"` + + // The command line executed by this process. + // It is equal to the Command.CommandLine which this process created from + CommandLine string `json:"commandLine"` + + // The type of the command line, this field is rather useful meta + // information than something used for functioning. It is equal + // to the Command.Type which this process created from + Type string `json:"type"` + + // Whether this process is alive or dead + Alive bool `json:"alive"` + + // The native(OS) pid, it is unique per alive processes, + // but those which are not alive, may have the same NativePid + NativePid int `json:"nativePid"` + + // Process log filename + logfileName string + + // Command executed by this process. + // If process is not alive then the command value is set to nil + command *exec.Cmd + + // Stdout/stderr pumper. + // If process is not alive then the pumper value is set to nil + pumper *LogsPumper + + // Process subscribers, all the outgoing events are go through those subscribers. + // If process is not alive then the subscribers value is set to nil + subs []*Subscriber + + // Process file logger + fileLogger *FileLogger + + // Process mutex should be used to sync process data + // or block on process related operations such as events publications + mutex sync.RWMutex + + // When the process was last time used by client + lastUsed time.Time + lastUsedLock sync.RWMutex + + // Called once before any of process events is published + // and after process is started + beforeEventsHook func(process MachineProcess) +} + +type Subscriber struct { + Id string + Mask uint64 + Channel chan *rpc.Event +} + +type LogMessage struct { + Kind string `json:"kind"` + Time time.Time `json:"time"` + Text string `json:"text"` +} + +type NoProcessError struct { + error + Pid uint64 +} + +type NotAliveError struct { + error + Pid uint64 +} + +// Lockable map for storing processes +type processesMap struct { + sync.RWMutex + items map[uint64]*MachineProcess +} + +func Start(process MachineProcess) (MachineProcess, error) { + // wrap command to be able to kill child processes see https://github.com/golang/go/issues/8854 + cmd := exec.Command("setsid", "sh", "-c", process.CommandLine) + + // getting stdout pipe + stdout, err := cmd.StdoutPipe() + if err != nil { + return process, err + } + + // getting stderr pipe + stderr, err := cmd.StderrPipe() + if err != nil { + return process, err + } + + // starting a new process + err = cmd.Start() + if err != nil { + return process, err + } + + // increment current pid & assign it to the value + pid := atomic.AddUint64(&prevPid, 1) + + // Figure out the place for logs file + dir, err := logsDist.DirForPid(LogsDir, pid) + if err != nil { + return process, err + } + filename := fmt.Sprintf("%s%cpid-%d", dir, os.PathSeparator, pid) + + fileLogger, err := NewLogger(filename) + if err != nil { + return process, err + } + + // save process + process.Pid = pid + process.Alive = true + process.NativePid = cmd.Process.Pid + process.command = cmd + process.pumper = NewPumper(stdout, stderr) + process.logfileName = filename + process.fileLogger = fileLogger + process.updateLastUsedTime() + + processes.Lock() + processes.items[pid] = &process + processes.Unlock() + + // register logs consumers + process.pumper.AddConsumer(fileLogger) + process.pumper.AddConsumer(&process) + + if process.beforeEventsHook != nil { + process.beforeEventsHook(process) + } + + // before pumping is started publish process_started event + startPublished := make(chan bool) + go func() { + process.notifySubs(newStartedEvent(process), ProcessStatusBit) + startPublished <- true + }() + + // start pumping after start event is published 'pumper.Pump' is blocking + go func() { + <-startPublished + process.pumper.Pump() + }() + + return process, nil +} + +// Gets process by pid. +// If process doesn't exist then error of type NoProcessError is returned. +func Get(pid uint64) (MachineProcess, error) { + p, ok := directGet(pid) + if ok { + return *p, nil + } + return MachineProcess{}, noProcess(pid) +} + +func GetProcesses(all bool) []MachineProcess { + processes.RLock() + defer processes.RUnlock() + + pArr := make([]MachineProcess, 0, len(processes.items)) + for _, p := range processes.items { + if all { + pArr = append(pArr, *p) + } else { + p.mutex.RLock() + if p.Alive { + pArr = append(pArr, *p) + } + p.mutex.RUnlock() + } + } + return pArr +} + +// Kills process by given pid. +// Returns an error when any error occurs during process kill. +// If process doesn't exist error of type NoProcessError is returned. +func Kill(pid uint64) error { + p, ok := directGet(pid) + if !ok { + return noProcess(pid) + } + if !p.Alive { + return notAlive(pid) + } + // workaround for killing child processes see https://github.com/golang/go/issues/8854 + return syscall.Kill(-p.NativePid, syscall.SIGKILL) +} + +// Reads process logs between [from, till] inclusive. +// Returns an error if any error occurs during logs reading. +// If process doesn't exist error of type NoProcessError is returned. +func ReadLogs(pid uint64, from time.Time, till time.Time) ([]*LogMessage, error) { + p, ok := directGet(pid) + if !ok { + return nil, noProcess(pid) + } + fl := p.fileLogger + if p.Alive { + fl.Flush() + } + return NewLogsReader(p.logfileName).From(from).Till(till).ReadLogs() +} + +// Reads all process logs. +// Returns an error if any error occurs during logs reading. +// If process doesn't exist error of type NoProcessError is returned. +func ReadAllLogs(pid uint64) ([]*LogMessage, error) { + return ReadLogs(pid, time.Time{}, time.Now()) +} + +// Unsubscribe subscriber with given id from process events. +// If process doesn't exist then error of type NoProcessError is returned. +func RemoveSubscriber(pid uint64, id string) error { + p, ok := directGet(pid) + if !ok { + return noProcess(pid) + } + if !p.Alive { + return notAlive(pid) + } + p.mutex.Lock() + defer p.mutex.Unlock() + for idx, sub := range p.subs { + if sub.Id == id { + p.subs = append(p.subs[0:idx], p.subs[idx+1:]...) + break + } + } + return nil +} + +// Subscribe to the process output. +// An error of type NoProcessError is returned when process +// with given pid doesn't exist, a regular error is returned +// if the process is dead or subscriber with such id already subscribed +// to the process output. +func AddSubscriber(pid uint64, subscriber Subscriber) error { + p, ok := directGet(pid) + if !ok { + return noProcess(pid) + } + p.mutex.Lock() + defer p.mutex.Unlock() + if !p.Alive && p.NativePid != 0 { + return errors.New("Can't subscribe to the events of dead process") + } + for _, sub := range p.subs { + if sub.Id == subscriber.Id { + return errors.New("Already subscribed") + } + } + p.subs = append(p.subs, &subscriber) + return nil +} + +// Adds a new process subscriber by reading all the logs between +// given 'after' and now and publishing them to the channel. +// Returns an error of type NoProcessError if process with given id doesn't exist, +// returns a regular error if process is alive an subscriber with such id +// already subscribed. +func RestoreSubscriber(pid uint64, subscriber Subscriber, after time.Time) error { + p, ok := directGet(pid) + if !ok { + return noProcess(pid) + } + p.mutex.Lock() + defer p.mutex.Unlock() + + // Read logs between after and now + logs, err := ReadLogs(pid, after, time.Now()) + if err != nil { + return err + } + + // If process is dead there is no need to subscribe to it + // as it is impossible to get it alive again, but it is still + // may be useful for client to get missed logs, that's why this + // function doesn't throw any errors in the case of dead process + if p.Alive { + for _, sub := range p.subs { + if sub.Id == subscriber.Id { + return errors.New("Already subscribed") + } + } + p.subs = append(p.subs, &subscriber) + } + + // Publish all the logs between (after, now] + for i := 0; i < len(logs); i++ { + message := logs[i] + if message.Time.After(after) { + if message.Kind == StdoutKind { + subscriber.Channel <- newStdoutEvent(p.Pid, message.Text, message.Time) + } else { + subscriber.Channel <- newStderrEvent(p.Pid, message.Text, message.Time) + } + } + } + + // Publish died event after logs are published and process is dead + if !p.Alive { + subscriber.Channel <- newDiedEvent(*p) + } + + return nil +} + +// Updates subscriber with given id. +// An error of type NoProcessError is returned when process +// with given pid doesn't exist, a regular error is returned +// if the process is dead. +func UpdateSubscriber(pid uint64, id string, newMask uint64) error { + p, ok := directGet(pid) + if !ok { + return noProcess(pid) + } + if !p.Alive { + return notAlive(pid) + } + p.mutex.Lock() + defer p.mutex.Unlock() + for _, sub := range p.subs { + if sub.Id == id { + sub.Mask = newMask + return nil + } + } + return errors.New(fmt.Sprintf("No subscriber with id '%s'", id)) +} + +func (process *MachineProcess) OnStdout(line string, time time.Time) { + process.notifySubs(newStdoutEvent(process.Pid, line, time), StdoutBit) +} + +func (process *MachineProcess) OnStderr(line string, time time.Time) { + process.notifySubs(newStderrEvent(process.Pid, line, time), StderrBit) +} + +func (mp *MachineProcess) Close() { + // Cleanup command resources + mp.command.Wait() + // Cleanup machine process resources before dead event is sent + mp.mutex.Lock() + mp.Alive = false + mp.command = nil + mp.pumper = nil + mp.mutex.Unlock() + + mp.notifySubs(newDiedEvent(*mp), ProcessStatusBit) + + mp.mutex.Lock() + mp.subs = nil + mp.mutex.Unlock() + + mp.updateLastUsedTime() +} + +func (p *MachineProcess) notifySubs(event *rpc.Event, typeBit uint64) { + p.mutex.RLock() + subs := p.subs + for _, subscriber := range subs { + // Check whether subscriber needs such kind of event and then try to notify it + if subscriber.Mask&typeBit == typeBit && !tryWrite(subscriber.Channel, event) { + // Impossible to write to the channel, remove the channel from the subscribers list. + // It may happen when writing to the closed channel + defer RemoveSubscriber(p.Pid, subscriber.Id) + } + } + p.mutex.RUnlock() +} + +func (mp *MachineProcess) updateLastUsedTime() { + mp.lastUsedLock.Lock() + mp.lastUsed = time.Now() + mp.lastUsedLock.Unlock() +} + +// Writes to a channel and returns true if write is successful, +// otherwise if write to the channel failed e.g. channel is closed then returns false +func tryWrite(eventsChan chan *rpc.Event, event *rpc.Event) (ok bool) { + defer func() { + if r := recover(); r != nil { + ok = false + } + }() + eventsChan <- event + return true +} + +func directGet(pid uint64) (*MachineProcess, bool) { + processes.RLock() + defer processes.RUnlock() + item, ok := processes.items[pid] + if ok { + item.updateLastUsedTime() + } + return item, ok +} + +// Returns an error indicating that process with given pid doesn't exist +func noProcess(pid uint64) *NoProcessError { + return &NoProcessError{ + error: errors.New(fmt.Sprintf("Process with id '%d' does not exist", pid)), + Pid: pid, + } +} + +// Returns an error indicating that process with given pid is not alive +func notAlive(pid uint64) *NotAliveError { + return &NotAliveError{ + error: errors.New(fmt.Sprintf("Process with id '%d' is not alive", pid)), + Pid: pid, + } +} diff --git a/exec-agent/src/process/process_builder.go b/exec-agent/src/process/process_builder.go new file mode 100644 index 00000000000..3d18110df41 --- /dev/null +++ b/exec-agent/src/process/process_builder.go @@ -0,0 +1,72 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +type ProcessBuilder struct { + command Command + beforeEventsHook func(p MachineProcess) + firstSubscriber *Subscriber +} + +func NewBuilder() *ProcessBuilder { + return &ProcessBuilder{} +} + +func (pb *ProcessBuilder) Cmd(command Command) *ProcessBuilder { + pb.command = command + return pb +} + +func (pb *ProcessBuilder) CmdLine(cmdLine string) *ProcessBuilder { + pb.command.CommandLine = cmdLine + return pb +} + +func (pb *ProcessBuilder) CmdType(cmdType string) *ProcessBuilder { + pb.command.Type = cmdType + return pb +} + +func (pb *ProcessBuilder) CmdName(cmdName string) *ProcessBuilder { + pb.command.Name = cmdName + return pb +} + +// Sets the hook which will be called once before +// process subscribers notified with any of the process events, +// and after process is started. +func (pb *ProcessBuilder) BeforeEventsHook(hook func(p MachineProcess)) *ProcessBuilder { + pb.beforeEventsHook = hook + return pb +} + +func (pb *ProcessBuilder) FirstSubscriber(subscriber Subscriber) *ProcessBuilder { + pb.firstSubscriber = &subscriber + return pb +} + +func (pb *ProcessBuilder) Build() MachineProcess { + p := MachineProcess{ + Name: pb.command.Name, + CommandLine: pb.command.CommandLine, + Type: pb.command.Type, + beforeEventsHook: pb.beforeEventsHook, + } + if pb.firstSubscriber != nil { + p.subs = []*Subscriber{pb.firstSubscriber} + } + return p +} + +func (pb *ProcessBuilder) Start() (MachineProcess, error) { + return Start(pb.Build()) +} diff --git a/exec-agent/src/process/process_cleaner.go b/exec-agent/src/process/process_cleaner.go new file mode 100644 index 00000000000..7068618fbc2 --- /dev/null +++ b/exec-agent/src/process/process_cleaner.go @@ -0,0 +1,56 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "log" + "os" + "time" +) + +type Cleaner struct { + CleanupPeriod time.Duration + CleanupThreshold time.Duration +} + +func NewCleaner(period int, threshold int) *Cleaner { + return &Cleaner{ + time.Duration(period) * time.Minute, + time.Duration(threshold) * time.Minute, + } +} + +func (c *Cleaner) CleanPeriodically() { + ticker := time.NewTicker(c.CleanupPeriod) + defer ticker.Stop() + for range ticker.C { + c.CleanOnce() + } +} + +func (pc *Cleaner) CleanOnce() { + deadPoint := time.Now().Add(-pc.CleanupThreshold) + processes.Lock() + for _, mp := range processes.items { + mp.lastUsedLock.RLock() + if !mp.Alive && mp.lastUsed.Before(deadPoint) { + delete(processes.items, mp.Pid) + if err := os.Remove(mp.logfileName); err != nil { + if !os.IsNotExist(err) { + log.Printf("Couldn't remove process logs file, '%s'", mp.logfileName) + } + } + } + mp.lastUsedLock.RUnlock() + } + processes.Unlock() +} diff --git a/exec-agent/src/process/process_cleaner_test.go b/exec-agent/src/process/process_cleaner_test.go new file mode 100644 index 00000000000..42f8fc1d12a --- /dev/null +++ b/exec-agent/src/process/process_cleaner_test.go @@ -0,0 +1,60 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process_test + +import ( + "testing" + + "github.com/eclipse/che/exec-agent/process" + "time" +) + +func TestCleanWithZeroThreshold(t *testing.T) { + p := startAndWaitTestProcess(testCmd, t) + defer cleanupLogsDir() + + process.NewCleaner(0, 0).CleanOnce() + + _, err := process.Get(p.Pid) + if err == nil { + t.Fatal("Must not exist") + } + if _, ok := err.(*process.NoProcessError); !ok { + t.Fatal(err) + } +} + +func TestCleansOnlyUnusedProcesses(t *testing.T) { + p1 := startAndWaitTestProcess(testCmd, t) + p2 := startAndWaitTestProcess(testCmd, t) + + time.Sleep(500 * time.Millisecond) + + // use one of the processes, so it is used now + process.Get(p1.Pid) + + // cleanup immediately + (&process.Cleaner{CleanupPeriod: 0, CleanupThreshold: 500 * time.Millisecond}).CleanOnce() + + _, err1 := process.Get(p1.Pid) + _, err2 := process.Get(p2.Pid) + + // process 1 must be cleaned + if err1 != nil { + t.Fatalf("Expected process 2 to exist, but got an error: %s", err1.Error()) + } + + // process 2 must exist + if _, ok := err2.(*process.NoProcessError); !ok { + t.Fatal("Expected process 2 to be cleaned") + } +} diff --git a/exec-agent/src/process/process_test.go b/exec-agent/src/process/process_test.go new file mode 100644 index 00000000000..a535789922a --- /dev/null +++ b/exec-agent/src/process/process_test.go @@ -0,0 +1,255 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process_test + +import ( + "github.com/eclipse/che/exec-agent/process" + "github.com/eclipse/che/exec-agent/rpc" + "os" + "strings" + "testing" + "time" +) + +const ( + testCmd = "printf \"1\n2\n3\n4\n5\n6\n7\n8\n9\n10\"" +) + +func TestOneLineOutput(t *testing.T) { + defer cleanupLogsDir() + // create and start a process + p := startAndWaitTestProcess("echo test", t) + + logs, _ := process.ReadAllLogs(p.Pid) + + if len(logs) != 1 { + t.Fatalf("Expected logs size to be 1, but got %d", len(logs)) + } + + if logs[0].Text != "test" { + t.Fatalf("Expected to get 'test' output but got %s", logs[0].Text) + } +} + +func TestEmptyLinesOutput(t *testing.T) { + defer cleanupLogsDir() + p := startAndWaitTestProcess("printf \"\n\n\n\n\n\"", t) + + logs, _ := process.ReadAllLogs(p.Pid) + + if len(logs) != 5 { + t.Fatal("Expected logs to be 4 sized") + } + + for _, value := range logs { + if value.Text != "" { + t.Fatal("Expected all the logs to be empty files") + } + } +} + +func TestAddSubscriber(t *testing.T) { + process.LogsDir = TmpFile() + defer cleanupLogsDir() + + outputLines := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"} + + // create and start a process + pb := process.NewBuilder(). + CmdName("test"). + CmdType("test"). + CmdLine("printf \"" + strings.Join(outputLines, "\n") + "\"") + + // add a new subscriber + eventsChan := make(chan *rpc.Event) + pb.FirstSubscriber(process.Subscriber{ + Id: "test", + Mask: process.DefaultMask, + Channel: eventsChan, + }) + + // start a new process + if _, err := pb.Start(); err != nil { + t.Fatal(err) + } + + // read all the process output events + done := make(chan bool) + var received []string + go func() { + event := <-eventsChan + for event.EventType != process.DiedEventType { + if event.EventType == process.StdoutEventType { + out := event.Body.(*process.ProcessOutputEventBody) + received = append(received, out.Text) + } + event = <-eventsChan + } + done <- true + }() + + // wait until process is done + <-done + + if len(outputLines) != len(received) { + t.Fatalf("Expected the same size but got %d != %d", len(outputLines), len(received)) + } + + for idx, value := range outputLines { + if value != received[idx] { + t.Fatalf("Expected %s but got %s", value, received[idx]) + } + } +} + +func TestRestoreSubscriberForDeadProcess(t *testing.T) { + process.LogsDir = TmpFile() + defer cleanupLogsDir() + beforeStart := time.Now() + p := startAndWaitTestProcess("echo test", t) + + // Read all the data from channel + channel := make(chan *rpc.Event) + done := make(chan bool) + var received []*rpc.Event + go func() { + statusReceived := false + timeoutReached := false + for !statusReceived && !timeoutReached { + select { + case v := <-channel: + received = append(received, v) + if v.EventType == process.DiedEventType { + statusReceived = true + } + case <-time.After(time.Second): + timeoutReached = true + } + } + done <- true + }() + + process.RestoreSubscriber(p.Pid, process.Subscriber{ + "test", + process.DefaultMask, + channel, + }, beforeStart) + + <-done + + if len(received) != 2 { + t.Fatalf("Expected to recieve 2 events but got %d", len(received)) + } + e1Type := received[0].EventType + e1Text := received[0].Body.(*process.ProcessOutputEventBody).Text + if received[0].EventType != process.StdoutEventType || e1Text != "test" { + t.Fatalf("Expected to receieve output event with text 'test', but got '%s' event with text %s", + e1Type, + e1Text) + } + if received[1].EventType != process.DiedEventType { + t.Fatal("Expected to get 'process_died' event") + } +} + +func TestMachineProcessIsNotAliveAfterItIsDead(t *testing.T) { + p := startAndWaitTestProcess(testCmd, t) + defer cleanupLogsDir() + if p.Alive { + t.Fatal("Process should not be alive") + } +} + +func TestItIsNotPossibleToAddSubscriberToDeadProcess(t *testing.T) { + p := startAndWaitTestProcess(testCmd, t) + defer cleanupLogsDir() + if err := process.AddSubscriber(p.Pid, process.Subscriber{}); err == nil { + t.Fatal("Should not be able to add subscriber") + } +} + +func TestReadProcessLogs(t *testing.T) { + p := startAndWaitTestProcess(testCmd, t) + defer cleanupLogsDir() + logs, err := process.ReadLogs(p.Pid, time.Time{}, time.Now()) + if err != nil { + t.Fatal(err) + } + expected := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"} + + for idx := range expected { + if process.StdoutKind != logs[idx].Kind { + t.Fatalf("Expected log message kind to be '%s', while got '%s'", process.StdoutKind, logs[idx].Kind) + } + if expected[idx] != logs[idx].Text { + t.Fatalf("Expected log message to be '%s', but got '%s'", expected[idx], logs[idx].Text) + } + } +} + +func startAndWaitTestProcess(cmd string, t *testing.T) process.MachineProcess { + process.LogsDir = TmpFile() + events := make(chan *rpc.Event) + done := make(chan bool) + + // Create and start process + pb := process.NewBuilder(). + CmdName("test"). + CmdType("test"). + CmdLine(cmd). + FirstSubscriber(process.Subscriber{ + Id: "test", + Mask: process.DefaultMask, + Channel: events, + }) + + go func() { + statusReceived := false + timeoutReached := false + for !statusReceived && !timeoutReached { + select { + case event := <-events: + if event.EventType == process.DiedEventType { + statusReceived = true + } + case <-time.After(time.Second): + timeoutReached = true + } + } + done <- true + }() + + p, err := pb.Start() + if err != nil { + t.Fatal(err) + } + + // Wait until process is finished or timeout is reached + if ok := <-done; !ok { + t.Fatalf("Expected to receive %s process event", process.DiedEventType) + } + + // Check process state after it is finished + result, err := process.Get(p.Pid) + if err != nil { + t.Fatal(err) + } + return result +} + +func TmpFile() string { + return os.TempDir() + string(os.PathSeparator) + randomName(10) +} + +func cleanupLogsDir() { + os.RemoveAll(process.LogsDir) +} diff --git a/exec-agent/src/process/pumper.go b/exec-agent/src/process/pumper.go new file mode 100644 index 00000000000..86c01656ecd --- /dev/null +++ b/exec-agent/src/process/pumper.go @@ -0,0 +1,108 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "bufio" + "io" + "log" + "sync" + "time" +) + +type acceptLine func(line string) + +// LogsPumper client consumes a message read by pumper +type LogsConsumer interface { + + // called on each line pumped from process stdout + OnStdout(line string, time time.Time) + + // called on each line pumped from process stderr + OnStderr(line string, time time.Time) + + // called when pumping is finished either by normal return or by error + Close() +} + +// Pumps lines from the stdout and stderr +type LogsPumper struct { + stdout io.Reader + stderr io.Reader + clients []LogsConsumer + waitGroup sync.WaitGroup +} + +func NewPumper(stdout io.Reader, stderr io.Reader) *LogsPumper { + return &LogsPumper{ + stdout: stdout, + stderr: stderr, + } +} + +func (pumper *LogsPumper) AddConsumer(consumer LogsConsumer) { + pumper.clients = append(pumper.clients, consumer) +} + +// Start 'pumping' logs from the stdout and stderr +// The method execution is synchronous and waits for +// both stderr and stdout to complete closing all the clients after +func (pumper *LogsPumper) Pump() { + pumper.waitGroup.Add(2) + + // reading from stdout & stderr + go pump(pumper.stdout, pumper.notifyStdout, &pumper.waitGroup) + go pump(pumper.stderr, pumper.notifyStderr, &pumper.waitGroup) + + // cleanup after pumping is complete + pumper.waitGroup.Wait() + pumper.notifyClose() +} + +func pump(r io.Reader, lineConsumer acceptLine, wg *sync.WaitGroup) { + defer wg.Done() + br := bufio.NewReader(r) + for { + line, err := br.ReadBytes('\n') + + if err != nil { + if err != io.EOF { + log.Println("Error pumping: " + err.Error()) + } else if len(line) != 0 { + lineConsumer(string(line)) + } + return + } + + lineConsumer(string(line[:len(line)-1])) + } +} + +func (pumper *LogsPumper) notifyStdout(line string) { + t := time.Now() + for _, client := range pumper.clients { + client.OnStdout(line, t) + } +} + +func (pumper *LogsPumper) notifyStderr(line string) { + t := time.Now() + for _, client := range pumper.clients { + client.OnStderr(line, t) + } +} + +func (pumper *LogsPumper) notifyClose() { + for _, client := range pumper.clients { + client.Close() + } +} diff --git a/exec-agent/src/process/rest_service.go b/exec-agent/src/process/rest_service.go new file mode 100644 index 00000000000..c2c4b497a06 --- /dev/null +++ b/exec-agent/src/process/rest_service.go @@ -0,0 +1,194 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "errors" + "fmt" + "github.com/eclipse/che/exec-agent/rest" + "github.com/eclipse/che/exec-agent/rest/restutil" + "github.com/eclipse/che/exec-agent/rpc" + "io" + "math" + "net/http" + "strconv" + "strings" + "time" +) + +var HttpRoutes = rest.RoutesGroup{ + "Process Routes", + []rest.Route{ + { + "POST", + "Start Process", + "/process", + startProcessHF, + }, + { + "GET", + "Get Process", + "/process/:pid", + getProcessHF, + }, + { + "DELETE", + "Kill Process", + "/process/:pid", + killProcessHF, + }, + { + "GET", + "Get Process Logs", + "/process/:pid/logs", + getProcessLogsHF, + }, + { + "GET", + "Get Processes", + "/process", + getProcessesHF, + }, + }, +} + +func startProcessHF(w http.ResponseWriter, r *http.Request, p rest.Params) error { + command := Command{} + if err := restutil.ReadJson(r, &command); err != nil { + return err + } + if err := checkCommand(&command); err != nil { + return rest.BadRequest(err) + } + + // If channel is provided then check whether it is ready to be + // first process subscriber and use it if it is + var subscriber *Subscriber + channelId := r.URL.Query().Get("channel") + if channelId != "" { + channel, ok := rpc.GetChannel(channelId) + if !ok { + m := fmt.Sprintf("Channel with id '%s' doesn't exist. Process won't be started", channelId) + return rest.NotFound(errors.New(m)) + } + subscriber = &Subscriber{ + Id: channelId, + Mask: parseTypes(r.URL.Query().Get("types")), + Channel: channel.Events, + } + } + + pb := NewBuilder().Cmd(command) + + if subscriber != nil { + pb.FirstSubscriber(*subscriber) + } + + process, err := pb.Start() + if err != nil { + return err + } + return restutil.WriteJson(w, process) +} + +func getProcessHF(w http.ResponseWriter, r *http.Request, p rest.Params) error { + pid, err := parsePid(p.Get("pid")) + if err != nil { + return rest.BadRequest(err) + } + + process, err := Get(pid) + if err != nil { + return asHttpError(err) + } + return restutil.WriteJson(w, process) +} + +func killProcessHF(w http.ResponseWriter, r *http.Request, p rest.Params) error { + pid, err := parsePid(p.Get("pid")) + if err != nil { + return rest.BadRequest(err) + } + if err := Kill(pid); err != nil { + return asHttpError(err) + } + return nil +} + +func getProcessLogsHF(w http.ResponseWriter, r *http.Request, p rest.Params) error { + pid, err := parsePid(p.Get("pid")) + if err != nil { + return rest.BadRequest(err) + } + + // Parse 'from', if 'from' is not specified then read all the logs from the start + // if 'from' format is different from the DATE_TIME_FORMAT then return 400 + from, err := parseTime(r.URL.Query().Get("from"), time.Time{}) + if err != nil { + return rest.BadRequest(errors.New("Bad format of 'from', " + err.Error())) + } + + // Parse 'till', if 'till' is not specified then 'now' is used for it + // if 'till' format is different from the DATE_TIME_FORMAT then return 400 + till, err := parseTime(r.URL.Query().Get("till"), time.Now()) + if err != nil { + return rest.BadRequest(errors.New("Bad format of 'till', " + err.Error())) + } + + logs, err := ReadLogs(pid, from, till) + if err != nil { + return asHttpError(err) + } + + // limit logs from the latest to the earliest + // limit - how many the latest logs will be present + // skip - how many log lines should be skipped from the end + limit := restutil.IntQueryParam(r, "limit", DefaultLogsPerPageLimit) + skip := restutil.IntQueryParam(r, "skip", 0) + if limit < 1 { + return rest.BadRequest(errors.New("Required 'limit' to be > 0")) + } + if skip < 0 { + return rest.BadRequest(errors.New("Required 'skip' to be >= 0")) + } + len := len(logs) + fromIdx := int(math.Max(float64(len-limit-skip), 0)) + toIdx := len - int(math.Min(float64(skip), float64(len))) + + // Respond with an appropriate logs format, default json + format := r.URL.Query().Get("format") + switch strings.ToLower(format) { + case "text": + for _, item := range logs[fromIdx:toIdx] { + line := fmt.Sprintf("[%s] %s \t %s\n", item.Kind, item.Time.Format(DateTimeFormat), item.Text) + io.WriteString(w, line) + } + default: + return restutil.WriteJson(w, logs[fromIdx:toIdx]) + } + return nil +} + +func getProcessesHF(w http.ResponseWriter, r *http.Request, _ rest.Params) error { + all, err := strconv.ParseBool(r.URL.Query().Get("all")) + if err != nil { + all = false + } + return restutil.WriteJson(w, GetProcesses(all)) +} + +func asHttpError(err error) error { + if npErr, ok := err.(*NoProcessError); ok { + return rest.NotFound(npErr.error) + } + return err +} diff --git a/exec-agent/src/process/ws_service.go b/exec-agent/src/process/ws_service.go new file mode 100644 index 00000000000..a75ea8bd1d8 --- /dev/null +++ b/exec-agent/src/process/ws_service.go @@ -0,0 +1,348 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package process + +import ( + "encoding/json" + "errors" + "github.com/eclipse/che/exec-agent/rpc" + "math" + "time" +) + +const ( + StartMethod = "process.start" + KillMethod = "process.kill" + SubscribeMethod = "process.subscribe" + UnsubscribeMethod = "process.unsubscribe" + UpdateSubscriberMethod = "process.updateSubscriber" + GetLogsMethod = "process.getLogs" + GetProcessMethod = "process.getProcess" + GetProcessesMethod = "process.getProcesses" + + NoSuchProcessErrorCode = -32000 + ProcessNotAliveErrorCode = -32001 +) + +var RpcRoutes = rpc.RoutesGroup{ + "Process Routes", + []rpc.Route{ + { + StartMethod, + func(body []byte) (interface{}, error) { + b := StartParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + startProcessReqHF, + }, + { + KillMethod, + func(body []byte) (interface{}, error) { + b := KillParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + killProcessReqHF, + }, + { + SubscribeMethod, + func(body []byte) (interface{}, error) { + b := SubscribeParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + subscribeReqHF, + }, + { + UnsubscribeMethod, + func(body []byte) (interface{}, error) { + b := UnsubscribeParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + unsubscribeReqHF, + }, + { + UpdateSubscriberMethod, + func(body []byte) (interface{}, error) { + b := UpdateSubscriberParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + updateSubscriberReqHF, + }, + { + GetLogsMethod, + func(body []byte) (interface{}, error) { + b := GetLogsParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + getProcessLogsReqHF, + }, + { + GetProcessMethod, + func(body []byte) (interface{}, error) { + b := GetProcessParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + getProcessReqHF, + }, + { + GetProcessesMethod, + func(body []byte) (interface{}, error) { + b := GetProcessesParams{} + err := json.Unmarshal(body, &b) + return b, err + }, + getProcessesReqHF, + }, + }, +} + +type ProcessResult struct { + Pid uint64 `json:"pid"` + Text string `json:"text"` +} + +//-- process start +type StartParams struct { + Name string `json:"name"` + CommandLine string `json:"commandLine"` + Type string `json:"type"` + EventTypes string `json:"eventTypes"` +} + +func startProcessReqHF(params interface{}, t *rpc.Transmitter) error { + startParams := params.(StartParams) + command := Command{ + Name: startParams.Name, + CommandLine: startParams.CommandLine, + Type: startParams.Type, + } + if err := checkCommand(&command); err != nil { + return rpc.NewArgsError(err) + } + + _, err := NewBuilder(). + Cmd(command). + FirstSubscriber(Subscriber{ + Id: t.Channel.Id, + Mask: parseTypes(startParams.EventTypes), + Channel: t.Channel.Events, + }). + BeforeEventsHook(func(process MachineProcess) { + t.Send(process) + }). + Start() + return err +} + +//-- process kill +type KillParams struct { + Pid uint64 `json:"pid"` + NativePid uint64 `json:"nativePid"` +} + +func killProcessReqHF(params interface{}, t *rpc.Transmitter) error { + killParams := params.(KillParams) + if err := Kill(killParams.Pid); err != nil { + return asRpcError(err) + } + t.Send(&ProcessResult{ + Pid: killParams.Pid, + Text: "Successfully killed", + }) + return nil +} + +//-- process subscribe +type SubscribeResult struct { + Pid uint64 `json:"pid"` + EventTypes string `json:"eventTypes"` + Text string `json:"text"` +} + +type SubscribeParams struct { + Pid uint64 `json:"pid"` + EventTypes string `json:"eventTypes"` + After string `json:"after"` +} + +func subscribeReqHF(params interface{}, t *rpc.Transmitter) error { + subscribeParams := params.(SubscribeParams) + + mask := maskFromTypes(subscribeParams.EventTypes) + if mask == 0 { + return rpc.NewArgsError(errors.New("Required at least 1 valid event type")) + } + + subscriber := Subscriber{ + Id: t.Channel.Id, + Mask: mask, + Channel: t.Channel.Events, + } + // Check whether subscriber should see previous logs or not + if subscribeParams.After == "" { + if err := AddSubscriber(subscribeParams.Pid, subscriber); err != nil { + return asRpcError(err) + } + } else { + after, err := time.Parse(DateTimeFormat, subscribeParams.After) + if err != nil { + return rpc.NewArgsError(errors.New("Bad format of 'after', " + err.Error())) + } + if err := RestoreSubscriber(subscribeParams.Pid, subscriber, after); err != nil { + return err + } + } + t.Send(&SubscribeResult{ + Pid: subscribeParams.Pid, + EventTypes: subscribeParams.EventTypes, + Text: "Successfully subscribed", + }) + return nil +} + +//-- process unsubscribe +type UnsubscribeParams struct { + Pid uint64 `json:"pid"` +} + +func unsubscribeReqHF(params interface{}, t *rpc.Transmitter) error { + unsubscribeParams := params.(UnsubscribeParams) + if err := RemoveSubscriber(unsubscribeParams.Pid, t.Channel.Id); err != nil { + return asRpcError(err) + } + t.Send(&ProcessResult{ + Pid: unsubscribeParams.Pid, + Text: "Successfully unsubscribed", + }) + return nil +} + +//-- process update subscriber +type UpdateSubscriberParams struct { + Pid uint64 `json:"pid"` + EventTypes string `json:"eventTypes"` +} + +func updateSubscriberReqHF(params interface{}, t *rpc.Transmitter) error { + updateParams := params.(UpdateSubscriberParams) + if updateParams.EventTypes == "" { + return rpc.NewArgsError(errors.New("'eventTypes' required for subscriber update")) + } + if err := UpdateSubscriber(updateParams.Pid, t.Channel.Id, maskFromTypes(updateParams.EventTypes)); err != nil { + return asRpcError(err) + } + t.Send(&SubscribeResult{ + Pid: updateParams.Pid, + EventTypes: updateParams.EventTypes, + Text: "Subscriber successfully updated", + }) + return nil +} + +//-- process get logs +type GetLogsParams struct { + Pid uint64 `json:"pid"` + From string `json:"from"` + Till string `json:"till"` + Limit int `json:"limit"` + Skip int `json:"skip"` +} + +func getProcessLogsReqHF(params interface{}, t *rpc.Transmitter) error { + getLogsParams := params.(GetLogsParams) + + if getLogsParams.Skip < 0 { + getLogsParams.Skip = 0 + } + if getLogsParams.Limit < 0 { + getLogsParams.Limit = 0 + } + + from, err := parseTime(getLogsParams.From, time.Time{}) + if err != nil { + return rpc.NewArgsError(errors.New("Bad format of 'from', " + err.Error())) + } + + till, err := parseTime(getLogsParams.Till, time.Now()) + if err != nil { + return rpc.NewArgsError(errors.New("Bad format of 'till', " + err.Error())) + } + + logs, err := ReadLogs(getLogsParams.Pid, from, till) + if err != nil { + return asRpcError(err) + } + + limit := DefaultLogsPerPageLimit + if getLogsParams.Limit != 0 { + if limit < 1 { + return rpc.NewArgsError(errors.New("Required 'limit' to be > 0")) + } + limit = getLogsParams.Limit + } + + skip := 0 + if getLogsParams.Skip != 0 { + if skip < 0 { + return rpc.NewArgsError(errors.New("Required 'skip' to be >= 0")) + } + skip = getLogsParams.Skip + } + + logsLen := len(logs) + fromIdx := int(math.Max(float64(logsLen-limit-skip), 0)) + toIdx := logsLen - int(math.Min(float64(skip), float64(logsLen))) + + t.Send(logs[fromIdx:toIdx]) + return nil +} + +//-- get process +type GetProcessParams struct { + Pid uint64 `json:"pid"` +} + +func getProcessReqHF(body interface{}, t *rpc.Transmitter) error { + params := body.(GetProcessParams) + p, err := Get(params.Pid) + if err != nil { + return asRpcError(err) + } + t.Send(p) + return nil +} + +//-- get processes +type GetProcessesParams struct { + All bool `json:"all"` +} + +func getProcessesReqHF(body interface{}, t *rpc.Transmitter) error { + params := body.(GetProcessesParams) + t.Send(GetProcesses(params.All)) + return nil +} + +func asRpcError(err error) error { + if npErr, ok := err.(*NoProcessError); ok { + return rpc.NewError(npErr.error, NoSuchProcessErrorCode) + } else if naErr, ok := err.(*NotAliveError); ok { + return rpc.NewError(naErr.error, ProcessNotAliveErrorCode) + } + return err +} diff --git a/exec-agent/src/rest/errors.go b/exec-agent/src/rest/errors.go new file mode 100644 index 00000000000..096771b392b --- /dev/null +++ b/exec-agent/src/rest/errors.go @@ -0,0 +1,41 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package rest + +import ( + "net/http" +) + +type ApiError struct { + error + Code int +} + +func BadRequest(err error) error { + return ApiError{err, http.StatusBadRequest} +} + +func NotFound(err error) error { + return ApiError{err, http.StatusNotFound} +} + +func Conflict(err error) error { + return ApiError{err, http.StatusConflict} +} + +func Forbidden(err error) error { + return ApiError{err, http.StatusForbidden} +} + +func Unauthorized(err error) error { + return ApiError{err, http.StatusUnauthorized} +} diff --git a/exec-agent/src/rest/restutil/util.go b/exec-agent/src/rest/restutil/util.go new file mode 100644 index 00000000000..10e667d234c --- /dev/null +++ b/exec-agent/src/rest/restutil/util.go @@ -0,0 +1,45 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package restutil + +import ( + "encoding/json" + "net/http" + "strconv" +) + +// Writes body as json to the response writer +func WriteJson(w http.ResponseWriter, body interface{}) error { + w.Header().Set("Content-Type", "application/json") + return json.NewEncoder(w).Encode(body) +} + +// Reads json body from the request +func ReadJson(r *http.Request, v interface{}) error { + return json.NewDecoder(r.Body).Decode(v) +} + +func IntQueryParam(r *http.Request, name string, defaultValue int) int { + qp := r.URL.Query().Get(name) + if qp == "" { + return defaultValue + } else { + v, err := strconv.Atoi(qp) + if err != nil { + return defaultValue + } + if v < 0 { + return defaultValue + } + return v + } +} diff --git a/exec-agent/src/rest/route.go b/exec-agent/src/rest/route.go new file mode 100644 index 00000000000..2531acd0e1e --- /dev/null +++ b/exec-agent/src/rest/route.go @@ -0,0 +1,80 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package rest + +import ( + "fmt" + "net/http" + "strings" +) + +const ( + maxNameLen = 40 + maxMethodLen = len("DELETE") +) + +// Handler for http routes +// vars variable contain only path parameters if any specified for given route +type HttpRouteHandlerFunc func(w http.ResponseWriter, r *http.Request, params Params) error + +// An interface for getting mapped path parameters by their names +type Params interface { + + // Gets path parameter by it's name e.g. + // for url template `/process/:id` and actual value `/process/123` + // this method will return string '123' + Get(name string) string +} + +// Describes route for http requests +type Route struct { + + // Http method e.g. 'GET' + Method string + + // The name of the http route, used in logs + // this name is unique for all the application http routes + // example: 'StartProcess' + Name string + + // The path of the http route which this route is mapped to + // example: '/process' + Path string + + // The function used for handling http request + HandleFunc HttpRouteHandlerFunc +} + +// Named group of http routes, those groups +// should be defined by separate apis, and then combined together +type RoutesGroup struct { + + // The name of this group e.g.: 'ProcessRoutes' + Name string + + // The http routes of this group + Items []Route +} + +func (r *Route) String() string { + name := r.Name + " " + strings.Repeat(".", maxNameLen-len(r.Name)) + method := r.Method + strings.Repeat(" ", maxMethodLen-len(r.Method)) + return fmt.Sprintf("%s %s %s", name, method, r.Path) +} + +func WriteError(w http.ResponseWriter, err error) { + if apiErr, ok := err.(ApiError); ok { + http.Error(w, apiErr.Error(), apiErr.Code) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} diff --git a/exec-agent/src/rpc/channels.go b/exec-agent/src/rpc/channels.go new file mode 100644 index 00000000000..9e73a2c05ec --- /dev/null +++ b/exec-agent/src/rpc/channels.go @@ -0,0 +1,334 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package rpc + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/eclipse/che-lib/websocket" + "github.com/eclipse/che/exec-agent/rest" +) + +const ( + ConnectedEventType = "connected" +) + +var ( + upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { + return true + }, + } + + prevChanId uint64 = 0 + + channels = channelsMap{items: make(map[string]Channel)} + + HttpRoutes = rest.RoutesGroup{ + "Channel Routes", + []rest.Route{ + { + "GET", + "Connect to Exec-Agent(webscoket)", + "/connect", + registerChannel, + }, + }, + } + + messageHandler = jsonrpc2_0MessageHandler{} +) + +// Published when websocket connection is established +// and channel is ready for interaction +type ChannelConnected struct { + Timed + ChannelId string `json:"channel"` + Text string `json:"text"` +} + +// Describes channel which is websocket connection +// with additional properties required by the application +type Channel struct { + // Unique channel identifier + Id string `json:"id"` + + // When the connection was established + Connected time.Time `json:"connected"` + + // the uri of the request that established this connection + RequestURI string `json:"-"` + + // Go channel for sending events to the websocket. + // All the events are encoded to the json messages and + // send to websocket connection defined by this channel. + Events chan *Event + + // Everything passed to this channel will be encoded + // to json and send to the client. + output chan interface{} + + // If any value is send to this channel then + // physical connection associated with it along with + // output channel will be immediately closed. + drop chan bool + + // Websocket connection + conn *websocket.Conn +} + +// A struct for reading raw websocket messages +type WsMessage struct { + err error + bytes []byte +} + +// Handles raw messages received from websocket channel +type MessageHandler interface { + // handles a message in implementation specific way + handle(message *WsMessage, channel Channel) +} + +// Defines lockable map for managing channels +type channelsMap struct { + sync.RWMutex + items map[string]Channel +} + +// Gets channel by the channel id, if there is no such channel +// then returned 'ok' is false. +func GetChannel(chanId string) (Channel, bool) { + channels.RLock() + defer channels.RUnlock() + item, ok := channels.items[chanId] + return item, ok +} + +// Returns all the currently registered channels. +func GetChannels() []Channel { + channels.RLock() + defer channels.RUnlock() + all := make([]Channel, len(channels.items)) + idx := 0 + for _, v := range channels.items { + all[idx] = v + idx++ + } + return all +} + +// Drops the channel with the given id. +func DropChannel(id string) { + if c, ok := GetChannel(id); ok { + c.drop <- true + } +} + +// Saves the channel with the given identifier and returns true. +// If the channel with the given identifier already exists then false is returned +// and the channel is not saved. +func saveChannel(channel Channel) bool { + channels.Lock() + defer channels.Unlock() + _, ok := channels.items[channel.Id] + if ok { + return false + } + channels.items[channel.Id] = channel + return true +} + +// Removes channel +func removeChannel(channel Channel) { + channels.Lock() + defer channels.Unlock() + delete(channels.items, channel.Id) +} + +func registerChannel(w http.ResponseWriter, r *http.Request, _ rest.Params) error { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Println("Couldn't establish websocket connection " + err.Error()) + return nil + } + + channel := Channel{ + Id: "channel-" + strconv.Itoa(int(atomic.AddUint64(&prevChanId, 1))), + Connected: time.Now(), + RequestURI: r.RequestURI, + Events: make(chan *Event), + output: make(chan interface{}), + drop: make(chan bool), + conn: conn, + } + saveChannel(channel) + + log.Printf("A new channel with id '%s' successfully opened", channel.Id) + + go transferAsJson(conn, channel.output) + go redirectEventsToOutput(channel) + go handleMessages(readMessages(conn), channel) + + // Say hello to the client + channel.Events <- NewEvent(ConnectedEventType, &ChannelConnected{ + Timed: Timed{Time: channel.Connected}, + ChannelId: channel.Id, + Text: "Hello!", + }) + return nil +} + +// Handles all the messages from the given channel +// until an error occurs or a drop signal is sent. +// Clears all the associated resources. +func handleMessages(messageChan chan *WsMessage, channel Channel) { + for { + select { + case message := <-messageChan: + if message.err == nil { + messageHandler.handle(message, channel) + } else { + closeErr, ok := message.err.(*websocket.CloseError) + if !ok || !isNormallyClosed(closeErr.Code) { + log.Println("Error reading message, " + message.err.Error()) + } + closeChannel(channel) + return + } + case <-channel.drop: + closeChannel(channel) + return + } + } +} + +// Closes all associated go channels(events, output, drop) +// and physical websocket connection. +func closeChannel(channel Channel) { + close(channel.Events) + close(channel.output) + close(channel.drop) + if err := channel.conn.Close(); err != nil { + log.Println("Error closing connection, " + err.Error()) + } + removeChannel(channel) + log.Printf("Channel with id '%s' successfully closed", channel.Id) +} + +// Reads the message from the websocket connection until error is received, +// returns the channel which should be used for reading such messages. +func readMessages(conn *websocket.Conn) chan *WsMessage { + messagesChan := make(chan *WsMessage) + go func() { + for { + _, bytes, err := conn.ReadMessage() + messagesChan <- &WsMessage{err: err, bytes: bytes} + if err != nil { + close(messagesChan) + break + } + } + }() + return messagesChan +} + +func redirectEventsToOutput(channel Channel) { + for event := range channel.Events { + channel.output <- event + } +} + +// transfers data from channel to physical connection, +// tries to transform data to json. +func transferAsJson(conn *websocket.Conn, c chan interface{}) { + for message := range c { + err := conn.WriteJSON(message) + if err != nil { + log.Printf("Couldn't write message to the channel. Message: %T, %v", message, message) + } + } +} + +// handles messages as jsonrpc as described by package doc +type jsonrpc2_0MessageHandler struct{} + +func (h *jsonrpc2_0MessageHandler) handle(message *WsMessage, channel Channel) { + req := &Request{} + + // try to unmarshal the request + if err := json.Unmarshal(message.bytes, req); err != nil { + // Respond parse error according to specification + channel.output <- &Response{ + Version: "2.0", + Error: &Error{ + Code: ParseErrorCode, + Message: "Invalid json object", + }, + } + log.Printf("Error decoding request '%s', Error: %s \n", string(message.bytes), err.Error()) + return + } + + // ensure provided version is supported + if req.Version != "" && strings.Trim(req.Version, " ") != "2.0" { + channel.output <- &Response{ + Version: "2.0", + Error: &Error{ + Code: InvalidRequestErrorCode, + Message: "'2.0' is the only supported version, use it or omit version at all", + }, + } + return + } + + transmitter := &Transmitter{Channel: channel, id: req.Id} + + opRoute, ok := routes.get(req.Method) + if !ok { + m := fmt.Sprintf("No route for the operation '%s'", req.Method) + transmitter.SendError(NewError(errors.New(m), MethodNotFoundErrorCode)) + return + } + + decodedBody, err := opRoute.DecoderFunc(req.RawParams) + if err != nil { + m := fmt.Sprintf("Error decoding body for the operation '%s'. Error: '%s'", req.Method, err.Error()) + transmitter.SendError(NewError(errors.New(m), InvalidRequestErrorCode)) + return + } + + if err := opRoute.HandlerFunc(decodedBody, transmitter); err != nil { + opError, ok := err.(Error) + if ok { + transmitter.SendError(opError) + } else { + transmitter.SendError(NewError(err, InternalErrorCode)) + } + } +} + +func isNormallyClosed(code int) bool { + return code == websocket.CloseGoingAway || + code == websocket.CloseNormalClosure || + code == websocket.CloseNoStatusReceived +} diff --git a/exec-agent/src/rpc/model.go b/exec-agent/src/rpc/model.go new file mode 100644 index 00000000000..f9e461f7bef --- /dev/null +++ b/exec-agent/src/rpc/model.go @@ -0,0 +1,173 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +// Provides a lightweight implementation of jsonrpc2.0 protocol. +// The original jsonrpc2.0 specification - http://www.jsonrpc.org/specification +// +// The implementations does not fully implement the protocol +// and introduces a few modifications to its terminology in +// term of exec-agent transport needs. +// +// From the specification: +// The Client is defined as the origin of Request objects and the handler of Response objects. +// The Server is defined as the origin of Response objects and the handler of Request objects. +// +// Exec-agent serves as both, server and client as it receives +// Responses and sends Notifications in the same time. +// +// Request. +// It's a message from the physical websocket connection client to the exec-agent server. +// Request(in it's origin form) is considered to be unidirectional. +// WS Client =---> WS Server. +// +// Response. +// It's a message from the the exec-agent server to a websocket client, +// indicates the result of the operation execution requested by certain request. +// Response doesn't exist without request. The response is considered to be unidirectional. +// WS Client <---= WS Server +// +// Event. +// Is a message from the exec-agent server to a websocket client, the analogue +// from the specification is Notification, which is defined as a request +// which doesn't need any response, that's also true for events. +// Events may happen periodically and don't need to be indicated by request. +// WS Client <---X WS Server +package rpc + +import ( + "encoding/json" + "time" +) + +const ( + + // Invalid JSON was received by the server. + ParseErrorCode = -32700 + + // Request object is not valid, fails + // when route decoder can't decode params. + InvalidRequestErrorCode = -32600 + + // There is no route for such method. + MethodNotFoundErrorCode = -32601 + + // When handler parameters are considered as not valid + // this error type should be returned directly from the HandlerFunc + InvalidParamsErrorCode = -32602 + + // When error returned from the Route HandlerFunc is different from Error type + InternalErrorCode = -32603 + + // -32000 to -32099 Reserved for implementation-defined server-errors. +) + +// Describes named operation which is called +// on the websocket client's side and performed +// on the servers's side, if appropriate Route exists. +type Request struct { + + // Version of this request e.g. '2.0'. + Version string `json:"jsonrpc"` + + // The method name which should be proceeded by this call + // usually dot separated resource and action e.g. 'process.start'. + Method string `json:"method"` + + // The unique identifier of this operation request. + // If a client needs to identify the result of the operation execution, + // the id should be passed by the client, then it is guaranteed + // that the client will receive the result frame with the same id. + // The uniqueness of the identifier must be controlled by the client, + // if client doesn't specify the identifier in the operation call, + // the response won't contain the identifier as well. + // + // It is preferable to specify identifier for those calls which may + // either validate data, or produce such information which can't be + // identified by itself. + Id interface{} `json:"id"` + + // Request data, parameters which are needed for operation execution. + RawParams json.RawMessage `json:"params"` +} + +// A message from the server to the client, +// which represents the result of the certain operation execution. +// The result is sent to the client only once per operation. +type Response struct { + + // Version of this response e.g. '2.0'. + Version string `json:"jsonrpc"` + + // The operation call identifier, will be set only + // if the operation contains it. See 'rpc.Request.Id' + Id interface{} `json:"id"` + + // The actual result data, the operation execution result. + Result interface{} `json:"result,omitempty"` + + // Body and Error are mutual exclusive. + // Present only if the operation execution fails due to an error. + Error *Error `json:"error,omitempty"` +} + +// A message from the server to the client, +// which may notify client about any activity that the client is interested in. +// The difference from the 'rpc.Response' is that the event may happen periodically, +// before or even after some operation calls, while the 'rpc.Response' is more like +// result of the operation call execution, which is sent to the client immediately +// after the operation execution is done. +type Event struct { + + // Version of this notification e.g. '2.0' + Version string `json:"jsonrpc"` + + // A type of this operation event, must be always set. + // The type must be generally unique. + EventType string `json:"method"` + + // Event related data. + Body interface{} `json:"params"` +} + +// May be returned by any of route HandlerFunc. +type Error struct { + error `json:"-"` + + // An error code + Code int `json:"code"` + + // A short description of the occurred error. + Message string `json:"message"` +} + +type Timed struct { + Time time.Time `json:"time"` +} + +func NewEvent(eType string, body interface{}) *Event { + return &Event{ + Version: "2.0", + EventType: eType, + Body: body, + } +} + +func NewArgsError(err error) Error { + return NewError(err, InvalidParamsErrorCode) +} + +func NewError(err error, code int) Error { + return Error{ + error: err, + Code: code, + Message: err.Error(), + } +} diff --git a/exec-agent/src/rpc/route.go b/exec-agent/src/rpc/route.go new file mode 100644 index 00000000000..f1653cba6f4 --- /dev/null +++ b/exec-agent/src/rpc/route.go @@ -0,0 +1,88 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package rpc + +import ( + "log" + "sync" +) + +var ( + routes = &routesMap{items: make(map[string]Route)} +) + +// Describes route for rpc requests +type Route struct { + + // The operation name like defined by Request.Method + Method string + + // The decoder used for decoding raw request parameters + // into the certain object. If decoding is okay, then + // decoded value will be passed to the HandlerFunc + // of this request route, so it is up to the route + // - to define type safe couple of DecoderFunc & HandlerFunc. + DecoderFunc func(body []byte) (interface{}, error) + + // Defines handler for decoded request parameters. + // If handler function can't perform the operation then + // handler function should either return an error, or + // send it directly within transmitter#SendError func. + // Params is a value returned from the DecoderFunc. + // If an error is returned from this function and the type + // of the error is different from rpc.Error, it will be + // published as internal rpc error(-32603). + HandlerFunc func(params interface{}, t *Transmitter) error +} + +// Named group of rpc routes +type RoutesGroup struct { + // The name of this group e.g.: 'ProcessRpcRoutes' + Name string + + // Rpc routes of this group + Items []Route +} + +// Defines lockable map for storing operation routes +type routesMap struct { + sync.RWMutex + items map[string]Route +} + +// Gets route by the operation name +func (routes *routesMap) get(method string) (Route, bool) { + routes.RLock() + defer routes.RUnlock() + item, ok := routes.items[method] + return item, ok +} + +// Returns true if route is added and false if route for such method +// already present(won't override it). +func (or *routesMap) add(r Route) bool { + routes.Lock() + defer routes.Unlock() + _, ok := routes.items[r.Method] + if ok { + return false + } + routes.items[r.Method] = r + return true +} + +// Adds a new route, panics if such route already exists. +func RegisterRoute(route Route) { + if !routes.add(route) { + log.Fatalf("Couldn't register a new route, route for the operation '%s' already exists", route.Method) + } +} diff --git a/exec-agent/src/rpc/transmitter.go b/exec-agent/src/rpc/transmitter.go new file mode 100644 index 00000000000..72a2349352b --- /dev/null +++ b/exec-agent/src/rpc/transmitter.go @@ -0,0 +1,41 @@ +// +// Copyright (c) 2012-2016 Codenvy, S.A. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// Codenvy, S.A. - initial API and implementation +// + +package rpc + +// Transmitter is used for sending +// results of the operation executions to the channel. +type Transmitter struct { + + // The id of the request behind this transmitter. + id interface{} + + // The channel to which the message will be send. + Channel Channel +} + +// Wraps the given message with 'rpc.Result' and sends it to the client. +func (t *Transmitter) Send(message interface{}) { + t.Channel.output <- &Response{ + Version: "2.0", + Id: t.id, + Result: message, + } +} + +// Wraps the given error with 'rpc.Result' and sends it to the client. +func (t *Transmitter) SendError(err Error) { + t.Channel.output <- &Response{ + Version: "2.0", + Id: t.id, + Error: &err, + } +} diff --git a/exec-agent/src/static/term.js b/exec-agent/src/static/term.js new file mode 100644 index 00000000000..9d80e4bfc30 --- /dev/null +++ b/exec-agent/src/static/term.js @@ -0,0 +1,5793 @@ +/** + * term.js - an xterm emulator + * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) + * https://github.com/chjj/term.js + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Originally forked from (with the author's permission): + * Fabrice Bellard's javascript vt100 for jslinux: + * http://bellard.org/jslinux/ + * Copyright (c) 2011 Fabrice Bellard + * The original design remains. The terminal itself + * has been extended to include xterm CSI codes, among + * other features. + */ + +;(function() { + +/** + * Terminal Emulation References: + * http://vt100.net/ + * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt + * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + * http://invisible-island.net/vttest/ + * http://www.inwap.com/pdp10/ansicode.txt + * http://linux.die.net/man/4/console_codes + * http://linux.die.net/man/7/urxvt + */ + +'use strict'; + +/** + * Shared + */ + +var window = this + , document = this.document; + +/** + * EventEmitter + */ + +function EventEmitter() { + this._events = this._events || {}; +} + +EventEmitter.prototype.addListener = function(type, listener) { + this._events[type] = this._events[type] || []; + this._events[type].push(listener); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.removeListener = function(type, listener) { + if (!this._events[type]) return; + + var obj = this._events[type] + , i = obj.length; + + while (i--) { + if (obj[i] === listener || obj[i].listener === listener) { + obj.splice(i, 1); + return; + } + } +}; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = function(type) { + if (this._events[type]) delete this._events[type]; +}; + +EventEmitter.prototype.once = function(type, listener) { + function on() { + var args = Array.prototype.slice.call(arguments); + this.removeListener(type, on); + return listener.apply(this, args); + } + on.listener = listener; + return this.on(type, on); +}; + +EventEmitter.prototype.emit = function(type) { + if (!this._events[type]) return; + + var args = Array.prototype.slice.call(arguments, 1) + , obj = this._events[type] + , l = obj.length + , i = 0; + + for (; i < l; i++) { + obj[i].apply(this, args); + } +}; + +EventEmitter.prototype.listeners = function(type) { + return this._events[type] = this._events[type] || []; +}; + +/** + * States + */ + +var normal = 0 + , escaped = 1 + , csi = 2 + , osc = 3 + , charset = 4 + , dcs = 5 + , ignore = 6; + +/** + * Terminal + */ + +function Terminal(options) { + var self = this; + + if (!(this instanceof Terminal)) { + return new Terminal(arguments[0], arguments[1], arguments[2]); + } + + EventEmitter.call(this); + + if (typeof options === 'number') { + options = { + cols: arguments[0], + rows: arguments[1], + handler: arguments[2] + }; + } + + options = options || {}; + + each(keys(Terminal.defaults), function(key) { + if (options[key] == null) { + options[key] = Terminal.options[key]; + // Legacy: + if (Terminal[key] !== Terminal.defaults[key]) { + options[key] = Terminal[key]; + } + } + self[key] = options[key]; + }); + + if (options.colors.length === 8) { + options.colors = options.colors.concat(Terminal._colors.slice(8)); + } else if (options.colors.length === 16) { + options.colors = options.colors.concat(Terminal._colors.slice(16)); + } else if (options.colors.length === 10) { + options.colors = options.colors.slice(0, -2).concat( + Terminal._colors.slice(8, -2), options.colors.slice(-2)); + } else if (options.colors.length === 18) { + options.colors = options.colors.slice(0, -2).concat( + Terminal._colors.slice(16, -2), options.colors.slice(-2)); + } + this.colors = options.colors; + + this.options = options; + + // this.context = options.context || window; + // this.document = options.document || document; + this.parent = options.body || options.parent + || (document ? document.getElementsByTagName('body')[0] : null); + + this.cols = options.cols || options.geometry[0]; + this.rows = options.rows || options.geometry[1]; + + if (options.handler) { + this.on('data', options.handler); + } + + this.ybase = 0; + this.ydisp = 0; + this.x = 0; + this.y = 0; + this.cursorState = 0; + this.cursorHidden = false; + this.convertEol; + this.state = 0; + this.queue = ''; + this.scrollTop = 0; + this.scrollBottom = this.rows - 1; + + // modes + this.applicationKeypad = false; + this.applicationCursor = false; + this.originMode = false; + this.insertMode = false; + this.wraparoundMode = false; + this.normal = null; + + // select modes + this.selectMode = false; + this.visualMode = false; + this.searchMode = false; + this.searchDown; + this.entry = ''; + this.entryPrefix = 'Search: '; + this._real; + this._selected; + this._textarea; + + // charset + this.charset = null; + this.gcharset = null; + this.glevel = 0; + this.charsets = [null]; + + // mouse properties + this.decLocator; + this.x10Mouse; + this.vt200Mouse; + this.vt300Mouse; + this.normalMouse; + this.mouseEvents; + this.sendFocus; + this.utfMouse; + this.sgrMouse; + this.urxvtMouse; + + // misc + this.element; + this.children; + this.refreshStart; + this.refreshEnd; + this.savedX; + this.savedY; + this.savedCols; + + // stream + this.readable = true; + this.writable = true; + + this.defAttr = (0 << 18) | (257 << 9) | (256 << 0); + this.curAttr = this.defAttr; + + this.params = []; + this.currentParam = 0; + this.prefix = ''; + this.postfix = ''; + + this.lines = []; + var i = this.rows; + while (i--) { + this.lines.push(this.blankLine()); + } + + this.tabs; + this.setupStops(); +} + +inherits(Terminal, EventEmitter); + +// back_color_erase feature for xterm. +Terminal.prototype.eraseAttr = function() { + // if (this.is('screen')) return this.defAttr; + return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff); +}; + +/** + * Colors + */ + +// Colors 0-15 +Terminal.tangoColors = [ + // dark: + '#2e3436', + '#cc0000', + '#4e9a06', + '#c4a000', + '#3465a4', + '#75507b', + '#06989a', + '#d3d7cf', + // bright: + '#555753', + '#ef2929', + '#8ae234', + '#fce94f', + '#729fcf', + '#ad7fa8', + '#34e2e2', + '#eeeeec' +]; + +Terminal.xtermColors = [ + // dark: + '#000000', // black + '#cd0000', // red3 + '#00cd00', // green3 + '#cdcd00', // yellow3 + '#0000ee', // blue2 + '#cd00cd', // magenta3 + '#00cdcd', // cyan3 + '#e5e5e5', // gray90 + // bright: + '#7f7f7f', // gray50 + '#ff0000', // red + '#00ff00', // green + '#ffff00', // yellow + '#5c5cff', // rgb:5c/5c/ff + '#ff00ff', // magenta + '#00ffff', // cyan + '#ffffff' // white +]; + +// Colors 0-15 + 16-255 +// Much thanks to TooTallNate for writing this. +Terminal.colors = (function() { + var colors = Terminal.tangoColors.slice() + , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] + , i; + + // 16-231 + i = 0; + for (; i < 216; i++) { + out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]); + } + + // 232-255 (grey) + i = 0; + for (; i < 24; i++) { + r = 8 + i * 10; + out(r, r, r); + } + + function out(r, g, b) { + colors.push('#' + hex(r) + hex(g) + hex(b)); + } + + function hex(c) { + c = c.toString(16); + return c.length < 2 ? '0' + c : c; + } + + return colors; +})(); + +// Default BG/FG +Terminal.colors[256] = '#000000'; +Terminal.colors[257] = '#f0f0f0'; + +Terminal._colors = Terminal.colors.slice(); + +Terminal.vcolors = (function() { + var out = [] + , colors = Terminal.colors + , i = 0 + , color; + + for (; i < 256; i++) { + color = parseInt(colors[i].substring(1), 16); + out.push([ + (color >> 16) & 0xff, + (color >> 8) & 0xff, + color & 0xff + ]); + } + + return out; +})(); + +/** + * Options + */ + +Terminal.defaults = { + colors: Terminal.colors, + convertEol: false, + termName: 'xterm', + geometry: [80, 24], + cursorBlink: true, + visualBell: false, + popOnBell: false, + scrollback: 1000, + screenKeys: false, + debug: false, + useStyle: false + // programFeatures: false, + // focusKeys: false, +}; + +Terminal.options = {}; + +each(keys(Terminal.defaults), function(key) { + Terminal[key] = Terminal.defaults[key]; + Terminal.options[key] = Terminal.defaults[key]; +}); + +/** + * Focused Terminal + */ + +Terminal.focus = null; + +Terminal.prototype.focus = function() { + if (Terminal.focus === this) return; + + if (Terminal.focus) { + Terminal.focus.blur(); + } + + if (this.sendFocus) this.send('\x1b[I'); + this.showCursor(); + + try { + this.element.focus(); + } catch (e) { + ; + } + + this.emit('focus'); + + Terminal.focus = this; +}; + +Terminal.prototype.blur = function() { + if (Terminal.focus !== this) return; + + this.cursorState = 0; + this.refresh(this.y, this.y); + if (this.sendFocus) this.send('\x1b[O'); + + // try { + // this.element.blur(); + // } catch (e) { + // ; + // } + + // this.emit('blur'); + + Terminal.focus = null; +}; + +/** + * Initialize global behavior + */ + +Terminal.prototype.initGlobal = function() { + var document = this.document; + + Terminal._boundDocs = Terminal._boundDocs || []; + if (~indexOf(Terminal._boundDocs, document)) { + return; + } + Terminal._boundDocs.push(document); + + Terminal.bindPaste(document); + + Terminal.bindKeys(document); + + Terminal.bindCopy(document); + + if (this.isMobile) { + this.fixMobile(document); + } + + if (this.useStyle) { + Terminal.insertStyle(document, this.colors[256], this.colors[257]); + } +}; + +/** + * Bind to paste event + */ + +Terminal.bindPaste = function(document) { + // This seems to work well for ctrl-V and middle-click, + // even without the contentEditable workaround. + var window = document.defaultView; + on(window, 'paste', function(ev) { + var term = Terminal.focus; + if (!term) return; + if (ev.clipboardData) { + term.send(ev.clipboardData.getData('text/plain')); + } else if (term.context.clipboardData) { + term.send(term.context.clipboardData.getData('Text')); + } + // Not necessary. Do it anyway for good measure. + term.element.contentEditable = 'inherit'; + return cancel(ev); + }); +}; + +/** + * Global Events for key handling + */ + +Terminal.bindKeys = function(document) { + // We should only need to check `target === body` below, + // but we can check everything for good measure. + on(document, 'keydown', function(ev) { + if (!Terminal.focus) return; + var target = ev.target || ev.srcElement; + if (!target) return; + if (target === Terminal.focus.element + || target === Terminal.focus.context + || target === Terminal.focus.document + || target === Terminal.focus.body + || target === Terminal._textarea + || target === Terminal.focus.parent) { + return Terminal.focus.keyDown(ev); + } + }, true); + + on(document, 'keypress', function(ev) { + if (!Terminal.focus) return; + var target = ev.target || ev.srcElement; + if (!target) return; + if (target === Terminal.focus.element + || target === Terminal.focus.context + || target === Terminal.focus.document + || target === Terminal.focus.body + || target === Terminal._textarea + || target === Terminal.focus.parent) { + return Terminal.focus.keyPress(ev); + } + }, true); + + // If we click somewhere other than a + // terminal, unfocus the terminal. + on(document, 'mousedown', function(ev) { + if (!Terminal.focus) return; + + var el = ev.target || ev.srcElement; + if (!el) return; + + do { + if (el === Terminal.focus.element) return; + } while (el = el.parentNode); + + Terminal.focus.blur(); + }); +}; + +/** + * Copy Selection w/ Ctrl-C (Select Mode) + */ + +Terminal.bindCopy = function(document) { + var window = document.defaultView; + + // if (!('onbeforecopy' in document)) { + // // Copies to *only* the clipboard. + // on(window, 'copy', function fn(ev) { + // var term = Terminal.focus; + // if (!term) return; + // if (!term._selected) return; + // var text = term.grabText( + // term._selected.x1, term._selected.x2, + // term._selected.y1, term._selected.y2); + // term.emit('copy', text); + // ev.clipboardData.setData('text/plain', text); + // }); + // return; + // } + + // Copies to primary selection *and* clipboard. + // NOTE: This may work better on capture phase, + // or using the `beforecopy` event. + on(window, 'copy', function(ev) { + var term = Terminal.focus; + if (!term) return; + if (!term._selected) return; + var textarea = term.getCopyTextarea(); + var text = term.grabText( + term._selected.x1, term._selected.x2, + term._selected.y1, term._selected.y2); + term.emit('copy', text); + textarea.focus(); + textarea.textContent = text; + textarea.value = text; + textarea.setSelectionRange(0, text.length); + setTimeout(function() { + term.element.focus(); + term.focus(); + }, 1); + }); +}; + +/** + * Fix Mobile + */ + +Terminal.prototype.fixMobile = function(document) { + var self = this; + + var textarea = document.createElement('textarea'); + textarea.style.position = 'absolute'; + textarea.style.left = '-32000px'; + textarea.style.top = '-32000px'; + textarea.style.width = '0px'; + textarea.style.height = '0px'; + textarea.style.opacity = '0'; + textarea.style.backgroundColor = 'transparent'; + textarea.style.borderStyle = 'none'; + textarea.style.outlineStyle = 'none'; + textarea.autocapitalize = 'none'; + textarea.autocorrect = 'off'; + + document.getElementsByTagName('body')[0].appendChild(textarea); + + Terminal._textarea = textarea; + + setTimeout(function() { + textarea.focus(); + }, 1000); + + if (this.isAndroid) { + on(textarea, 'change', function() { + var value = textarea.textContent || textarea.value; + textarea.value = ''; + textarea.textContent = ''; + self.send(value + '\r'); + }); + } +}; + +/** + * Insert a default style + */ + +Terminal.insertStyle = function(document, bg, fg) { + var style = document.getElementById('term-style'); + if (style) return; + + var head = document.getElementsByTagName('head')[0]; + if (!head) return; + + var style = document.createElement('style'); + style.id = 'term-style'; + + // textContent doesn't work well with IE for