blob: 849516e6898c780cf37440954c74f723407f9d90 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2008 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.sse.core.internal.tasks;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.wst.sse.core.internal.Logger;
import org.eclipse.wst.sse.core.internal.provisional.tasks.IFileTaskScanner;
import org.eclipse.wst.sse.core.internal.provisional.tasks.TaskTag;
import org.eclipse.wst.sse.core.utils.StringUtils;
/**
* Dispatcher for scanning based on deltas and requested projects
*/
class WorkspaceTaskScanner {
private static WorkspaceTaskScanner _instance = null;
static synchronized WorkspaceTaskScanner getInstance() {
if (_instance == null) {
_instance = new WorkspaceTaskScanner();
}
return _instance;
}
final String DEFAULT_MARKER_TYPE = IFileTaskScanner.TASK_MARKER_ID;
private List fActiveScanners = null;
private IContentType[] fCurrentIgnoreContentTypes = null;
private TaskTag[] fCurrentTaskTags = null;
private FileTaskScannerRegistryReader registry = null;
private long time0;
/**
*
*/
private WorkspaceTaskScanner() {
super();
registry = FileTaskScannerRegistryReader.getInstance();
fActiveScanners = new ArrayList();
fCurrentTaskTags = new TaskTag[0];
fCurrentIgnoreContentTypes = new IContentType[0];
}
private IContentType[] detectContentTypes(IResource resource) {
IContentType[] types = null;
if (resource.getType() == IResource.FILE && resource.isAccessible()) {
types = Platform.getContentTypeManager().findContentTypesFor(resource.getName());
if (types.length == 0) {
IContentDescription d = null;
try {
// optimized description lookup, might not succeed
d = ((IFile) resource).getContentDescription();
if (d != null) {
types = new IContentType[]{d.getContentType()};
}
}
catch (CoreException e) {
/*
* should not be possible given the accessible and file
* type check above
*/
}
}
if (types == null) {
types = Platform.getContentTypeManager().findContentTypesFor(resource.getName());
}
if (Logger.DEBUG_TASKSCONTENTTYPE) {
if (types.length > 0) {
if (types.length > 1) {
System.out.println(resource.getFullPath() + ": " + "multiple based on name (probably hierarchical)"); //$NON-NLS-1$ //$NON-NLS-2$
}
for (int i = 0; i < types.length; i++) {
System.out.println(resource.getFullPath() + " matched: " + types[i].getId()); //$NON-NLS-1$
}
}
}
}
return types;
}
/**
* @param resource
* @return
*/
private IProject getProject(IResource resource) {
IProject project = null;
if (resource.getType() == IResource.PROJECT) {
project = (IProject) resource;
}
else {
project = resource.getProject();
}
return project;
}
private boolean init(IResource resource) {
IProject project = getProject(resource);
IPreferencesService preferencesService = Platform.getPreferencesService();
IScopeContext[] lookupOrder = new IScopeContext[]{new ProjectScope(project), new InstanceScope(), new DefaultScope()};
boolean proceed = preferencesService.getBoolean(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_ENABLE, false, lookupOrder);
if (Logger.DEBUG_TASKSPREFS) {
System.out.println(getClass().getName() + " scan of " + resource.getFullPath() + ":" + proceed); //$NON-NLS-1$ //$NON-NLS-2$
}
if (proceed) {
String[] tags = StringUtils.unpack(preferencesService.getString(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_TAGS, null, lookupOrder));
String[] priorities = StringUtils.unpack(preferencesService.getString(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_PRIORITIES, null, lookupOrder));
String[] currentIgnoreContentTypeIDs = StringUtils.unpack(preferencesService.getString(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_CONTENTTYPES_IGNORED, null, lookupOrder));
if (Logger.DEBUG_TASKSPREFS) {
System.out.print(getClass().getName() + " tags: "); //$NON-NLS-1$
for (int i = 0; i < tags.length; i++) {
if (i > 0) {
System.out.print(","); //$NON-NLS-1$
}
System.out.print(tags[i]);
}
System.out.println();
System.out.print(getClass().getName() + " priorities: "); //$NON-NLS-1$
for (int i = 0; i < priorities.length; i++) {
if (i > 0) {
System.out.print(","); //$NON-NLS-1$
}
System.out.print(priorities[i]);
}
System.out.println();
System.out.print(getClass().getName() + " ignored content types: "); //$NON-NLS-1$
for (int i = 0; i < currentIgnoreContentTypeIDs.length; i++) {
if (i > 0) {
System.out.print(","); //$NON-NLS-1$
}
System.out.print(currentIgnoreContentTypeIDs[i]);
}
System.out.println();
}
fCurrentIgnoreContentTypes = new IContentType[currentIgnoreContentTypeIDs.length];
IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
for (int i = 0; i < currentIgnoreContentTypeIDs.length; i++) {
fCurrentIgnoreContentTypes[i] = contentTypeManager.getContentType(currentIgnoreContentTypeIDs[i]);
}
int max = Math.min(tags.length, priorities.length);
fCurrentTaskTags = new TaskTag[max];
for (int i = 0; i < max; i++) {
int priority = TaskTag.PRIORITY_NORMAL;
try {
priority = Integer.parseInt(priorities[i]);
}
catch (NumberFormatException e) {
// default to normal priority
}
fCurrentTaskTags[i] = new TaskTag(tags[i], priority);
}
}
return proceed;
}
void internalScan(final IProject project, final IResource resource, final IProgressMonitor scanMonitor) {
if (scanMonitor.isCanceled())
return;
try {
String name = resource.getName();
if (resource.isAccessible() && !resource.isDerived() && !resource.isPhantom() && !resource.isTeamPrivateMember() && name.length() != 0 && name.charAt(0) != '.') {
if ((resource.getType() & IResource.FOLDER) > 0 || (resource.getType() & IResource.PROJECT) > 0) {
IResource[] children = ((IContainer) resource).members();
scanMonitor.beginTask("", children.length); //$NON-NLS-1$
for (int i = 0; i < children.length; i++) {
internalScan(project, children[i], new SubProgressMonitor(scanMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
}
scanMonitor.done();
}
else if ((resource.getType() & IResource.FILE) > 0) {
scanFile(project, fCurrentTaskTags, (IFile) resource, scanMonitor);
}
}
}
catch (CoreException e) {
Logger.logException(e);
}
}
void internalScan(IResourceDelta delta, final IProgressMonitor monitor) {
if (monitor.isCanceled())
return;
try {
String name = delta.getFullPath().lastSegment();
IResource resource = delta.getResource();
if (!resource.isDerived() && !resource.isPhantom() && !resource.isTeamPrivateMember() && name.length() != 0 && name.charAt(0) != '.') {
if ((resource.getType() & IResource.FOLDER) > 0 || (resource.getType() & IResource.PROJECT) > 0) {
IResourceDelta[] children = delta.getAffectedChildren();
monitor.beginTask("", children.length);
if (name.length() != 0 && name.charAt(0) != '.' && children.length > 0) {
for (int i = children.length - 1; i >= 0; i--) {
internalScan(children[i], new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
}
}
monitor.done();
}
else if ((resource.getType() & IResource.FILE) > 0) {
if ((delta.getKind() & IResourceDelta.ADDED) > 0 || ((delta.getKind() & IResourceDelta.CHANGED) > 0 && (delta.getFlags() & IResourceDelta.CONTENT) > 0)) {
IFile file = (IFile) resource;
scanFile(file.getProject(), fCurrentTaskTags, file, monitor);
}
}
}
}
catch (Exception e) {
Logger.logException(e);
}
}
private void replaceTaskMarkers(final IFile file, final String[] markerTypes, final Map markerAttributes[], IProgressMonitor monitor) {
final IFile finalFile = file;
if (file.isAccessible()) {
try {
IWorkspaceRunnable r = new IWorkspaceRunnable() {
public void run(IProgressMonitor progressMonitor) throws CoreException {
try {
/*
* Delete old Task markers (don't delete regular
* Tasks since that includes user-defined ones)
*/
for (int i = 0; i < markerTypes.length; i++) {
file.deleteMarkers(markerTypes[i], true, IResource.DEPTH_ZERO);
}
}
catch (CoreException e) {
Logger.logException("exception deleting old tasks", e); //$NON-NLS-1$
}
if (markerAttributes != null && markerAttributes.length > 0) {
if (Logger.DEBUG_TASKS) {
System.out.println("" + markerAttributes.length + " tasks for " + file.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
}
for (int i = 0; i < markerAttributes.length; i++) {
String specifiedMarkerType = (String) markerAttributes[i].get(IMarker.TASK);
IMarker marker = finalFile.createMarker(specifiedMarkerType != null ? specifiedMarkerType : DEFAULT_MARKER_TYPE);
marker.setAttributes(markerAttributes[i]);
}
}
}
};
if (file.isAccessible()) {
finalFile.getWorkspace().run(r, file, IWorkspace.AVOID_UPDATE, monitor);
}
}
catch (CoreException e1) {
Logger.logException(e1);
}
catch(OperationCanceledException e) {
// not an error condition
}
}
}
void scan(final IProject project, final IProgressMonitor scanMonitor) {
if (scanMonitor.isCanceled())
return;
if (Logger.DEBUG_TASKS) {
System.out.println(getClass().getName() + " scanning project " + project.getName()); //$NON-NLS-1$
}
if (!project.isAccessible()) {
if (Logger.DEBUG_TASKS) {
System.out.println(getClass().getName() + " skipping inaccessible project " + project.getName()); //$NON-NLS-1$
}
return;
}
if (Logger.DEBUG_TASKSOVERALLPERF) {
time0 = System.currentTimeMillis();
}
if (init(project)) {
internalScan(project, project, scanMonitor);
shutdownDelegates(project);
}
if (Logger.DEBUG_TASKSOVERALLPERF) {
System.out.println("" + (System.currentTimeMillis() - time0) + "ms for " + project.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
void scan(IResourceDelta delta, final IProgressMonitor monitor) {
if (monitor.isCanceled())
return;
if (Logger.DEBUG_TASKSOVERALLPERF) {
time0 = System.currentTimeMillis();
}
if (init(delta.getResource())) {
internalScan(delta, monitor);
shutdownDelegates(delta.getResource().getProject());
}
if (Logger.DEBUG_TASKSOVERALLPERF) {
System.out.println("" + (System.currentTimeMillis() - time0) + "ms for " + delta.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
void scanFile(IProject project, TaskTag[] taskTags, IFile file, IProgressMonitor monitor) {
if (monitor.isCanceled())
return;
// 3 "stages"
monitor.beginTask("", 3);
monitor.subTask(file.getFullPath().toString());
List markerAttributes = null;
IContentType[] types = detectContentTypes(file);
Set markerTypes = new HashSet(3);
// Always included for safety and migration
markerTypes.add(DEFAULT_MARKER_TYPE);
monitor.worked(1);
IFileTaskScanner[] fileScanners = null;
if (types != null) {
if (fCurrentIgnoreContentTypes.length == 0) {
fileScanners = registry.getFileTaskScanners(types);
}
else {
List validTypes = new ArrayList();
// obtain a filtered list of delegates
for (int i = 0; i < types.length; i++) {
boolean ignoreContentType = false;
for (int j = 0; j < fCurrentIgnoreContentTypes.length; j++) {
ignoreContentType = ignoreContentType || types[i].isKindOf(fCurrentIgnoreContentTypes[j]);
}
if (!ignoreContentType) {
validTypes.add(types[i]);
}
}
fileScanners = registry.getFileTaskScanners((IContentType[]) validTypes.toArray(new IContentType[validTypes.size()]));
}
if (fileScanners.length > 0) {
IProgressMonitor scannerMonitor = new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL);
scannerMonitor.beginTask("", fileScanners.length); //$NON-NLS-1$
for (int j = 0; fileScanners != null && j < fileScanners.length; j++) {
if (monitor.isCanceled())
continue;
try {
if (!fActiveScanners.contains(fileScanners[j]) && !monitor.isCanceled()) {
fileScanners[j].startup(file.getProject());
fActiveScanners.add(fileScanners[j]);
}
markerTypes.add(fileScanners[j].getMarkerType());
Map[] taskMarkerAttributes = fileScanners[j].scan(file, taskTags, new SubProgressMonitor(scannerMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
/*
* TODO: pool the marker results so there's only one
* operation creating them
*/
for (int i = 0; i < taskMarkerAttributes.length; i++) {
if (markerAttributes == null) {
markerAttributes = new ArrayList();
}
if (!taskMarkerAttributes[i].containsKey(IMarker.TASK)) {
taskMarkerAttributes[i].put(IMarker.TASK, fileScanners[j].getMarkerType());
}
markerAttributes.add(taskMarkerAttributes[i]);
}
}
catch (Exception e) {
Logger.logException(file.getFullPath().toString(), e);
}
}
scannerMonitor.done();
}
}
else {
monitor.worked(1);
}
if (monitor.isCanceled())
return;
// only update markers if we ran a scanner on this file
if (fileScanners != null && fileScanners.length > 0) {
IProgressMonitor markerUpdateMonitor = new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
if (markerAttributes != null) {
replaceTaskMarkers(file, (String[]) markerTypes.toArray(new String[markerTypes.size()]), (Map[]) markerAttributes.toArray(new Map[markerAttributes.size()]), markerUpdateMonitor);
}
}
else {
monitor.worked(1);
}
monitor.done();
}
private void shutdownDelegates(IProject project) {
for (int j = 0; j < fActiveScanners.size(); j++) {
try {
((IFileTaskScanner) fActiveScanners.get(j)).shutdown(project);
}
catch (Exception e) {
Logger.logException(project.getFullPath().toString(), e);
}
}
fActiveScanners = new ArrayList(1);
}
}