/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.client; import com.google.gwt.core.client.Callback; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Document; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.RootLayoutPanel; import com.google.gwt.user.client.ui.SimpleLayoutPanel; 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.api.machine.shared.dto.MachineDto; 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.api.workspace.shared.dto.WorkspaceDto; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.component.Component; import org.eclipse.che.ide.api.component.WsAgentComponent; import org.eclipse.che.ide.api.event.WindowActionEvent; import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.api.machine.WsAgentStateController; import org.eclipse.che.ide.api.machine.WsAgentURLModifier; import org.eclipse.che.ide.api.theme.Style; import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient; import org.eclipse.che.ide.api.workspace.event.WorkspaceStartedEvent; import org.eclipse.che.ide.context.AppContextImpl; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.statepersistance.AppStateManager; import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.ide.workspace.WorkspacePresenter; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; /** * Performs initial application startup. * * @author Nikolay Zamosenchuk * @author Dmitry Shnurenko * @author Vlad Zhukovskyi */ @Singleton public class BootstrapController { private final Provider<WorkspacePresenter> workspaceProvider; private final ExtensionInitializer extensionInitializer; private final EventBus eventBus; private final Provider<AppStateManager> appStateManagerProvider; private final AppContext appContext; private final WorkspaceServiceClient workspaceService; private final Provider<WsAgentStateController> wsAgentStateControllerProvider; private final WsAgentURLModifier wsAgentURLModifier; @Inject public BootstrapController(Provider<WorkspacePresenter> workspaceProvider, ExtensionInitializer extensionInitializer, EventBus eventBus, Provider<AppStateManager> appStateManagerProvider, AppContext appContext, DtoRegistrar dtoRegistrar, WorkspaceServiceClient workspaceService, Provider<WsAgentStateController> wsAgentStateControllerProvider, WsAgentURLModifier wsAgentURLModifier) { this.workspaceProvider = workspaceProvider; this.extensionInitializer = extensionInitializer; this.eventBus = eventBus; this.appStateManagerProvider = appStateManagerProvider; this.appContext = appContext; this.workspaceService = workspaceService; this.wsAgentStateControllerProvider = wsAgentStateControllerProvider; this.wsAgentURLModifier = wsAgentURLModifier; appContext.setStartUpActions(StartUpActionsParser.getStartUpActions()); dtoRegistrar.registerDtoProviders(); setCustomInterval(); } @Inject private void startComponents(Map<String, Provider<Component>> components) { startComponents(components.values().iterator()); } @Inject private void startWsAgentComponents(EventBus eventBus, final Map<String, Provider<WsAgentComponent>> components) { eventBus.addHandler(WorkspaceStartedEvent.TYPE, new WorkspaceStartedEvent.Handler() { @Override public void onWorkspaceStarted(WorkspaceStartedEvent event) { workspaceService.getWorkspace(event.getWorkspace().getId()).then(new Operation<WorkspaceDto>() { @Override public void apply(WorkspaceDto ws) throws OperationException { MachineDto devMachineDto = ws.getRuntime().getDevMachine(); DevMachine devMachine = new DevMachine(devMachineDto); if (appContext instanceof AppContextImpl) { ((AppContextImpl)appContext).setProjectsRoot(Path.valueOf(devMachineDto.getRuntime().projectsRoot())); } wsAgentStateControllerProvider.get().initialize(devMachine); wsAgentURLModifier.initialize(devMachine); SortedMap<String, Provider<WsAgentComponent>> sortedComponents = new TreeMap<>(); sortedComponents.putAll(components); startWsAgentComponents(sortedComponents.values().iterator()); } }).catchError(new Operation<PromiseError>() { @Override public void apply(PromiseError err) throws OperationException { Log.error(getClass(), err.getCause()); initializationFailed(err.getMessage()); } }); } }); } private void startComponents(final Iterator<Provider<Component>> componentProviderIterator) { if (componentProviderIterator.hasNext()) { Provider<Component> componentProvider = componentProviderIterator.next(); final Component component = componentProvider.get(); component.start(new Callback<Component, Exception>() { @Override public void onSuccess(Component result) { startComponents(componentProviderIterator); } @Override public void onFailure(Exception reason) { Log.error(component.getClass(), reason); initializationFailed(reason.getMessage()); } }); } else { startExtensionsAndDisplayUI(); } } private void startWsAgentComponents(final Iterator<Provider<WsAgentComponent>> componentProviderIterator) { if (componentProviderIterator.hasNext()) { Provider<WsAgentComponent> componentProvider = componentProviderIterator.next(); final WsAgentComponent component = componentProvider.get(); component.start(new Callback<WsAgentComponent, Exception>() { @Override public void onSuccess(WsAgentComponent result) { startWsAgentComponents(componentProviderIterator); } @Override public void onFailure(Exception reason) { Log.error(component.getClass(), reason); initializationFailed(reason.getMessage()); } }); } } private void startExtensionsAndDisplayUI() { // Change background color according to the current theme if (Style.theme != null) { Document.get().getBody().getStyle().setBackgroundColor(Style.theme.backgroundColor()); } appStateManagerProvider.get(); displayIDE(); extensionInitializer.startExtensions(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { notifyShowIDE(); } }); } private void displayIDE() { // Start UI SimpleLayoutPanel mainPanel = new SimpleLayoutPanel(); RootLayoutPanel.get().add(mainPanel); // Make sure the root panel creates its own stacking context RootLayoutPanel.get().getElement().getStyle().setZIndex(0); WorkspacePresenter workspacePresenter = workspaceProvider.get(); // Display IDE workspacePresenter.go(mainPanel); // Bind browser's window events Window.addWindowClosingHandler(new Window.ClosingHandler() { @Override public void onWindowClosing(Window.ClosingEvent event) { eventBus.fireEvent(WindowActionEvent.createWindowClosingEvent(event)); } }); Window.addCloseHandler(new CloseHandler<Window>() { @Override public void onClose(CloseEvent<Window> event) { eventBus.fireEvent(WindowActionEvent.createWindowClosedEvent()); } }); } /** * Sends a message to the parent frame to inform that IDE application can be shown. */ private native void notifyShowIDE() /*-{ $wnd.parent.postMessage("show-ide", "*"); }-*/; /** * Handles any of initialization errors. * Tries to call predefined IDE.eventHandlers.ideInitializationFailed function. * * @param reason * failure encountered */ private native void initializationFailed(String reason) /*-{ try { $wnd.IDE.eventHandlers.initializationFailed(reason); this.@org.eclipse.che.ide.client.BootstrapController::notifyShowIDE()(); } catch (e) { console.log(e.message); } }-*/; /** * When we change browser tab and IDE executes into inactive tab, browser set code execution interval to improve performance. For * example Chrome and Firefox set 1000ms = 1sec interval. The method override global setInterval function and set custom value (100ms) * of interval. This solution fix issue when we need execute some code into inactive tab permanently, for example launch factory. */ private native void setCustomInterval() /*-{ var customInterval = 10; var setInterval = function () { clearInterval(interval); customInterval *= 10; }; var interval = setInterval(setInterval, customInterval); }-*/; }