blob: 2e91d4df51e6e20f18191b51fca6d5cfa05189d4 [file] [log] [blame]
/*=============================================================================#
# 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();
}
}