From 212da9f42ea84c5188a7f2067128c2fa104ebc50 Mon Sep 17 00:00:00 2001 From: pazi146 Date: Wed, 23 Oct 2024 10:32:44 +0200 Subject: [PATCH] Added ChangeListener to Type Library listens to changes to linked libraries and starts resolve if needed --- .../ide/library/LibraryChangeListener.java | 75 +++++++++++++++++++ .../fordiac/ide/library/LibraryManager.java | 38 ++++++---- .../ui/wizard/New4diacProjectWizard.java | 13 +--- 3 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryChangeListener.java diff --git a/plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryChangeListener.java b/plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryChangeListener.java new file mode 100644 index 0000000000..86f802f74e --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryChangeListener.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2024 Primetals Technologies Austria GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Patrick Aigner - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.fordiac.ide.library; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.fordiac.ide.model.typelibrary.TypeLibraryManager; +import org.eclipse.fordiac.ide.ui.FordiacLogHelper; + +public class LibraryChangeListener implements IResourceChangeListener { + private static final int MASK = IResourceDelta.ADDED | IResourceDelta.REMOVED | IResourceDelta.CHANGED; + + @Override + public void resourceChanged(final IResourceChangeEvent event) { + if (event.getType() == IResourceChangeEvent.POST_CHANGE) { + final IResourceDelta rootDelta = event.getDelta(); + try { + rootDelta.accept(visitor, IContainer.INCLUDE_HIDDEN); + } catch (final CoreException e) { + FordiacLogHelper.logError("Couldn't process resource delta", e); //$NON-NLS-1$ + } + } + + } + + private final IResourceDeltaVisitor visitor = delta -> { + switch (delta.getResource().getType()) { + case IResource.PROJECT: + return delta.getKind() != IResourceDelta.REMOVED; // ignore deleted projects + case IResource.FILE: + // information on previous linked status is not available on delete + if (delta.getResource() instanceof final IFile file + && (file.isLinked() || delta.getKind() == IResourceDelta.REMOVED) + && LibraryManager.MANIFEST.equals(file.getName()) && (delta.getKind() & MASK) != 0) { + final IProject project = file.getProject(); + LibraryManager.INSTANCE.startResolveJob(project, TypeLibraryManager.INSTANCE.getTypeLibrary(project)); + + } + return false; + case IResource.FOLDER: + if (delta.getResource() instanceof final IFolder folder) { + // only search inside linked folders inside the Type Library + return isTypeLibraryFolder(folder) || ((folder.isLinked() || delta.getKind() == IResourceDelta.REMOVED) + && isTypeLibraryFolder(folder.getParent())); + } + break; + default: + break; + } + return true; + }; + + private static boolean isTypeLibraryFolder(final IContainer container) { + return container instanceof IFolder && container.getParent() instanceof IProject + && LibraryManager.TYPE_LIB_FOLDER_NAME.equals(container.getName()); + } +} diff --git a/plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryManager.java b/plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryManager.java index f4cfdd6539..c225a3707c 100644 --- a/plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryManager.java +++ b/plugins/org.eclipse.fordiac.ide.library/src/org/eclipse/fordiac/ide/library/LibraryManager.java @@ -45,6 +45,7 @@ import org.eclipse.core.resources.IPathVariableManager; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; @@ -54,6 +55,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.URIUtil; +import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobGroup; import org.eclipse.e4.core.contexts.EclipseContextFactory; @@ -124,6 +126,8 @@ public enum LibraryManager { private IEventBroker eventBroker; private JobGroup jobGroup; private boolean uninitialised = true; + private final IResourceChangeListener libraryListener = new LibraryChangeListener(); + private final Set resolvingProjects = Collections.synchronizedSet(new HashSet<>()); /** * Initialise library maps and start the {@link WatchService} @@ -157,6 +161,7 @@ private void init(final IProject project) { // empty } jobGroup = new JobGroup("LibraryManager JobGroup", 0, 0); //$NON-NLS-1$ + addLibraryChangeListener(); uninitialised = false; } @@ -370,6 +375,7 @@ public void importLibrary(final IProject project, final TypeLibrary typeLibrary, final IFolder libDirectory = project.getFolder(TYPE_LIB_FOLDER_NAME) .getFolder(libManifest.getProduct().getSymbolicName()); + removeLibraryChangeListener(); SystemManager.INSTANCE.removeFordiacChangeListener(); final Map cachedTypes = removeOldLibVersion(libDirectory, typeLib); final java.net.URI libUri = URIUtil.append(uri, LIB_TYPELIB_FOLDER_NAME); @@ -399,20 +405,10 @@ public void importLibrary(final IProject project, final TypeLibrary typeLibrary, } SystemManager.INSTANCE.addFordiacChangeListener(); + addLibraryChangeListener(); // dependency resolution if (resolve && imported) { - final WorkspaceJob job = new WorkspaceJob( - "Resolve dependencies for: " + libManifest.getProduct().getSymbolicName()) { //$NON-NLS-1$ - @Override - public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { - resolveDependencies(project, typeLib); - return Status.OK_STATUS; - } - }; - job.setRule(project); - job.setJobGroup(jobGroup); - job.setPriority(Job.LONG); - job.schedule(); + startResolveJob(project, typeLibrary); } } @@ -618,7 +614,7 @@ public void checkManifestFile(final IProject project, final TypeLibrary typeLibr ManifestHelper.sortAndSaveManifest(manifest); - startLocalResolveJob(project, typeLibrary); + startResolveJob(project, typeLibrary); } /** @@ -628,7 +624,12 @@ public void checkManifestFile(final IProject project, final TypeLibrary typeLibr * @param project selected project * @param typeLibrary {@link TypeLibrary} to use */ - private void startLocalResolveJob(final IProject project, final TypeLibrary typeLibrary) { + public void startResolveJob(final IProject project, final TypeLibrary typeLibrary) { + if (resolvingProjects.contains(project)) { + return; + } + resolvingProjects.add(project); + final WorkspaceJob job = new WorkspaceJob("Resolve dependencies: " + project.getName()) { //$NON-NLS-1$ @Override @@ -641,6 +642,8 @@ public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreExcepti job.setJobGroup(jobGroup); job.setPriority(Job.LONG); job.schedule(); + // act after job is done and has sent its POST_CHANGE notifications + job.addJobChangeListener(IJobChangeListener.onDone(c -> resolvingProjects.remove(project))); } /** @@ -1038,4 +1041,11 @@ public JobGroup getJobGroup() { } }; + public void removeLibraryChangeListener() { + ResourcesPlugin.getWorkspace().removeResourceChangeListener(libraryListener); + } + + public void addLibraryChangeListener() { + ResourcesPlugin.getWorkspace().addResourceChangeListener(libraryListener); + } } diff --git a/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/wizard/New4diacProjectWizard.java b/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/wizard/New4diacProjectWizard.java index 20cefeab70..fe3d97a8d1 100644 --- a/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/wizard/New4diacProjectWizard.java +++ b/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/wizard/New4diacProjectWizard.java @@ -19,14 +19,12 @@ import java.lang.reflect.InvocationTargetException; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.fordiac.ide.library.ui.wizards.LibrarySelectionPage; import org.eclipse.fordiac.ide.model.libraryElement.Application; import org.eclipse.fordiac.ide.model.libraryElement.AutomationSystem; -import org.eclipse.fordiac.ide.model.typelibrary.TypeLibraryManager; import org.eclipse.fordiac.ide.model.ui.actions.OpenListenerManager; import org.eclipse.fordiac.ide.systemmanagement.SystemManager; import org.eclipse.fordiac.ide.systemmanagement.ui.Messages; @@ -82,22 +80,13 @@ public void addPages() { @Override public boolean performFinish() { try { - WorkspaceModifyOperation op = new WorkspaceModifyOperation() { + final WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(final IProgressMonitor monitor) { createProject(monitor != null ? monitor : new NullProgressMonitor()); } }; getContainer().run(false, true, op); - // re-send TypeLibrary event after complete project setup - final IProject newProject = ResourcesPlugin.getWorkspace().getRoot().getProject(page.getProjectName()); - op = new WorkspaceModifyOperation() { - @Override - protected void execute(final IProgressMonitor monitor) { - TypeLibraryManager.INSTANCE.resendCreateEvent(newProject); - } - }; - getContainer().run(false, true, op); } catch (final InvocationTargetException e) { FordiacLogHelper.logError(e.getMessage(), e); return false;