Merge pull request #541 from eclipse/wsAgentStateEvent
Improve handling of ws agent started event6.19.x
commit
ccfd0924df
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.ext.java.server;
|
||||
package org.eclipse.che.wsagent.server;
|
||||
|
||||
import org.eclipse.che.api.core.ApiException;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonRequestFactory;
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.ext.java.server;
|
||||
package org.eclipse.che.wsagent.server;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.ext.java.server;
|
||||
package org.eclipse.che.wsagent.server;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.servlet.ServletModule;
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.ext.java.server;
|
||||
package org.eclipse.che.wsagent.server;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.ext.java.server;
|
||||
package org.eclipse.che.wsagent.server;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
|
|
@ -101,7 +101,7 @@ public class MachineModule extends AbstractModule {
|
|||
bind(WSocketEventBusClient.class).asEagerSingleton();
|
||||
|
||||
bind(String.class).annotatedWith(Names.named("event.bus.url")).toProvider(EventBusURLProvider.class);
|
||||
bind(org.eclipse.che.ide.ext.java.server.ApiEndpointAccessibilityChecker.class);
|
||||
bind(ApiEndpointAccessibilityChecker.class);
|
||||
}
|
||||
|
||||
//it's need for WSocketEventBusClient and in the future will be replaced with the property
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.ext.java.server;
|
||||
package org.eclipse.che.wsagent.server;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import java.net.URI;
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.ext.java.server;
|
||||
package org.eclipse.che.wsagent.server;
|
||||
|
||||
import com.google.inject.Provider;
|
||||
|
||||
|
|
@ -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.rest;
|
||||
|
||||
/**
|
||||
* Describe information available service like fqn of class and path.
|
||||
*
|
||||
* @author Vitalii Parfonov
|
||||
*/
|
||||
public class RestServiceInfo {
|
||||
|
||||
private String fqn;
|
||||
|
||||
private String regex;
|
||||
|
||||
private String path;
|
||||
|
||||
public RestServiceInfo(String fqn, String regex, String path) {
|
||||
this.fqn = fqn;
|
||||
this.regex = regex;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* FQN of REST service class
|
||||
* @return fqn
|
||||
*/
|
||||
public String getFqn() {
|
||||
return fqn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular expressions for URI pattern.
|
||||
* @return
|
||||
*/
|
||||
public String getRegex() {
|
||||
return regex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the Path annotation, see {@link javax.ws.rs.Path}
|
||||
* @return
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestServiceInfo{" +
|
||||
"fqn='" + fqn + '\'' +
|
||||
", regex='" + regex + '\'' +
|
||||
", path='" + path + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,28 +10,39 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.api.machine.gwt.client;
|
||||
|
||||
import com.google.gwt.json.client.JSONArray;
|
||||
import com.google.gwt.json.client.JSONObject;
|
||||
import com.google.gwt.json.client.JSONParser;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Named;
|
||||
import com.google.web.bindery.event.shared.EventBus;
|
||||
|
||||
import org.eclipse.che.api.machine.gwt.client.events.WsAgentStateEvent;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper;
|
||||
import org.eclipse.che.ide.rest.AsyncRequestCallback;
|
||||
import org.eclipse.che.ide.rest.AsyncRequestFactory;
|
||||
import org.eclipse.che.ide.rest.RestServiceInfo;
|
||||
import org.eclipse.che.ide.rest.StringUnmarshaller;
|
||||
import org.eclipse.che.ide.ui.loaders.initialization.InitialLoadingInfo;
|
||||
import org.eclipse.che.ide.ui.loaders.initialization.LoaderPresenter;
|
||||
import org.eclipse.che.ide.util.loging.Log;
|
||||
import org.eclipse.che.ide.websocket.MessageBus;
|
||||
import org.eclipse.che.ide.websocket.MessageBusProvider;
|
||||
import org.eclipse.che.ide.websocket.WebSocket;
|
||||
import org.eclipse.che.ide.websocket.events.ConnectionClosedHandler;
|
||||
import org.eclipse.che.ide.websocket.events.ConnectionErrorHandler;
|
||||
import org.eclipse.che.ide.websocket.events.ConnectionOpenedHandler;
|
||||
import org.eclipse.che.ide.websocket.events.WebSocketClosedEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.eclipse.che.api.machine.gwt.client.WsAgentState.STARTED;
|
||||
import static org.eclipse.che.api.machine.gwt.client.WsAgentState.STOPPED;
|
||||
import static org.eclipse.che.ide.ui.loaders.initialization.InitialLoadingInfo.Operations.WS_AGENT_BOOTING;
|
||||
import static org.eclipse.che.ide.ui.loaders.initialization.OperationInfo.Status.ERROR;
|
||||
import static org.eclipse.che.ide.ui.loaders.initialization.OperationInfo.Status.IN_PROGRESS;
|
||||
import static org.eclipse.che.ide.ui.loaders.initialization.OperationInfo.Status.SUCCESS;
|
||||
|
||||
|
|
@ -42,72 +53,88 @@ import static org.eclipse.che.ide.ui.loaders.initialization.OperationInfo.Status
|
|||
@Singleton
|
||||
public class WsAgentStateController implements ConnectionOpenedHandler, ConnectionClosedHandler, ConnectionErrorHandler {
|
||||
|
||||
private final Timer retryConnectionTimer;
|
||||
private final EventBus eventBus;
|
||||
private final MessageBusProvider messageBusProvider;
|
||||
private final InitialLoadingInfo initialLoadingInfo;
|
||||
private final LoaderPresenter loader;
|
||||
private final EventBus eventBus;
|
||||
private final MessageBusProvider messageBusProvider;
|
||||
private final InitialLoadingInfo initialLoadingInfo;
|
||||
private final LoaderPresenter loader;
|
||||
private final AsyncRequestFactory asyncRequestFactory;
|
||||
private final String extPath;
|
||||
|
||||
private MessageBus messageBus;
|
||||
private WsAgentState state;
|
||||
private String wsUrl;
|
||||
private int countRetry;
|
||||
private AsyncCallback<MessageBus> messageBusCallback;
|
||||
private WebSocket testConnection; //use it only for testing state of ext-service
|
||||
//not used now added it for future if it we will have possibility check that service available for client call
|
||||
private final List<RestServiceInfo> availableServices;
|
||||
|
||||
private MessageBus messageBus;
|
||||
private WsAgentState state;
|
||||
private String wsUrl;
|
||||
private String wsId;
|
||||
private AsyncCallback<MessageBus> messageBusCallback;
|
||||
|
||||
@Inject
|
||||
public WsAgentStateController(EventBus eventBus,
|
||||
LoaderPresenter loader,
|
||||
MessageBusProvider messageBusProvider,
|
||||
AsyncRequestFactory asyncRequestFactory,
|
||||
@Named("cheExtensionPath") String extPath,
|
||||
InitialLoadingInfo initialLoadingInfo) {
|
||||
this.loader = loader;
|
||||
this.eventBus = eventBus;
|
||||
this.messageBusProvider = messageBusProvider;
|
||||
this.asyncRequestFactory = asyncRequestFactory;
|
||||
this.extPath = extPath;
|
||||
this.initialLoadingInfo = initialLoadingInfo;
|
||||
|
||||
retryConnectionTimer = new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
connect();
|
||||
countRetry--;
|
||||
}
|
||||
};
|
||||
availableServices = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void initialize(String wsUrl) {
|
||||
this.wsUrl = wsUrl;
|
||||
this.countRetry = 50;
|
||||
this.state = WsAgentState.STOPPED;
|
||||
|
||||
public void initialize(String wsUrl, String wsId) {
|
||||
this.wsUrl = wsUrl + "/" + wsId;
|
||||
this.wsId = wsId;
|
||||
this.state = STOPPED;
|
||||
initialLoadingInfo.setOperationStatus(WS_AGENT_BOOTING.getValue(), IN_PROGRESS);
|
||||
connect();
|
||||
|
||||
|
||||
checkHttpConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocketClosedEvent event) {
|
||||
Log.info(getClass(), "Test WS connection closed with code " + event.getCode() + " reason: " + event.getReason() +
|
||||
" workspace agent started well ");
|
||||
Log.info(getClass(), "Test WS connection closed with code " + event.getCode() + " reason: " + event.getReason());
|
||||
if (state.equals(STARTED)) {
|
||||
state = STOPPED;
|
||||
eventBus.fireEvent(WsAgentStateEvent.createWsAgentStoppedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
if (countRetry > 0) {
|
||||
retryConnectionTimer.schedule(1000);
|
||||
} else {
|
||||
state = WsAgentState.STOPPED;
|
||||
initialLoadingInfo.setOperationStatus(WS_AGENT_BOOTING.getValue(), ERROR);
|
||||
loader.hide();
|
||||
Log.info(getClass(), "Test WS connection error");
|
||||
if (state.equals(STARTED)) {
|
||||
state = STOPPED;
|
||||
eventBus.fireEvent(WsAgentStateEvent.createWsAgentStoppedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen() {
|
||||
testConnection.close(); //close testing connection now we know ws-agent already start
|
||||
messageBus = messageBusProvider.createMachineMessageBus(wsUrl);
|
||||
state = WsAgentState.STARTED;
|
||||
messageBus.removeOnOpenHandler(this);
|
||||
MessageBus.ReadyState readyState = messageBus.getReadyState();
|
||||
Log.info(getClass(), readyState.toString());
|
||||
//need to make sure ready state equals 1 (OPEN) in same situations after opening it still equals 0 (CONNECTING)
|
||||
if (!readyState.equals(MessageBus.ReadyState.OPEN)) {
|
||||
new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.info(getClass(), messageBus.getReadyState());
|
||||
if (messageBus.getReadyState().equals(MessageBus.ReadyState.OPEN)) {
|
||||
cancel();
|
||||
started();
|
||||
}
|
||||
}
|
||||
}.scheduleRepeating(100);
|
||||
} else {
|
||||
started();
|
||||
}
|
||||
}
|
||||
|
||||
private void started() {
|
||||
state = STARTED;
|
||||
initialLoadingInfo.setOperationStatus(WS_AGENT_BOOTING.getValue(), SUCCESS);
|
||||
loader.hide();
|
||||
|
||||
|
|
@ -117,6 +144,8 @@ public class WsAgentStateController implements ConnectionOpenedHandler, Connecti
|
|||
eventBus.fireEvent(WsAgentStateEvent.createWsAgentStartedEvent());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public WsAgentState getState() {
|
||||
return state;
|
||||
}
|
||||
|
|
@ -134,10 +163,48 @@ public class WsAgentStateController implements ConnectionOpenedHandler, Connecti
|
|||
});
|
||||
}
|
||||
|
||||
private void connect() {
|
||||
testConnection = WebSocket.create(wsUrl);
|
||||
testConnection.setOnOpenHandler(this);
|
||||
testConnection.setOnCloseHandler(this);
|
||||
testConnection.setOnErrorHandler(this);
|
||||
/**
|
||||
* Goto checking HTTP connection via getting all registered REST Services
|
||||
*/
|
||||
private void checkHttpConnection() {
|
||||
asyncRequestFactory.createGetRequest(extPath + "/" + wsId + "/").send(new AsyncRequestCallback<String>(new StringUnmarshaller()) {
|
||||
@Override
|
||||
protected void onSuccess(String result) {
|
||||
JSONObject object = JSONParser.parseStrict(result).isObject();
|
||||
if (object.containsKey("rootResources")) {
|
||||
JSONArray rootResources = object.get("rootResources").isArray();
|
||||
for (int i = 0; i < rootResources.size(); i++) {
|
||||
JSONObject rootResource = rootResources.get(i).isObject();
|
||||
String regex = rootResource.get("regex").isString().stringValue();
|
||||
String fqn = rootResource.get("fqn").isString().stringValue();
|
||||
String path = rootResource.get("path").isString().stringValue();
|
||||
availableServices.add(new RestServiceInfo(fqn,regex,path));
|
||||
}
|
||||
checkWsConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFailure(Throwable exception) {
|
||||
Log.error(getClass(), exception.getMessage());
|
||||
new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
checkHttpConnection();
|
||||
}
|
||||
}.schedule(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to connect via WebSocket connection
|
||||
*/
|
||||
private void checkWsConnection() {
|
||||
messageBus = messageBusProvider.createMachineMessageBus(wsUrl);
|
||||
messageBus.addOnCloseHandler(this);
|
||||
messageBus.addOnCloseHandler(this);
|
||||
messageBus.addOnOpenHandler(this);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
|
|||
@Singleton
|
||||
public class MachineExtensionProxyServlet extends HttpServlet {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MachineExtensionProxyServlet.class);
|
||||
private static final Pattern EXTENSION_API_URI = Pattern.compile(".*?/ext/[^/]+/(?<workspaceId>[^/]+)/?.*");
|
||||
private static final String WORKSPACE_ID_PATTERN = "([^/]+)";
|
||||
private static final Pattern EXTENSION_API_URI = Pattern.compile(".*?/ext/([^/]+/" + WORKSPACE_ID_PATTERN + "/?.*|" + WORKSPACE_ID_PATTERN + "/)");
|
||||
|
||||
private final int extServicesPort;
|
||||
private final MachineManager machineManager;
|
||||
|
|
@ -119,7 +120,7 @@ public class MachineExtensionProxyServlet extends HttpServlet {
|
|||
String workspaceId;
|
||||
final Matcher matcher = EXTENSION_API_URI.matcher(req.getRequestURI());
|
||||
if (matcher.matches()) {
|
||||
workspaceId = matcher.group("workspaceId");
|
||||
workspaceId = matcher.group(2) != null ? matcher.group(2) : matcher.group(3);
|
||||
} else {
|
||||
throw new NotFoundException("No workspace id is found in request.");
|
||||
}
|
||||
|
|
@ -131,9 +132,21 @@ public class MachineExtensionProxyServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
final UriBuilder uriBuilder = UriBuilder.fromUri(server.getUrl())
|
||||
.replacePath(req.getRequestURI())
|
||||
.replaceQuery(req.getQueryString());
|
||||
|
||||
//check contain original url path to service before wsId
|
||||
//if yes we just change host and port and forward to the ws-agent
|
||||
//if not we need to cut wsId from URL
|
||||
if (matcher.group(2) == null) {
|
||||
// here we cut workspaceId from extension API Url for getting access to org.eclipse.che.api.core.rest.ApiInfoService
|
||||
// e.g localhost:8080/ide/ext/{wsid} -> localhost:{extServicesPort}/ide/ext/
|
||||
String originUri = req.getRequestURI();
|
||||
final int indexOf = originUri.lastIndexOf('/', originUri.length() - 2);
|
||||
uriBuilder.replacePath(originUri.substring(0, indexOf + 1));
|
||||
} else {
|
||||
uriBuilder.replacePath(req.getRequestURI());
|
||||
}
|
||||
|
||||
return uriBuilder.build().toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,32 @@ public class MachineExtensionProxyServletTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToProxyWithout() throws Exception {
|
||||
final String path = "/api/ext/" + WORKSPACE_ID + "/";
|
||||
|
||||
final String defaultContextPath = contextHandler.getContextPath();
|
||||
try {
|
||||
contextHandler.setContextPath("/api/ext/");
|
||||
|
||||
MockHttpServletRequest mockRequest =
|
||||
new MockHttpServletRequest(PROXY_ENDPOINT + path,
|
||||
new ByteArrayInputStream(new byte[0]),
|
||||
0,
|
||||
"GET",
|
||||
defaultHeaders);
|
||||
|
||||
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
|
||||
|
||||
proxyServlet.service(mockRequest, mockResponse);
|
||||
|
||||
assertEquals(mockResponse.getStatus(), 200);
|
||||
assertEquals(extensionApiRequest.uri, "/api/ext/");
|
||||
} finally {
|
||||
contextHandler.setContextPath(defaultContextPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldProxyWithQueryString() throws Exception {
|
||||
final String query = "key1=value1&key2=value2&key2=value3";
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ public class MachineManagerImpl implements MachineManager, WorkspaceStoppedHandl
|
|||
appContext.setDevMachineId(machineId);
|
||||
appContext.setProjectsRoot(machineDto.getRuntime().projectsRoot());
|
||||
devMachine = entityFactory.createMachine(machineDto);
|
||||
wsAgentStateController.initialize(devMachine.getWsServerExtensionsUrl() + "/" + appContext.getWorkspaceId());
|
||||
wsAgentStateController.initialize(devMachine.getWsServerExtensionsUrl(), appContext.getWorkspaceId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue