| /*=============================================================================# |
| # Copyright (c) 2014, 2020 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.eutils.autonature; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| import org.eclipse.core.resources.IFile; |
| 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.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.core.runtime.content.IContentDescription; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.osgi.util.NLS; |
| |
| |
| public class ResourceListener implements IResourceChangeListener, IResourceDeltaVisitor { |
| |
| |
| private final ConfigManager configManager; |
| |
| private final Map<IProject, List<AutoConfig>> projectConfigs; |
| |
| private final AtomicInteger counter= new AtomicInteger(); |
| |
| private final TaskProcessor taskProcessor= new TaskProcessor(); |
| |
| |
| public ResourceListener(final ConfigManager configManager) { |
| this.configManager= configManager; |
| this.projectConfigs= new HashMap<>(); |
| } |
| |
| |
| @Override |
| public void resourceChanged(final IResourceChangeEvent event) { |
| if (event.getType() == IResourceChangeEvent.POST_CHANGE |
| && this.configManager.hasActiveConfigs() ) { |
| this.counter.incrementAndGet(); |
| try { |
| event.getDelta().accept(this); |
| } |
| catch (final CoreException e) { |
| Activator.log(new Status(IStatus.ERROR, Activator.BUNDLE_ID, 0, |
| "An error occurred when checking for auto configuration tasks for changed resources.", |
| e )); |
| } |
| finally { |
| if (this.counter.decrementAndGet() == 0) { |
| scheduleTasks(); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public boolean visit(final IResourceDelta delta) throws CoreException { |
| IResource resource; |
| switch (delta.getKind()) { |
| case IResourceDelta.ADDED: |
| case IResourceDelta.CHANGED: |
| resource= delta.getResource(); |
| if (resource.getType() == IResource.FILE) { |
| checkFile((IFile) resource); |
| } |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| private void checkFile(final IFile file) { |
| try { |
| final IContentDescription description= file.getContentDescription(); |
| if (description == null) { |
| return; |
| } |
| final IContentType contentType= description.getContentType(); |
| if (contentType == null) { |
| return; |
| } |
| final AutoConfig config= this.configManager.getConfig(contentType, ConfigManager.AUTO_MODE); |
| if (config != null) { |
| addTasks(file.getProject(), config); |
| } |
| } |
| catch (final CoreException e) { |
| } |
| } |
| |
| private synchronized void addTasks(final IProject project, final AutoConfig config) { |
| List<AutoConfig> configs= this.projectConfigs.get(project); |
| if (configs == null) { |
| configs= new ArrayList<>(8); |
| this.projectConfigs.put(project, configs); |
| } |
| if (!configs.contains(config)) { |
| configs.add(config); |
| } |
| } |
| |
| private synchronized void scheduleTasks() { |
| if (this.projectConfigs.isEmpty()) { |
| return; |
| } |
| final List<Task> tasks= new ArrayList<>(); |
| for (final Entry<IProject, List<AutoConfig>> entry : this.projectConfigs.entrySet()) { |
| final IProject project= entry.getKey(); |
| try { |
| TaskProcessor.aggregateTasks(project, entry.getValue(), Task.CONTENT_MATCH, |
| tasks, null, null, |
| SubMonitor.convert(null) ); |
| |
| if (!tasks.isEmpty()) { |
| this.taskProcessor.add(project, tasks); |
| } |
| } |
| catch (final CoreException e) { |
| Activator.log(new Status(IStatus.ERROR, Activator.BUNDLE_ID, 0, |
| NLS.bind("An error occurred when aggregating auto configuration tasks for project ''{0}''", project), |
| e )); |
| } |
| finally { |
| tasks.clear(); |
| } |
| } |
| this.projectConfigs.clear(); |
| |
| this.taskProcessor.schedule(); |
| } |
| |
| } |