Rework Composer plugin to avoid using Everrest based Websocket calls (#5629)
* Rework Composer plugin to avoid using Everrest based Websocket calls Fixes #5348 Signed-off-by: Kaloyan Raev <kaloyan.r@zend.com> * Fix dependencies Signed-off-by: Vitalii Parfonov <vparfonov@redhat.com>6.19.x
parent
6bc14afaa0
commit
e1868db831
|
|
@ -104,7 +104,7 @@
|
|||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<updateOnly>false</updateOnly>
|
||||
<descriptors>
|
||||
<descriptor>${project.basedir}/src/assembly/assembly.xml</descriptor>
|
||||
<descriptor>${project.basedir}/src/assembly/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>eclipse-che-${project.version}</finalName>
|
||||
<tarLongFileMode>posix</tarLongFileMode>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@
|
|||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-project-shared</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016-2017 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.composer.ide;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
|
||||
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
|
||||
import org.eclipse.che.plugin.composer.shared.dto.ComposerOutput;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_CHANNEL_OUTPUT;
|
||||
import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_CHANNEL_SUBSCRIBE;
|
||||
|
||||
/**
|
||||
* A mechanism for handling all messages from the Composer and applying
|
||||
* registered consumers.
|
||||
*
|
||||
* @author Kaloyan Raev
|
||||
*/
|
||||
@Singleton
|
||||
public class ComposerJsonRpcHandler {
|
||||
private static final String WS_AGENT_ENDPOINT = "ws-agent";
|
||||
|
||||
private RequestHandlerConfigurator configurator;
|
||||
|
||||
private Set<Consumer<ComposerOutput>> composerOutputConsumers = new HashSet<>();
|
||||
|
||||
private boolean isSubscribed = false;
|
||||
|
||||
@Inject
|
||||
public ComposerJsonRpcHandler(RequestHandlerConfigurator configurator) {
|
||||
this.configurator = configurator;
|
||||
|
||||
handleComposerMessages();
|
||||
}
|
||||
|
||||
@Inject
|
||||
private void subscribe(RequestTransmitter requestTransmitter) {
|
||||
if (isSubscribed) {
|
||||
return;
|
||||
}
|
||||
|
||||
requestTransmitter.newRequest()
|
||||
.endpointId(WS_AGENT_ENDPOINT)
|
||||
.methodName(COMPOSER_CHANNEL_SUBSCRIBE)
|
||||
.noParams()
|
||||
.sendAndSkipResult();
|
||||
|
||||
isSubscribed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds consumer for the event with {@link ComposerOutput}.
|
||||
*
|
||||
* @param consumer
|
||||
* new consumer
|
||||
*/
|
||||
public void addComposerOutputHandler(Consumer<ComposerOutput> consumer) {
|
||||
composerOutputConsumers.add(consumer);
|
||||
}
|
||||
|
||||
private void handleComposerMessages() {
|
||||
configurator.newConfiguration()
|
||||
.methodName(COMPOSER_CHANNEL_OUTPUT)
|
||||
.paramsAsDto(ComposerOutput.class)
|
||||
.noResult()
|
||||
.withConsumer(archetypeOutput -> composerOutputConsumers.forEach(it -> it.accept(archetypeOutput)));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software, Inc.
|
||||
* Copyright (c) 2016-2017 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
|
||||
|
|
@ -12,26 +12,14 @@ package org.eclipse.che.plugin.composer.ide.communication;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.web.bindery.event.shared.EventBus;
|
||||
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.machine.WsAgentStateController;
|
||||
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
|
||||
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
|
||||
import org.eclipse.che.ide.dto.DtoFactory;
|
||||
import org.eclipse.che.ide.console.CommandConsoleFactory;
|
||||
import org.eclipse.che.ide.console.DefaultOutputConsole;
|
||||
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
|
||||
import org.eclipse.che.ide.util.loging.Log;
|
||||
import org.eclipse.che.ide.websocket.MessageBus;
|
||||
import org.eclipse.che.ide.websocket.WebSocketException;
|
||||
import org.eclipse.che.ide.websocket.events.MessageHandler;
|
||||
import org.eclipse.che.plugin.composer.ide.ComposerJsonRpcHandler;
|
||||
import org.eclipse.che.plugin.composer.shared.dto.ComposerOutput;
|
||||
|
||||
import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_CHANNEL_NAME;
|
||||
|
||||
/**
|
||||
* Handler which receives messages from the Composer tool.
|
||||
*
|
||||
|
|
@ -40,77 +28,43 @@ import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_CHANNEL_
|
|||
@Singleton
|
||||
public class ComposerOutputHandler {
|
||||
|
||||
private final EventBus eventBus;
|
||||
private final DtoFactory factory;
|
||||
private final ProcessesPanelPresenter processesPanelPresenter;
|
||||
private final CommandConsoleFactory commandConsoleFactory;
|
||||
private final AppContext appContext;
|
||||
|
||||
private DefaultOutputConsole outputConsole;
|
||||
|
||||
@Inject
|
||||
public ComposerOutputHandler(EventBus eventBus,
|
||||
DtoFactory factory,
|
||||
WsAgentStateController wsAgentStateController,
|
||||
public ComposerOutputHandler(ComposerJsonRpcHandler composerJsonRpcHandler,
|
||||
ProcessesPanelPresenter processesPanelPresenter,
|
||||
CommandConsoleFactory commandConsoleFactory,
|
||||
AppContext appContext) {
|
||||
this.eventBus = eventBus;
|
||||
this.factory = factory;
|
||||
this.processesPanelPresenter = processesPanelPresenter;
|
||||
this.commandConsoleFactory = commandConsoleFactory;
|
||||
this.appContext = appContext;
|
||||
|
||||
handleOperations(factory, wsAgentStateController);
|
||||
composerJsonRpcHandler.addComposerOutputHandler(this::onComposerOutput);
|
||||
|
||||
outputConsole = (DefaultOutputConsole) commandConsoleFactory.create("Composer");
|
||||
}
|
||||
|
||||
private void handleOperations(final DtoFactory factory, final WsAgentStateController wsAgentStateController) {
|
||||
eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() {
|
||||
@Override
|
||||
public void onWsAgentStarted(WsAgentStateEvent event) {
|
||||
wsAgentStateController.getMessageBus().then(new Operation<MessageBus>() {
|
||||
@Override
|
||||
public void apply(MessageBus messageBus) throws OperationException {
|
||||
handleComposerOutput(messageBus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWsAgentStopped(WsAgentStateEvent event) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleComposerOutput(final MessageBus messageBus) {
|
||||
final DefaultOutputConsole outputConsole = (DefaultOutputConsole) commandConsoleFactory.create("Composer");
|
||||
|
||||
try {
|
||||
messageBus.subscribe(COMPOSER_CHANNEL_NAME, new MessageHandler() {
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
Log.info(getClass(), message);
|
||||
ComposerOutput archetypeOutput = factory.createDtoFromJson(message, ComposerOutput.class);
|
||||
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole);
|
||||
switch (archetypeOutput.getState()) {
|
||||
case START:
|
||||
outputConsole.clearOutputsButtonClicked();
|
||||
outputConsole.printText(archetypeOutput.getOutput(),"green");
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
outputConsole.printText(archetypeOutput.getOutput());
|
||||
break;
|
||||
case DONE:
|
||||
outputConsole.printText(archetypeOutput.getOutput(),"green");
|
||||
break;
|
||||
case ERROR:
|
||||
outputConsole.printText(archetypeOutput.getOutput(),"red");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (WebSocketException e) {
|
||||
e.printStackTrace();
|
||||
private void onComposerOutput(ComposerOutput output) {
|
||||
String message = output.getOutput();
|
||||
switch (output.getState()) {
|
||||
case START:
|
||||
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole);
|
||||
outputConsole.clearOutputsButtonClicked();
|
||||
outputConsole.printText(message, "green");
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
outputConsole.printText(message);
|
||||
break;
|
||||
case DONE:
|
||||
outputConsole.printText(message, "green");
|
||||
break;
|
||||
case ERROR:
|
||||
outputConsole.printText(message, "red");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@
|
|||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
|
|
@ -33,10 +37,22 @@
|
|||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-multibindings</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-project</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software, Inc.
|
||||
* Copyright (c) 2016-2017 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
|
||||
|
|
@ -17,6 +17,7 @@ import org.eclipse.che.api.project.server.handlers.ProjectHandler;
|
|||
import org.eclipse.che.api.project.server.type.ProjectTypeDef;
|
||||
import org.eclipse.che.api.project.server.type.ValueProviderFactory;
|
||||
import org.eclipse.che.inject.DynaModule;
|
||||
import org.eclipse.che.plugin.composer.server.executor.ComposerJsonRpcMessenger;
|
||||
import org.eclipse.che.plugin.composer.server.projecttype.ComposerProjectGenerator;
|
||||
import org.eclipse.che.plugin.composer.server.projecttype.ComposerProjectInitializer;
|
||||
import org.eclipse.che.plugin.composer.server.projecttype.ComposerProjectType;
|
||||
|
|
@ -45,5 +46,7 @@ public class ComposerModule extends AbstractModule {
|
|||
Multibinder<ProjectHandler> projectHandlerMultibinder = newSetBinder(binder(), ProjectHandler.class);
|
||||
projectHandlerMultibinder.addBinding().to(ComposerProjectGenerator.class);
|
||||
projectHandlerMultibinder.addBinding().to(ComposerProjectInitializer.class);
|
||||
|
||||
bind(ComposerJsonRpcMessenger.class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016-2017 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.composer.server.executor;
|
||||
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.util.AbstractLineConsumer;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.api.core.util.ProcessUtil;
|
||||
import org.eclipse.che.api.core.util.ValueHolder;
|
||||
import org.eclipse.che.api.core.util.Watchdog;
|
||||
import org.eclipse.che.plugin.composer.shared.dto.ComposerOutput;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* @author Kaloyan Raev
|
||||
*/
|
||||
@Singleton
|
||||
public class ComposerCommandExecutor {
|
||||
|
||||
private EventService eventService;
|
||||
|
||||
@Inject
|
||||
public ComposerCommandExecutor(EventService eventService) {
|
||||
this.eventService = eventService;
|
||||
}
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ComposerCommandExecutor.class);
|
||||
|
||||
public void execute(String[] commandLine, File workDir)
|
||||
throws TimeoutException, IOException, InterruptedException {
|
||||
ProcessBuilder pb = new ProcessBuilder(commandLine).redirectErrorStream(true).directory(workDir);
|
||||
|
||||
eventService.publish(new ComposerOutputImpl(String.join(" ", commandLine), ComposerOutput.State.START));
|
||||
|
||||
LineConsumer lineConsumer = new AbstractLineConsumer() {
|
||||
@Override
|
||||
public void writeLine(String line) throws IOException {
|
||||
eventService.publish(new ComposerOutputImpl(line, ComposerOutput.State.IN_PROGRESS));
|
||||
}
|
||||
};
|
||||
|
||||
// process will be stopped after timeout
|
||||
Watchdog watcher = new Watchdog(10, TimeUnit.MINUTES);
|
||||
|
||||
try {
|
||||
final Process process = pb.start();
|
||||
final ValueHolder<Boolean> isTimeoutExceeded = new ValueHolder<>(false);
|
||||
watcher.start(() -> {
|
||||
isTimeoutExceeded.set(true);
|
||||
ProcessUtil.kill(process);
|
||||
});
|
||||
// consume logs until process ends
|
||||
ProcessUtil.process(process, lineConsumer);
|
||||
process.waitFor();
|
||||
eventService.publish(new ComposerOutputImpl("Done", ComposerOutput.State.DONE));
|
||||
if (isTimeoutExceeded.get()) {
|
||||
LOG.error("Command time expired : command-line " + Arrays.toString(commandLine));
|
||||
eventService.publish(new ComposerOutputImpl("Installing dependencies time expired", ComposerOutput.State.ERROR));
|
||||
throw new TimeoutException();
|
||||
} else if (process.exitValue() != 0) {
|
||||
LOG.error("Command failed : command-line " + Arrays.toString(commandLine));
|
||||
eventService.publish(new ComposerOutputImpl("Error occurred", ComposerOutput.State.ERROR));
|
||||
throw new IOException("Process failed. Exit code " + process.exitValue() + " command-line : " + Arrays.toString(commandLine));
|
||||
}
|
||||
} finally {
|
||||
watcher.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016-2017 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.composer.server.executor;
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
|
||||
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.notification.EventSubscriber;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.plugin.composer.shared.dto.ComposerOutput;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.collect.Sets.newConcurrentHashSet;
|
||||
import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_CHANNEL_OUTPUT;
|
||||
import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_CHANNEL_SUBSCRIBE;
|
||||
import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_CHANNEL_UNSUBSCRIBE;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Mechanism which sends events of Composer by using JSON RPC to the client.
|
||||
*
|
||||
* @author Kaloyan Raev
|
||||
*/
|
||||
@Singleton
|
||||
public class ComposerJsonRpcMessenger implements EventSubscriber<ComposerOutput> {
|
||||
private final Set<String> endpointIds = newConcurrentHashSet();
|
||||
private EventService eventService;
|
||||
private RequestTransmitter transmitter;
|
||||
|
||||
@Inject
|
||||
public ComposerJsonRpcMessenger(EventService eventService,
|
||||
RequestTransmitter transmitter) {
|
||||
this.eventService = eventService;
|
||||
this.transmitter = transmitter;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void subscribe() {
|
||||
eventService.subscribe(this);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
private void unsubscribe() {
|
||||
eventService.unsubscribe(this);
|
||||
}
|
||||
|
||||
@Inject
|
||||
private void configureHandlers(RequestHandlerConfigurator configurator) {
|
||||
configurator.newConfiguration()
|
||||
.methodName(COMPOSER_CHANNEL_SUBSCRIBE)
|
||||
.noParams()
|
||||
.noResult()
|
||||
.withConsumer(endpointIds::add);
|
||||
|
||||
configurator.newConfiguration()
|
||||
.methodName(COMPOSER_CHANNEL_UNSUBSCRIBE)
|
||||
.noParams()
|
||||
.noResult()
|
||||
.withConsumer(endpointIds::remove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ComposerOutput event) {
|
||||
ComposerOutput composerOutput = DtoFactory.newDto(ComposerOutput.class);
|
||||
composerOutput.setOutput(event.getOutput());
|
||||
composerOutput.setState(event.getState());
|
||||
|
||||
endpointIds.forEach(it -> transmitter.newRequest()
|
||||
.endpointId(it)
|
||||
.methodName(COMPOSER_CHANNEL_OUTPUT).paramsAsDto(composerOutput)
|
||||
.sendAndSkipResult());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software, Inc.
|
||||
* Copyright (c) 2016-2017 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
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Rogue Wave Software, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.composer.server.projecttype;
|
||||
package org.eclipse.che.plugin.composer.server.executor;
|
||||
|
||||
import org.eclipse.che.plugin.composer.shared.dto.ComposerOutput;
|
||||
|
||||
|
|
@ -34,4 +34,14 @@ public class ComposerOutputImpl implements ComposerOutput {
|
|||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutput(String output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* 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.composer.server.projecttype;
|
||||
|
||||
import org.eclipse.che.api.core.util.AbstractLineConsumer;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.api.core.util.ProcessUtil;
|
||||
import org.eclipse.che.api.core.util.ValueHolder;
|
||||
import org.eclipse.che.api.core.util.Watchdog;
|
||||
import org.eclipse.che.api.core.util.WebsocketMessageConsumer;
|
||||
import org.eclipse.che.plugin.composer.shared.Constants;
|
||||
import org.eclipse.che.plugin.composer.shared.dto.ComposerOutput;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class ComposerCommandExecutor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ComposerCommandExecutor.class);
|
||||
|
||||
public static void execute(String[] commandLine, File workDir)
|
||||
throws TimeoutException, IOException, InterruptedException {
|
||||
ProcessBuilder pb = new ProcessBuilder(commandLine).redirectErrorStream(true).directory(workDir);
|
||||
|
||||
try (WebsocketMessageConsumer<ComposerOutput> websocketMessageConsumer = new WebsocketMessageConsumer<>(Constants.COMPOSER_CHANNEL_NAME)) {
|
||||
websocketMessageConsumer.consume(new ComposerOutputImpl(String.join(" ", commandLine), ComposerOutput.State.START));
|
||||
LineConsumer lineConsumer = new AbstractLineConsumer() {
|
||||
@Override
|
||||
public void writeLine(String line) throws IOException {
|
||||
websocketMessageConsumer.consume(new ComposerOutputImpl(line, ComposerOutput.State.IN_PROGRESS));
|
||||
}
|
||||
};
|
||||
|
||||
// process will be stopped after timeout
|
||||
Watchdog watcher = new Watchdog(10, TimeUnit.MINUTES);
|
||||
|
||||
try {
|
||||
final Process process = pb.start();
|
||||
final ValueHolder<Boolean> isTimeoutExceeded = new ValueHolder<>(false);
|
||||
watcher.start(() -> {
|
||||
isTimeoutExceeded.set(true);
|
||||
ProcessUtil.kill(process);
|
||||
});
|
||||
// consume logs until process ends
|
||||
ProcessUtil.process(process, lineConsumer);
|
||||
process.waitFor();
|
||||
websocketMessageConsumer.consume(new ComposerOutputImpl("Done", ComposerOutput.State.DONE));
|
||||
if (isTimeoutExceeded.get()) {
|
||||
LOG.error("Command time expired : command-line " + Arrays.toString(commandLine));
|
||||
websocketMessageConsumer.consume(new ComposerOutputImpl("Installing dependencies time expired", ComposerOutput.State.ERROR));
|
||||
throw new TimeoutException();
|
||||
} else if (process.exitValue() != 0) {
|
||||
LOG.error("Command failed : command-line " + Arrays.toString(commandLine));
|
||||
websocketMessageConsumer.consume(new ComposerOutputImpl("Error occurred", ComposerOutput.State.ERROR));
|
||||
throw new IOException("Process failed. Exit code " + process.exitValue() + " command-line : " + Arrays.toString(commandLine));
|
||||
}
|
||||
} finally {
|
||||
watcher.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software, Inc.
|
||||
* Copyright (c) 2016-2017 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
|
||||
|
|
@ -10,8 +10,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.composer.server.projecttype;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.ForbiddenException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
|
|
@ -20,6 +18,7 @@ import org.eclipse.che.api.project.server.type.AttributeValue;
|
|||
import org.eclipse.che.api.vfs.Path;
|
||||
import org.eclipse.che.api.vfs.VirtualFileSystem;
|
||||
import org.eclipse.che.api.vfs.VirtualFileSystemProvider;
|
||||
import org.eclipse.che.plugin.composer.server.executor.ComposerCommandExecutor;
|
||||
import org.eclipse.che.plugin.composer.shared.Constants;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -27,10 +26,22 @@ import java.io.IOException;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* @author Kaloyan Raev
|
||||
*/
|
||||
public class ComposerProjectGenerator implements CreateProjectHandler {
|
||||
|
||||
private final VirtualFileSystem vfs;
|
||||
private final ComposerCommandExecutor commandExecutor;
|
||||
|
||||
@Inject
|
||||
private VirtualFileSystemProvider virtualFileSystemProvider;
|
||||
public ComposerProjectGenerator(VirtualFileSystemProvider vfsProvider,
|
||||
ComposerCommandExecutor commandExecutor) throws ServerException {
|
||||
this.vfs = vfsProvider.getVirtualFileSystem();
|
||||
this.commandExecutor = commandExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateProject(Path projectPath, Map<String, AttributeValue> attributes, Map<String, String> options)
|
||||
|
|
@ -40,12 +51,11 @@ public class ComposerProjectGenerator implements CreateProjectHandler {
|
|||
throw new ServerException("Missed some required options (package)");
|
||||
}
|
||||
|
||||
VirtualFileSystem vfs = virtualFileSystemProvider.getVirtualFileSystem();
|
||||
String projectAbsolutePath = new File(vfs.getRoot().toIoFile(), projectPath.toString()).toString();
|
||||
|
||||
String[] commandLine = { "composer", "create-project", packageName.getString(), projectAbsolutePath, "--no-install" };
|
||||
try {
|
||||
ComposerCommandExecutor.execute(commandLine, null);
|
||||
commandExecutor.execute(commandLine, null);
|
||||
} catch (TimeoutException | IOException | InterruptedException e) {
|
||||
throw new ServerException(e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software, Inc.
|
||||
* Copyright (c) 2016-2017 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
|
||||
|
|
@ -17,6 +17,7 @@ import org.eclipse.che.api.core.ServerException;
|
|||
import org.eclipse.che.api.project.server.FolderEntry;
|
||||
import org.eclipse.che.api.project.server.ProjectRegistry;
|
||||
import org.eclipse.che.api.project.server.handlers.ProjectInitHandler;
|
||||
import org.eclipse.che.plugin.composer.server.executor.ComposerCommandExecutor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
|
@ -24,15 +25,27 @@ import java.util.concurrent.TimeoutException;
|
|||
|
||||
import static org.eclipse.che.plugin.composer.shared.Constants.COMPOSER_PROJECT_TYPE_ID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* @author Kaloyan Raev
|
||||
*/
|
||||
public class ComposerProjectInitializer implements ProjectInitHandler {
|
||||
|
||||
private ComposerCommandExecutor commandExecutor;
|
||||
|
||||
@Inject
|
||||
public ComposerProjectInitializer(ComposerCommandExecutor commandExecutor) {
|
||||
this.commandExecutor = commandExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProjectInitialized(ProjectRegistry registry, FolderEntry projectFolder)
|
||||
throws ServerException, ForbiddenException, ConflictException, NotFoundException {
|
||||
String[] commandLine = { "composer", "install" };
|
||||
File workDir = projectFolder.getVirtualFile().toIoFile();
|
||||
try {
|
||||
ComposerCommandExecutor.execute(commandLine, workDir);
|
||||
commandExecutor.execute(commandLine, workDir);
|
||||
} catch (TimeoutException | IOException | InterruptedException e) {
|
||||
throw new ServerException(e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software, Inc.
|
||||
* Copyright (c) 2016-2017 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
|
||||
|
|
@ -18,8 +18,9 @@ public class Constants {
|
|||
public final static String COMPOSER_PROJECT_TYPE_ID = "composer";
|
||||
public final static String PACKAGE = "package";
|
||||
|
||||
/** Name of WebSocket channel for Composer output */
|
||||
public final static String COMPOSER_CHANNEL_NAME = "composer:output";
|
||||
public final static String COMPOSER_CHANNEL_OUTPUT = "composer/output";
|
||||
public final static String COMPOSER_CHANNEL_SUBSCRIBE = "composer/subscribe";
|
||||
public final static String COMPOSER_CHANNEL_UNSUBSCRIBE = "composer/unsubscribe";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software, Inc.
|
||||
* Copyright (c) 2016-2017 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
|
||||
|
|
@ -42,4 +42,8 @@ public interface ComposerOutput {
|
|||
*/
|
||||
State getState();
|
||||
|
||||
void setOutput(String output);
|
||||
|
||||
void setState(State state);
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue