| /** |
| * 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; |
| } |
| } |