blob: 953cb39681dd36ee0bd3f1e761c39e2e9ef35d87 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.tasklist.impl;
import org.netbeans.modules.tasklist.filter.TaskFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.netbeans.spi.tasklist.FileTaskScanner;
import org.netbeans.spi.tasklist.Task;
import org.openide.filesystems.FileObject;
import org.openide.util.Exceptions;
/**
*
* @author S. Aubrecht
*/
public class FileScanningWorker implements Runnable {
private TaskList taskList;
private boolean isCancel = false;
private Set<FileTaskScanner> preparedScanners = new HashSet<FileTaskScanner>();
private Iterator<FileObject> resourceIterator;
private Queue<FileObject> priorityResourceIterator = new LinkedList<FileObject>();
private Map<FileObject, Collection<FileTaskScanner>> priorityResource2scanner
= new HashMap<FileObject, Collection<FileTaskScanner>>();
private TaskFilter filter;
private final Object SCAN_LOCK = new Object();
private final Object SLEEP_LOCK = new Object();
/** Creates a new instance of Scanner */
public FileScanningWorker( TaskList taskList, TaskFilter filter ) {
this.taskList = taskList;
this.filter = filter;
}
public void scan( Iterator<FileObject> resources, TaskFilter filter ) {
abort();
synchronized( SLEEP_LOCK ) {
this.filter = filter;
List<? extends FileTaskScanner> providers = ScannerList.getFileScannerList().getScanners();
for( FileTaskScanner ts : providers ) {
if( filter.isEnabled( ts ) && !preparedScanners.contains( ts ) ) {
ts.notifyPrepare();
preparedScanners.add( ts );
}
}
this.resourceIterator = resources;
wakeup();
}
}
public void priorityScan( FileTaskScanner scanner, FileObject... res ) {
boolean wakeupNeeded = false;
synchronized( SCAN_LOCK ) {
wakeupNeeded = isCancel || !hasNext();
if( filter.isEnabled( scanner ) ) {
if( !preparedScanners.contains( scanner ) ) {
scanner.notifyPrepare();
preparedScanners.add( scanner );
}
for( FileObject rc : res ) {
Collection<FileTaskScanner> scanners = priorityResource2scanner.get( rc );
if( null == scanners ) {
scanners = new ArrayList<FileTaskScanner>( 10 );
priorityResource2scanner.put( rc, scanners );
}
if( !priorityResourceIterator.contains( rc ) ) {
priorityResourceIterator.offer( rc );
}
}
}
}
if( wakeupNeeded ) {
wakeup();
}
}
public void priorityScan( FileObject... res ) {
boolean wakeupNeeded = false;
synchronized( SCAN_LOCK ) {
wakeupNeeded = isCancel || !hasNext();
List<? extends FileTaskScanner> scanners = ScannerList.getFileScannerList().getScanners();
for( FileTaskScanner ts : scanners ) {
if( filter.isEnabled( ts ) && !preparedScanners.contains( ts ) ) {
ts.notifyPrepare();
preparedScanners.add( ts );
}
}
for( FileObject rc : res ) {
priorityResource2scanner.remove( rc );
if( !priorityResourceIterator.contains( rc ) ) {
priorityResourceIterator.offer( rc );
}
}
}
if( wakeupNeeded ) {
wakeup();
}
}
public void run() {
synchronized( SLEEP_LOCK ) {
while( true ) {
try {
if( killed ) {
return;
}
Set<FileTaskScanner> scannersToNotify = null;
ScanItem item = new ScanItem();
ScanMonitor monitor = ScanMonitor.getDefault();
while( true ) {
monitor.waitEnabled();
synchronized( SCAN_LOCK ) {
if( getNext( item ) ) {
if( !scan( item ) ) {
isCancel = true;
}
} else {
isCancel = true;
}
if( isCancel ) {
scannersToNotify = new HashSet<FileTaskScanner>( preparedScanners );
}
}
if( isCancel ) {
break;
}
}
cleanUp( scannersToNotify );
try {
SLEEP_LOCK.wait();
} catch( InterruptedException e ) {
//ignore
}
} catch (Exception e) {
Exceptions.printStackTrace(e);
}
}
}
}
private void wakeup() {
synchronized( SLEEP_LOCK ) {
isCancel = false;
SLEEP_LOCK.notifyAll();
}
}
void abort() {
isCancel = true;
}
private boolean killed = false;
void kill() {
abort();
killed = true;
wakeup();
}
private List<Task> scannedTasks = new LinkedList<Task>();
private boolean scan( ScanItem item ) {
if( isCancel )
return false;
boolean atLeastOneProviderIsActive = false;
for( FileTaskScanner scanner : item.scanners ) {
//check filter for enabled providers
if( !filter.isEnabled( scanner ) )
continue;
//check filter for visible items limit
if( filter.isTaskCountLimitReached( taskList.countTasks( scanner ) ) )
continue;
atLeastOneProviderIsActive = true;
scannedTasks.clear();
List<? extends Task> newTasks = null;
try {
if( item.resource.isValid() )
newTasks = scanner.scan( item.resource );
} catch( Throwable e ) {
//don't let uncaught exceptions break the thread synchronization
Exceptions.printStackTrace( e );
}
if (newTasks != null) {
scannedTasks.addAll( newTasks );
}
if( isCancel ) {
return false;
}
taskList.update( scanner, item.resource, scannedTasks, filter );
}
return atLeastOneProviderIsActive;
}
private void cleanUp( Set<FileTaskScanner> scannersToNotify ) {
synchronized( SCAN_LOCK ) {
resourceIterator = null;
priorityResourceIterator.clear();
priorityResource2scanner.clear();
}
notifyFinished( scannersToNotify );
}
private void notifyFinished( Set<FileTaskScanner> scannersToNotify ) {
if( null != scannersToNotify ) {
for( FileTaskScanner ts : scannersToNotify ) {
ts.notifyFinish();
}
}
preparedScanners.clear();
}
private boolean getNext( ScanItem item ) {
item.resource = priorityResourceIterator.poll();
item.scanners = preparedScanners;
if( null != item.resource ) {
item.scanners = priorityResource2scanner.get( item.resource );
if( null == item.scanners )
item.scanners = preparedScanners;
} else if( null != resourceIterator && resourceIterator.hasNext() ) {
item.resource = resourceIterator.next();
}
return null != item.resource;
}
private boolean hasNext() {
return priorityResourceIterator.size() > 0
|| (null != resourceIterator && resourceIterator.hasNext() );
}
private static class ScanItem {
FileObject resource;
Collection<FileTaskScanner> scanners;
}
}