| /******************************************************************************* |
| * Copyright (c) 2001, 2006 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.List; |
| import java.util.Map; |
| |
| 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.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 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 |
| */ |
| file.deleteMarkers(DEFAULT_MARKER_TYPE, 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); |
| } |
| } |
| } |
| |
| 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); |
| } |
| else { |
| scanMonitor.done(); |
| } |
| 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); |
| 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]); |
| } |
| 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(); |
| } |
| 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, (Map[]) markerAttributes.toArray(new Map[markerAttributes.size()]), markerUpdateMonitor); |
| } |
| else { |
| replaceTaskMarkers(file, null, 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); |
| } |
| } |