/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * 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.client.dependenciesupdater; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.builder.BuildStatus; import org.eclipse.che.api.builder.dto.BuildTaskDescriptor; import org.eclipse.che.api.project.shared.dto.ProjectDescriptor; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.app.CurrentProject; import org.eclipse.che.ide.api.build.BuildContext; import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.event.RefreshProjectTreeEvent; import org.eclipse.che.ide.api.notification.Notification; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.collections.StringMap; import org.eclipse.che.ide.ext.java.client.JavaLocalizationConstant; import org.eclipse.che.ide.ext.java.client.editor.JavaParserWorker; import org.eclipse.che.ide.ext.java.client.projecttree.JavaTreeStructure; import org.eclipse.che.ide.ext.java.client.projecttree.nodes.ExternalLibrariesNode; import org.eclipse.che.ide.extension.builder.client.build.BuildController; import org.eclipse.che.ide.extension.builder.client.console.BuilderConsolePresenter; import org.eclipse.che.ide.jseditor.client.texteditor.EmbeddedTextEditorPresenter; import org.eclipse.che.ide.rest.AsyncRequestCallback; import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; import org.eclipse.che.ide.rest.Unmarshallable; import org.eclipse.che.ide.util.Pair; import org.eclipse.che.ide.util.loging.Log; import java.util.LinkedList; import java.util.Queue; import static org.eclipse.che.ide.api.notification.Notification.Status.FINISHED; import static org.eclipse.che.ide.api.notification.Notification.Status.PROGRESS; import static org.eclipse.che.ide.api.notification.Notification.Type.ERROR; /** * Updates dependencies for Maven project. * * @author Artem Zatsarynnyy * @author Vladyslav Zhukovskii */ @Singleton public class DependenciesUpdater { private final BuilderConsolePresenter builderConsole; private final NotificationManager notificationManager; private final BuildContext buildContext; private final JavaParserWorker parserWorker; private final EditorAgent editorAgent; private final BuildController buildController; private final DtoUnmarshallerFactory dtoUnmarshallerFactory; private final EventBus eventBus; private final AppContext context; private final JavaNameEnvironmentServiceClient nameEnvironmentServiceClient; private final JavaLocalizationConstant javaLocalizationConstant; private Queue<Pair<ProjectDescriptor, Boolean>> projects = new LinkedList<>(); private boolean updating = false; private JavaTreeStructure javaTreeStructure; private Notification notification; @Inject public DependenciesUpdater(JavaLocalizationConstant javaLocalizationConstant, NotificationManager notificationManager, BuildContext buildContext, JavaParserWorker parserWorker, EditorAgent editorAgent, BuildController buildController, DtoUnmarshallerFactory dtoUnmarshallerFactory, EventBus eventBus, AppContext context, JavaNameEnvironmentServiceClient nameEnvironmentServiceClient, BuilderConsolePresenter builderConsole) { this.javaLocalizationConstant = javaLocalizationConstant; this.notificationManager = notificationManager; this.buildContext = buildContext; this.parserWorker = parserWorker; this.editorAgent = editorAgent; this.buildController = buildController; this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; this.eventBus = eventBus; this.context = context; this.nameEnvironmentServiceClient = nameEnvironmentServiceClient; this.builderConsole = builderConsole; } public void updateDependencies(final ProjectDescriptor project, final boolean force) { if (updating) { projects.add(new Pair<>(project, force)); return; } final CurrentProject currentProject = context.getCurrentProject(); if (currentProject == null) { return; } builderConsole.clear(); javaTreeStructure = null; if (currentProject.getCurrentTree() instanceof JavaTreeStructure) { javaTreeStructure = (JavaTreeStructure)currentProject.getCurrentTree(); } notification = new Notification(javaLocalizationConstant.updatingDependencies(), PROGRESS); notificationManager.showNotification(notification); buildContext.setBuilding(true); updating = true; // send a first request to launch build process and return build task descriptor final Unmarshallable<BuildTaskDescriptor> unmarshaller = dtoUnmarshallerFactory.newUnmarshaller(BuildTaskDescriptor.class); nameEnvironmentServiceClient.updateDependencies( project.getPath(), force, new AsyncRequestCallback<BuildTaskDescriptor>(unmarshaller) { @Override protected void onSuccess(BuildTaskDescriptor descriptor) { buildContext.setBuildTaskDescriptor(descriptor); if (descriptor.getStatus() == BuildStatus.SUCCESSFUL) { onUpdated(); return; } buildController.showRunningBuild(descriptor, "[INFO] Updating dependencies..."); // send a second request to be notified when dependencies update is finished updateAndWait(descriptor, project); } @Override protected void onFailure(Throwable exception) { Log.warn(DependenciesUpdater.class, "Failed to launch build process and get build task descriptor for " + project); updating = false; updateFinishedWithError(exception, notification); } }); } private void updateAndWait(BuildTaskDescriptor descriptor, final ProjectDescriptor project) { nameEnvironmentServiceClient.updateDependenciesAndWait(project.getPath(), descriptor, new AsyncRequestCallback<Void>() { @Override protected void onSuccess(Void result) { onUpdated(); parserWorker.dependenciesUpdated(); refreshOpenedEditors(); refreshExtLibs(project); if (!projects.isEmpty()) { Pair<ProjectDescriptor, Boolean> pair = projects.poll(); updateDependencies(pair.first, pair.second); } } @Override protected void onFailure(Throwable exception) { updating = false; if (!projects.isEmpty()) { Pair<ProjectDescriptor, Boolean> pair = projects.poll(); updateDependencies(pair.first, pair.second); } updateFinishedWithError(exception, notification); } }); } private void onUpdated() { updating = false; notification.setMessage(javaLocalizationConstant.dependenciesSuccessfullyUpdated()); notification.setStatus(FINISHED); buildContext.setBuilding(false); } private void refreshOpenedEditors() { editorAgent.getOpenedEditors().iterate(new StringMap.IterationCallback<EditorPartPresenter>() { @Override public void onIteration(String s, EditorPartPresenter editorPartPresenter) { if (editorPartPresenter instanceof EmbeddedTextEditorPresenter) { final EmbeddedTextEditorPresenter<?> editor = (EmbeddedTextEditorPresenter<?>)editorPartPresenter; editor.refreshEditor(); } } }); } private void refreshExtLibs(ProjectDescriptor project) { if (javaTreeStructure != null) { ExternalLibrariesNode librariesNode = javaTreeStructure.getExternalLibrariesNode(project.getPath()); if (librariesNode != null && librariesNode.isOpened()) { eventBus.fireEvent(new RefreshProjectTreeEvent(librariesNode)); } } } private void updateFinishedWithError(Throwable exception, Notification notification) { buildContext.setBuilding(false); notification.setMessage(exception.getMessage()); notification.setType(ERROR); notification.setStatus(FINISHED); } }