From 488333259338a48904541642f1e62e24f0931f53 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 1 Dec 2020 14:58:18 +0100 Subject: [PATCH 01/11] Issue #5086 Review and rework o.e.j.util.Scanner Signed-off-by: Jan Bartel --- .../eclipse/jetty/ant/ServerProxyImpl.java | 3 +- .../deploy/providers/ScanningAppProvider.java | 1 - ...ScanningAppProviderRuntimeUpdatesTest.java | 9 +- .../jetty/maven/plugin/JettyRunMojo.java | 4 +- .../jetty/maven/plugin/JettyRunWarMojo.java | 4 +- .../java/org/eclipse/jetty/util/Scanner.java | 503 ++++++++---------- .../jetty/util/ssl/KeyStoreScanner.java | 2 +- .../org/eclipse/jetty/util/ScannerTest.java | 77 +-- 8 files changed, 273 insertions(+), 330 deletions(-) diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java index e71da97c6576..f532858f2b2f 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.eclipse.jetty.ant.types.Connector; import org.eclipse.jetty.ant.types.ContextHandlers; @@ -135,7 +136,7 @@ public WebAppScannerListener(AntWebAppContext awc) } @Override - public void filesChanged(List changedFileNames) + public void filesChanged(Set changedFileNames) { boolean isScanned = false; try diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java index 3bffee94bc80..548015d5498f 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java @@ -140,7 +140,6 @@ protected void doStart() throws Exception _scanner = new Scanner(); _scanner.setScanDirs(files); _scanner.setScanInterval(_scanInterval); - _scanner.setRecursive(_recursive); _scanner.setFilenameFilter(_filenameFilter); _scanner.setReportDirs(true); _scanner.setScanDepth(1); //consider direct dir children of monitored dir diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java index 5a8c294fcc3b..38baeb7a7837 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java @@ -76,10 +76,15 @@ public void setupEnvironment() throws Exception if (provider instanceof ScanningAppProvider) { _providers++; - ((ScanningAppProvider)provider).addScannerListener(new Scanner.ScanListener() + ((ScanningAppProvider)provider).addScannerListener(new Scanner.ScanCycleListener() { @Override - public void scan() + public void scanStarted(int cycle) + { + } + + @Override + public void scanEnded(int cycle) { _scans.incrementAndGet(); } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java index 531a57d30001..4afc8f604ab4 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java @@ -22,7 +22,7 @@ import java.nio.file.Path; import java.nio.file.PathMatcher; import java.util.Date; -import java.util.List; +import java.util.Set; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; @@ -191,7 +191,7 @@ protected void configureScanner() } scanner.addListener(new Scanner.BulkListener() { - public void filesChanged(List changes) + public void filesChanged(Set changes) { try { diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java index 740ac9783158..35445b241d80 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java @@ -22,7 +22,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Date; -import java.util.List; +import java.util.Set; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Execute; @@ -197,7 +197,7 @@ public void configureScanner() throws MojoExecutionException configureScanTargetPatterns(scanner); scanner.addListener(new Scanner.BulkListener() { - public void filesChanged(List changes) + public void filesChanged(Set changes) { try { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index 7dddfa712b34..13cf41dcb424 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -28,22 +28,21 @@ import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; import org.eclipse.jetty.util.component.AbstractLifeCycle; -import org.eclipse.jetty.util.thread.AutoLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,27 +66,27 @@ public class Scanner extends AbstractLifeCycle private static final Logger LOG = LoggerFactory.getLogger(Scanner.class); private static int __scannerId = 0; - private final AutoLock _lock = new AutoLock(); private int _scanInterval; - private int _scanCount = 0; - private final List _listeners = new ArrayList<>(); - private final Map _prevScan = new HashMap<>(); - private final Map _currentScan = new HashMap<>(); + private AtomicInteger _scanCount = new AtomicInteger(0); + private final List _listeners = new CopyOnWriteArrayList<>(); + private Map _prevScan; private FilenameFilter _filter; - private final Map> _scannables = new HashMap<>(); - private volatile boolean _running = false; + private final Map> _scannables = new ConcurrentHashMap<>(); private boolean _reportExisting = true; private boolean _reportDirs = true; private Timer _timer; private TimerTask _task; private int _scanDepth = DEFAULT_SCAN_DEPTH; + public enum Status + { + ADDED, CHANGED, REMOVED, STABLE + } + public enum Notification { ADDED, CHANGED, REMOVED } - - private final Map _notifications = new HashMap<>(); /** * PathMatcherSet @@ -110,42 +109,43 @@ public boolean test(Path p) } /** - * TimeNSize + * MetaData * - * Metadata about a file: Last modified time and file size. + * Metadata about a file: Last modified time, file size and + * last file status (ADDED, CHANGED, DELETED) */ - static class TimeNSize + static class MetaData { final long _lastModified; final long _size; + Status _status; - public TimeNSize(long lastModified, long size) + public MetaData(long lastModified, long size) { _lastModified = lastModified; _size = size; } + + public void setStatus(Status status) + { + _status = status; + } @Override public int hashCode() { return (int)_lastModified ^ (int)_size; } - - @Override - public boolean equals(Object o) + + public boolean isModified(MetaData m) { - if (o instanceof TimeNSize) - { - TimeNSize tns = (TimeNSize)o; - return tns._lastModified == _lastModified && tns._size == _size; - } - return false; + return m._lastModified != _lastModified || m._size != _size; } @Override public String toString() { - return "[lm=" + _lastModified + ",s=" + _size + "]"; + return "[lm=" + _lastModified + ",sz=" + _size + ",s=" + _status + "]"; } } @@ -157,11 +157,11 @@ public String toString() */ class Visitor implements FileVisitor { - Map scanInfoMap; + Map scanInfoMap; IncludeExcludeSet rootIncludesExcludes; Path root; - public Visitor(Path root, IncludeExcludeSet rootIncludesExcludes, Map scanInfoMap) + public Visitor(Path root, IncludeExcludeSet rootIncludesExcludes, Map scanInfoMap) { this.root = root; this.rootIncludesExcludes = rootIncludesExcludes; @@ -195,7 +195,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th if (accepted) { - scanInfoMap.put(f.getCanonicalPath(), new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length())); + scanInfoMap.put(f.getCanonicalPath(), new MetaData(f.lastModified(), f.isDirectory() ? 0 : f.length())); if (LOG.isDebugEnabled()) LOG.debug("scan accepted dir {} mod={}", f, f.lastModified()); } } @@ -227,7 +227,7 @@ else if (_filter == null || _filter.accept(f.getParentFile(), f.getName())) if (accepted) { - scanInfoMap.put(f.getCanonicalPath(), new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length())); + scanInfoMap.put(f.getCanonicalPath(), new MetaData(f.lastModified(), f.isDirectory() ? 0 : f.length())); if (LOG.isDebugEnabled()) LOG.debug("scan accepted {} mod={}", f, f.lastModified()); } @@ -257,11 +257,10 @@ public interface Listener { } - public interface ScanListener extends Listener - { - public void scan(); - } - + /** + * Notification of exact file changes in the last scan. + * + */ public interface DiscreteListener extends Listener { public void fileChanged(String filename) throws Exception; @@ -271,9 +270,13 @@ public interface DiscreteListener extends Listener public void fileRemoved(String filename) throws Exception; } + /** + * Notification of files that changed in the last scan. + * + */ public interface BulkListener extends Listener { - public void filesChanged(List filenames) throws Exception; + public void filesChanged(Set filenames) throws Exception; } /** @@ -300,10 +303,7 @@ public Scanner() */ public int getScanInterval() { - try (AutoLock l = _lock.lock()) - { - return _scanInterval; - } + return _scanInterval; } /** @@ -312,44 +312,31 @@ public int getScanInterval() * @param scanInterval pause between scans in seconds, or 0 for no scan after the initial scan. */ public void setScanInterval(int scanInterval) - { - try (AutoLock l = _lock.lock()) - { - _scanInterval = scanInterval; - schedule(); - } + { + if (isRunning()) + throw new IllegalStateException("Scanner started"); + + _scanInterval = scanInterval; + schedule(); } - public void setScanDirs(List dirs) + public void setScanDirs(List dirs) throws IOException { + if (isRunning()) + throw new IllegalStateException("Scanner started"); + _scannables.clear(); if (dirs == null) return; - - for (File f:dirs) + for (File f :dirs) { - addScanDir(f); - } - } - - @Deprecated - public void addScanDir(File dir) - { - if (dir == null) - return; - try (AutoLock l = _lock.lock()) - { - if (dir.isDirectory()) - addDirectory(dir.toPath()); + if (f.isDirectory()) + addDirectory(f.toPath()); else - addFile(dir.toPath()); - } - catch (Exception e) - { - LOG.warn("Unable to add: {}", dir, e); + addFile(f.toPath()); } } - + /** * Add a file to be scanned. The file must not be null, and must exist. * @@ -358,6 +345,9 @@ public void addScanDir(File dir) */ public void addFile(Path p) throws IOException { + if (isRunning()) + throw new IllegalStateException("Scanner started"); + if (p == null) throw new IllegalStateException("Null path"); @@ -365,10 +355,7 @@ public void addFile(Path p) throws IOException if (!f.exists() || f.isDirectory()) throw new IllegalStateException("Not file or doesn't exist: " + f.getCanonicalPath()); - try (AutoLock l = _lock.lock()) - { - _scannables.put(p, null); - } + _scannables.putIfAbsent(p, null); } /** @@ -378,59 +365,60 @@ public void addFile(Path p) throws IOException * @return an IncludeExcludeSet to which the caller can add PathMatcher patterns to match * @throws IOException */ - public IncludeExcludeSet addDirectory(Path p) throws IOException + public IncludeExcludeSet addDirectory(Path p) { + if (isRunning()) + throw new IllegalStateException("Scanner started"); + if (p == null) throw new IllegalStateException("Null path"); File f = p.toFile(); if (!f.exists() || !f.isDirectory()) - throw new IllegalStateException("Not directory or doesn't exist: " + f.getCanonicalPath()); + throw new IllegalStateException("Not directory or doesn't exist: " + p); - try (AutoLock l = _lock.lock()) + try { - IncludeExcludeSet includesExcludes = _scannables.get(p); - if (includesExcludes == null) - { - includesExcludes = new IncludeExcludeSet<>(PathMatcherSet.class); - _scannables.put(p.toRealPath(), includesExcludes); - } + Path real = p.toRealPath(); + IncludeExcludeSet includesExcludes = new IncludeExcludeSet<>(PathMatcherSet.class); + IncludeExcludeSet prev = _scannables.putIfAbsent(real, includesExcludes); + if (prev != null) + includesExcludes = prev; return includesExcludes; } - } - - @Deprecated - public List getScanDirs() - { - ArrayList files = new ArrayList<>(); - for (Path p : _scannables.keySet()) - files.add(p.toFile()); - return Collections.unmodifiableList(files); + catch (IOException e) + { + throw new IllegalStateException(e); + } } - public Set getScannables() - { - return _scannables.keySet(); - } /** - * @param recursive True if scanning is recursive - * @see #setScanDepth(int) + * Apply a filter to files found in the scan directory. + * Only files matching the filter will be reported as added/changed/removed. + * + * @param filter the filename filter to use */ @Deprecated - public void setRecursive(boolean recursive) + public void setFilenameFilter(FilenameFilter filter) { - _scanDepth = recursive ? Integer.MAX_VALUE : 1; + _filter = filter; } /** - * @return True if scanning is recursive - * @see #getScanDepth() + * Get any filter applied to files in the scan dir. + * + * @return the filename filter */ @Deprecated - public boolean getRecursive() + public FilenameFilter getFilenameFilter() { - return _scanDepth > 1; + return _filter; + } + + public Set getScannables() + { + return Collections.unmodifiableSet(_scannables.keySet()); } /** @@ -450,32 +438,12 @@ public int getScanDepth() */ public void setScanDepth(int scanDepth) { + if (isRunning()) + throw new IllegalStateException("Scanner started"); + _scanDepth = scanDepth; } - /** - * Apply a filter to files found in the scan directory. - * Only files matching the filter will be reported as added/changed/removed. - * - * @param filter the filename filter to use - */ - @Deprecated - public void setFilenameFilter(FilenameFilter filter) - { - _filter = filter; - } - - /** - * Get any filter applied to files in the scan dir. - * - * @return the filename filter - */ - @Deprecated - public FilenameFilter getFilenameFilter() - { - return _filter; - } - /** * Whether or not an initial scan will report all files as being * added. @@ -485,6 +453,8 @@ public FilenameFilter getFilenameFilter() */ public void setReportExistingFilesOnStartup(boolean reportExisting) { + if (isRunning()) + throw new IllegalStateException("Scanner started"); _reportExisting = reportExisting; } @@ -500,6 +470,8 @@ public boolean getReportExistingFilesOnStartup() */ public void setReportDirs(boolean dirs) { + if (isRunning()) + throw new IllegalStateException("Scanner started"); _reportDirs = dirs; } @@ -517,10 +489,7 @@ public void addListener(Listener listener) { if (listener == null) return; - try (AutoLock l = _lock.lock()) - { - _listeners.add(listener); - } + _listeners.add(listener); } /** @@ -532,10 +501,7 @@ public void removeListener(Listener listener) { if (listener == null) return; - try (AutoLock l = _lock.lock()) - { - _listeners.remove(listener); - } + _listeners.remove(listener); } /** @@ -544,30 +510,22 @@ public void removeListener(Listener listener) @Override public void doStart() { - try (AutoLock l = _lock.lock()) - { - if (_running) - return; + if (LOG.isDebugEnabled()) + LOG.debug("Scanner start: rprtExists={}, depth={}, rprtDirs={}, interval={}, filter={}, scannables={}", + _reportExisting, _scanDepth, _reportDirs, _scanInterval, _filter, _scannables); - _running = true; - if (LOG.isDebugEnabled()) - LOG.debug("Scanner start: rprtExists={}, depth={}, rprtDirs={}, interval={}, filter={}, scannables={}", - _reportExisting, _scanDepth, _reportDirs, _scanInterval, _filter, _scannables); - - if (_reportExisting) - { - // if files exist at startup, report them - scan(); - scan(); // scan twice so files reported as stable - } - else - { - //just register the list of existing files and only report changes - scanFiles(); - _prevScan.putAll(_currentScan); - } - schedule(); + if (_reportExisting) + { + // if files exist at startup, report them + scan(); + scan(); // scan twice so files reported as stable } + else + { + //just register the list of existing files and only report changes + _prevScan = scanFiles(); + } + schedule(); } public TimerTask newTimerTask() @@ -589,7 +547,7 @@ public Timer newTimer() public void schedule() { - if (_running) + if (isRunning()) { if (_timer != null) _timer.cancel(); @@ -610,21 +568,14 @@ public void schedule() @Override public void doStop() { - try (AutoLock l = _lock.lock()) - { - if (_running) - { - _running = false; - if (_timer != null) - _timer.cancel(); - if (_task != null) - _task.cancel(); - _task = null; - _timer = null; - } - } + if (_timer != null) + _timer.cancel(); + if (_task != null) + _task.cancel(); + _task = null; + _timer = null; } - + /** * Clear the list of scannables. The scanner must first * be in the stopped state. @@ -633,13 +584,12 @@ public void reset() { if (!isStopped()) throw new IllegalStateException("Not stopped"); - + //clear the scannables _scannables.clear(); - + //clear the previous scans - _currentScan.clear(); - _prevScan.clear(); + _prevScan = null; } /** @@ -661,146 +611,116 @@ public boolean exists(String path) */ public void scan() { - try (AutoLock l = _lock.lock()) - { - reportScanStart(++_scanCount); - scanFiles(); - reportDifferences(_currentScan, _prevScan); - _prevScan.clear(); - _prevScan.putAll(_currentScan); - reportScanEnd(_scanCount); - - for (Listener listener : _listeners) - { - try - { - if (listener instanceof ScanListener) - ((ScanListener)listener).scan(); - } - catch (Throwable e) - { - LOG.warn("Unable to scan", e); - } - } - } + int cycle = _scanCount.incrementAndGet(); + reportScanStart(cycle); + Map currentScan = scanFiles(); + reportDifferences(currentScan, _prevScan == null ? Collections.emptyMap() : Collections.unmodifiableMap(_prevScan)); + _prevScan = currentScan; + reportScanEnd(cycle); } /** * Scan all of the given paths. */ - public void scanFiles() + public Map scanFiles() { - try (AutoLock l = _lock.lock()) + Map currentScan = new HashMap<>(); + for (Path p : _scannables.keySet()) { - _currentScan.clear(); - for (Path p : _scannables.keySet()) + try { - try - { - Files.walkFileTree(p, EnumSet.allOf(FileVisitOption.class),_scanDepth, new Visitor(p, _scannables.get(p), _currentScan)); - } - catch (IOException e) - { - LOG.warn("Error scanning files.", e); - } + Files.walkFileTree(p, EnumSet.allOf(FileVisitOption.class),_scanDepth, new Visitor(p, _scannables.get(p), currentScan)); + } + catch (IOException e) + { + LOG.warn("Error scanning files.", e); } } + return currentScan; } /** * Report the adds/changes/removes to the registered listeners + * + * Only report an add or change once a file has stablilized in size. * * @param currentScan the info from the most recent pass * @param oldScan info from the previous pass */ - private void reportDifferences(Map currentScan, Map oldScan) + private void reportDifferences(Map currentScan, Map oldScan) { - try (AutoLock l = _lock.lock()) + Map changes = new HashMap<>(); + + //Handle deleted files + Set oldScanKeys = new HashSet<>(oldScan.keySet()); + oldScanKeys.removeAll(currentScan.keySet()); + for (String file : oldScanKeys) { - // scan the differences and add what was found to the map of notifications: - Set oldScanKeys = new HashSet<>(oldScan.keySet()); + changes.put(file, Notification.REMOVED); + } - // Look for new and changed files - for (Entry entry : currentScan.entrySet()) + // Handle new and changed files + for (String file : currentScan.keySet()) + { + MetaData current = currentScan.get(file); + MetaData previous = oldScan.get(file); + + if (previous == null) { - String file = entry.getKey(); - if (!oldScanKeys.contains(file)) - { - Notification old = _notifications.put(file, Notification.ADDED); - if (old != null) - { - switch (old) - { - case REMOVED: - case CHANGED: - _notifications.put(file, Notification.CHANGED); - break; - default: - break; - } - } - } - else if (!oldScan.get(file).equals(currentScan.get(file))) - { - Notification old = _notifications.put(file, Notification.CHANGED); - if (old == Notification.ADDED) - _notifications.put(file, Notification.ADDED); - } + //New file - don't immediately + //notify this, wait until the size has + //settled down then notify the add. + current._status = Status.ADDED; } - - // Look for deleted files - for (String file : oldScan.keySet()) + else if (current.isModified(previous)) { - if (!currentScan.containsKey(file)) - { - Notification old = _notifications.put(file, Notification.REMOVED); - if (old == Notification.ADDED) - _notifications.remove(file); - } + //Changed file - handle case where file + //that was added on previous scan has since + //been modified. We need to retain status + //as added, so we send the ADDED event once + //the file has settled down. + if (previous._status == Status.ADDED) + current._status = Status.ADDED; + else + current._status = Status.CHANGED; + } + else + { + //Unchanged file: if it was previously + //ADDED, we can now send the ADDED event. + if (previous._status == Status.ADDED) + changes.put(file, Notification.ADDED); + else if (previous._status == Status.CHANGED) + changes.put(file, Notification.CHANGED); + + current._status = Status.STABLE; } + } - if (LOG.isDebugEnabled()) - LOG.debug("scanned {}: {}", _scannables.keySet(), _notifications); + if (LOG.isDebugEnabled()) + LOG.debug("scanned {}", _scannables.keySet()); - // Process notifications - // Only process notifications that are for stable files (ie same in old and current scan). - List bulkChanges = new ArrayList<>(); - for (Iterator> iter = _notifications.entrySet().iterator(); iter.hasNext(); ) + //Call the DiscreteListeners + for (Map.Entry entry : changes.entrySet()) + { + switch (entry.getValue()) { - - Entry entry = iter.next(); - String file = entry.getKey(); - // Is the file stable? - if (oldScan.containsKey(file)) - { - if (!oldScan.get(file).equals(currentScan.get(file))) - continue; - } - else if (currentScan.containsKey(file)) - continue; - - // File is stable so notify - Notification notification = entry.getValue(); - iter.remove(); - bulkChanges.add(file); - switch (notification) - { - case ADDED: - reportAddition(file); - break; - case CHANGED: - reportChange(file); - break; - case REMOVED: - reportRemoval(file); - break; - default: - break; - } + case ADDED: + reportAddition(entry.getKey()); + break; + case CHANGED: + reportChange(entry.getKey()); + break; + case REMOVED: + reportRemoval(entry.getKey()); + break; + default: + LOG.warn("Unknown file change: {}", entry.getValue()); + break; } - if (!bulkChanges.isEmpty()) - reportBulkChanges(bulkChanges); } + //Call the BulkListeners + reportBulkChanges(changes.keySet()); } private void warn(Object listener, String filename, Throwable th) @@ -857,6 +777,9 @@ private void reportRemoval(String filename) */ private void reportChange(String filename) { + if (filename == null) + return; + for (Listener l : _listeners) { try @@ -876,8 +799,11 @@ private void reportChange(String filename) * * @param filenames names of all files added/changed/removed */ - private void reportBulkChanges(List filenames) + private void reportBulkChanges(Set filenames) { + if (filenames == null || filenames.isEmpty()) + return; + for (Listener l : _listeners) { try @@ -902,9 +828,7 @@ private void reportScanStart(int cycle) try { if (listener instanceof ScanCycleListener) - { ((ScanCycleListener)listener).scanStarted(cycle); - } } catch (Exception e) { @@ -923,9 +847,8 @@ private void reportScanEnd(int cycle) try { if (listener instanceof ScanCycleListener) - { ((ScanCycleListener)listener).scanEnded(cycle); - } + } catch (Exception e) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java index 20ebfd1270c7..225c09a91305 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java @@ -77,7 +77,7 @@ public KeyStoreScanner(SslContextFactory sslContextFactory) throw new IllegalArgumentException("error obtaining keystore dir"); _scanner = new Scanner(); - _scanner.setScanDirs(Collections.singletonList(parentFile)); + _scanner.addDirectory(parentFile.toPath()); _scanner.setScanInterval(1); _scanner.setReportDirs(false); _scanner.setReportExistingFilesOnStartup(false); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java index 62a37f47587a..73ff025a35de 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java @@ -24,7 +24,7 @@ import java.io.OutputStream; import java.nio.file.Path; import java.nio.file.PathMatcher; -import java.util.List; +import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -42,6 +42,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.condition.OS.WINDOWS; @@ -49,8 +50,8 @@ public class ScannerTest { static File _directory; static Scanner _scanner; - static BlockingQueue _queue = new LinkedBlockingQueue(); - static BlockingQueue> _bulk = new LinkedBlockingQueue>(); + static BlockingQueue _queue = new LinkedBlockingQueue<>(); + static BlockingQueue> _bulk = new LinkedBlockingQueue<>(); @BeforeAll public static void setUpBeforeClass() throws Exception @@ -63,7 +64,7 @@ public static void setUpBeforeClass() throws Exception _directory = testDir.toPath().toRealPath().toFile(); _scanner = new Scanner(); - _scanner.addScanDir(_directory); + _scanner.addDirectory(_directory.toPath()); _scanner.setScanInterval(0); _scanner.setReportDirs(false); _scanner.setReportExistingFilesOnStartup(false); @@ -90,7 +91,7 @@ public void fileAdded(String filename) throws Exception _scanner.addListener(new Scanner.BulkListener() { @Override - public void filesChanged(List filenames) throws Exception + public void filesChanged(Set filenames) throws Exception { _bulk.add(filenames); } @@ -296,9 +297,9 @@ public void testAddedChangeRemove() throws Exception // not stable after 1 scan so should not be seen yet. _scanner.scan(); event = _queue.poll(); - assertTrue(event == null); + assertNull(event); - // Keep a2 unstable and remove a3 before it stabalized + // Keep a2 unstable and remove a3 before it stabilized Thread.sleep(1100); // make sure time in seconds changes touch("a2"); delete("a3"); @@ -306,21 +307,26 @@ public void testAddedChangeRemove() throws Exception // only a1 is stable so it should be seen. _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/a1", event._filename); assertEquals(Notification.ADDED, event._notification); - assertTrue(_queue.isEmpty()); + //TODO: behaviour change, we should see an immediate + //delete for a3 + event = _queue.poll(); + assertNotNull(event); + assertEquals(_directory + "/a3", event._filename); + assertEquals(Notification.REMOVED, event._notification); + assertTrue(_queue.isEmpty()); + // Now a2 is stable _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/a2", event._filename); assertEquals(Notification.ADDED, event._notification); assertTrue(_queue.isEmpty()); - // We never see a3 as it was deleted before it stabalised - // touch a1 and a2 Thread.sleep(1100); // make sure time in seconds changes touch("a1"); @@ -337,7 +343,7 @@ public void testAddedChangeRemove() throws Exception // only a1 is stable so it should be seen. _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/a1", event._filename); assertEquals(Notification.CHANGED, event._notification); assertTrue(_queue.isEmpty()); @@ -345,7 +351,7 @@ public void testAddedChangeRemove() throws Exception // Now a2 is stable _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/a2", event._filename); assertEquals(Notification.CHANGED, event._notification); assertTrue(_queue.isEmpty()); @@ -353,28 +359,37 @@ public void testAddedChangeRemove() throws Exception // delete a1 and a2 delete("a1"); delete("a2"); - // not stable after 1scan so nothing should not be seen yet. + + //TODO: behaviour change, now we get immediate notification of + //deletes. _scanner.scan(); + event = _queue.poll(); - assertTrue(event == null); - - // readd a2 + assertNotNull(event); + assertEquals(_directory + "/a1", event._filename); + assertEquals(Notification.REMOVED, event._notification); + event = _queue.poll(); + assertNotNull(event); + assertEquals(_directory + "/a2", event._filename); + assertEquals(Notification.REMOVED, event._notification); + assertTrue(_queue.isEmpty()); + + // recreate a2 touch("a2"); - // only a1 is stable so it should be seen. + // a2 not stable yet, shouldn't be seen _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); - assertEquals(_directory + "/a1", event._filename); - assertEquals(Notification.REMOVED, event._notification); + assertNull(event); assertTrue(_queue.isEmpty()); - // Now a2 is stable and is a changed file rather than a remove + //TODO: behaviour change, now a2 is reported as ADDED. Previously, a2 + //delete was not reported, but was reported as CHANGED when re-added. _scanner.scan(); event = _queue.poll(); assertTrue(event != null); assertEquals(_directory + "/a2", event._filename); - assertEquals(Notification.CHANGED, event._notification); + assertEquals(Notification.ADDED, event._notification); assertTrue(_queue.isEmpty()); } @@ -386,9 +401,9 @@ public void testSizeChange() throws Exception _scanner.scan(); _scanner.scan(); - // takes 2s to notice tsc0 and check that it is stable. This syncs us with the scan + // takes 2 scans to notice tsc0 and check that it is stable. Event event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/tsc0", event._filename); assertEquals(Notification.ADDED, event._notification); @@ -404,7 +419,7 @@ public void testSizeChange() throws Exception // Not stable yet so no notification. _scanner.scan(); event = _queue.poll(); - assertTrue(event == null); + assertNull(event); // Modify size only out.write('x'); @@ -414,12 +429,12 @@ public void testSizeChange() throws Exception // Still not stable yet so no notification. _scanner.scan(); event = _queue.poll(); - assertTrue(event == null); + assertNull(event); // now stable so finally see the ADDED _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/st", event._filename); assertEquals(Notification.ADDED, event._notification); @@ -431,12 +446,12 @@ public void testSizeChange() throws Exception // Still not stable yet so no notification. _scanner.scan(); event = _queue.poll(); - assertTrue(event == null); + assertNull(event); // now stable so finally see the ADDED _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/st", event._filename); assertEquals(Notification.CHANGED, event._notification); } From 4304c7861cf6a4cc5efdfbf286bd226f85b0d318 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 1 Dec 2020 15:55:45 +0100 Subject: [PATCH 02/11] Issue #5086 Improve ScannerTest Signed-off-by: Jan Bartel --- .../org/eclipse/jetty/util/ScannerTest.java | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java index 73ff025a35de..05677ffdfe44 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java @@ -24,6 +24,8 @@ import java.io.OutputStream; import java.nio.file.Path; import java.nio.file.PathMatcher; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -121,6 +123,20 @@ public Event(String filename, Notification notification) _filename = filename; _notification = notification; } + + @Override + public boolean equals(Object obj) + { + return ((Event)obj)._filename.equals(_filename) && ((Event)obj)._notification == _notification; + } + + @Override + public String toString() + { + return ("File: " + _filename + ":" + _notification); + } + + } @Test @@ -274,7 +290,6 @@ public void fileAdded(String filename) throws Exception @Test @DisabledOnOs(WINDOWS) // TODO: needs review - @DisabledIfSystemProperty(named = "env", matches = "ci") // TODO: SLOW, needs review public void testAddedChangeRemove() throws Exception { touch("a0"); @@ -304,19 +319,14 @@ public void testAddedChangeRemove() throws Exception touch("a2"); delete("a3"); - // only a1 is stable so it should be seen. + // only a1 is stable so it should be seen, a3 is deleted _scanner.scan(); - event = _queue.poll(); - assertNotNull(event); - assertEquals(_directory + "/a1", event._filename); - assertEquals(Notification.ADDED, event._notification); - - //TODO: behaviour change, we should see an immediate - //delete for a3 - event = _queue.poll(); - assertNotNull(event); - assertEquals(_directory + "/a3", event._filename); - assertEquals(Notification.REMOVED, event._notification); + List actualEvents = new ArrayList<>(); + _queue.drainTo(actualEvents); + assertEquals(2, actualEvents.size()); + Event a1 = new Event(_directory + "/a1", Notification.ADDED); + Event a3 = new Event(_directory + "/a3", Notification.REMOVED); + assertThat(actualEvents, Matchers.containsInAnyOrder(a1, a3)); assertTrue(_queue.isEmpty()); // Now a2 is stable @@ -360,18 +370,14 @@ public void testAddedChangeRemove() throws Exception delete("a1"); delete("a2"); - //TODO: behaviour change, now we get immediate notification of - //deletes. + //Immediate notification of deletes. _scanner.scan(); - - event = _queue.poll(); - assertNotNull(event); - assertEquals(_directory + "/a1", event._filename); - assertEquals(Notification.REMOVED, event._notification); - event = _queue.poll(); - assertNotNull(event); - assertEquals(_directory + "/a2", event._filename); - assertEquals(Notification.REMOVED, event._notification); + a1 = new Event(_directory + "/a1", Notification.REMOVED); + Event a2 = new Event(_directory + "/a2", Notification.REMOVED); + actualEvents = new ArrayList<>(); + _queue.drainTo(actualEvents); + assertEquals(2, actualEvents.size()); + assertThat(actualEvents, Matchers.containsInAnyOrder(a1, a2)); assertTrue(_queue.isEmpty()); // recreate a2 @@ -383,8 +389,7 @@ public void testAddedChangeRemove() throws Exception assertNull(event); assertTrue(_queue.isEmpty()); - //TODO: behaviour change, now a2 is reported as ADDED. Previously, a2 - //delete was not reported, but was reported as CHANGED when re-added. + //Now a2 is reported as ADDED. _scanner.scan(); event = _queue.poll(); assertTrue(event != null); From 115a72da6562646b5bbc8ffb3aafd6830d7a165f Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 1 Dec 2020 17:19:46 +0100 Subject: [PATCH 03/11] Issue #5086 Fix checkstyle in test Signed-off-by: Jan Bartel --- .../src/test/java/org/eclipse/jetty/util/ScannerTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java index 05677ffdfe44..09b5b0261d69 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java @@ -38,7 +38,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import org.junit.jupiter.api.condition.DisabledOnOs; import static org.hamcrest.MatcherAssert.assertThat; @@ -127,7 +126,7 @@ public Event(String filename, Notification notification) @Override public boolean equals(Object obj) { - return ((Event)obj)._filename.equals(_filename) && ((Event)obj)._notification == _notification; + return ((Event)obj)._filename.equals(_filename) && ((Event)obj)._notification == _notification; } @Override @@ -135,8 +134,6 @@ public String toString() { return ("File: " + _filename + ":" + _notification); } - - } @Test From 90e48ba0b5d6fa58aafbcb89d333e436f5455261 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 1 Dec 2020 17:44:33 +0100 Subject: [PATCH 04/11] Issue #5086 Fix javadoc Signed-off-by: Jan Bartel --- .../main/java/org/eclipse/jetty/util/Scanner.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index 13cf41dcb424..e2b6dfa8e89f 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -112,7 +112,7 @@ public boolean test(Path p) * MetaData * * Metadata about a file: Last modified time, file size and - * last file status (ADDED, CHANGED, DELETED) + * last file status (ADDED, CHANGED, DELETED, STABLE) */ static class MetaData { @@ -320,7 +320,7 @@ public void setScanInterval(int scanInterval) schedule(); } - public void setScanDirs(List dirs) throws IOException + public void setScanDirs(List dirs) { if (isRunning()) throw new IllegalStateException("Scanner started"); @@ -341,9 +341,8 @@ public void setScanDirs(List dirs) throws IOException * Add a file to be scanned. The file must not be null, and must exist. * * @param p the Path of the file to scan. - * @throws IOException */ - public void addFile(Path p) throws IOException + public void addFile(Path p) { if (isRunning()) throw new IllegalStateException("Scanner started"); @@ -353,7 +352,7 @@ public void addFile(Path p) throws IOException File f = p.toFile(); if (!f.exists() || f.isDirectory()) - throw new IllegalStateException("Not file or doesn't exist: " + f.getCanonicalPath()); + throw new IllegalStateException("Not file or doesn't exist: " + p); _scannables.putIfAbsent(p, null); } @@ -363,7 +362,6 @@ public void addFile(Path p) throws IOException * * @param p the directory to scan. * @return an IncludeExcludeSet to which the caller can add PathMatcher patterns to match - * @throws IOException */ public IncludeExcludeSet addDirectory(Path p) { @@ -820,6 +818,8 @@ private void reportBulkChanges(Set filenames) /** * Call ScanCycleListeners with start of scan + * + * @param cycle scan count */ private void reportScanStart(int cycle) { @@ -839,6 +839,8 @@ private void reportScanStart(int cycle) /** * Call ScanCycleListeners with end of scan. + * + * @param cycle scan count */ private void reportScanEnd(int cycle) { From 31cc29898758197f7a4c7643a4b353cc2ca2cbee Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 1 Dec 2020 22:05:33 +0100 Subject: [PATCH 05/11] Issue #5086 Changes after review Signed-off-by: Jan Bartel --- .../deploy/providers/ScanningAppProvider.java | 14 +-- .../java/org/eclipse/jetty/util/Scanner.java | 117 +++++++++--------- .../jetty/util/ssl/KeyStoreScanner.java | 5 +- .../org/eclipse/jetty/util/ScannerTest.java | 23 ++-- 4 files changed, 80 insertions(+), 79 deletions(-) diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java index 548015d5498f..b1153d809bce 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java @@ -54,7 +54,6 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements private DeploymentManager _deploymentManager; protected FilenameFilter _filenameFilter; private final List _monitored = new CopyOnWriteArrayList<>(); - private boolean _recursive = false; private int _scanInterval = 10; private Scanner _scanner; @@ -236,12 +235,6 @@ public int getScanInterval() return _scanInterval; } - @ManagedAttribute("recursive scanning supported") - public boolean isRecursive() - { - return _recursive; - } - @Override public void setDeploymentManager(DeploymentManager deploymentManager) { @@ -294,11 +287,6 @@ public void setMonitoredDirectories(Collection directories) } } - protected void setRecursive(boolean recursive) - { - _recursive = recursive; - } - public void setScanInterval(int scanInterval) { _scanInterval = scanInterval; @@ -311,7 +299,7 @@ public void scan() getMonitoredResources().stream().map((r) -> r.getURI().toASCIIString()) .collect(Collectors.joining(", ", "[", "]")) ); - _scanner.scan(); + _scanner.nudge(); } @Override diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index e2b6dfa8e89f..c322ecc1589c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -35,14 +35,15 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; import org.eclipse.jetty.util.component.AbstractLifeCycle; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; +import org.eclipse.jetty.util.thread.Scheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,15 +68,15 @@ public class Scanner extends AbstractLifeCycle private static int __scannerId = 0; private int _scanInterval; - private AtomicInteger _scanCount = new AtomicInteger(0); + private final AtomicInteger _scanCount = new AtomicInteger(0); private final List _listeners = new CopyOnWriteArrayList<>(); private Map _prevScan; private FilenameFilter _filter; private final Map> _scannables = new ConcurrentHashMap<>(); private boolean _reportExisting = true; private boolean _reportDirs = true; - private Timer _timer; - private TimerTask _task; + private Scheduler.Task _task; + private ScheduledExecutorScheduler _scheduler; private int _scanDepth = DEFAULT_SCAN_DEPTH; public enum Status @@ -114,7 +115,7 @@ public boolean test(Path p) * Metadata about a file: Last modified time, file size and * last file status (ADDED, CHANGED, DELETED, STABLE) */ - static class MetaData + private static class MetaData { final long _lastModified; final long _size; @@ -125,11 +126,6 @@ public MetaData(long lastModified, long size) _lastModified = lastModified; _size = size; } - - public void setStatus(Status status) - { - _status = status; - } @Override public int hashCode() @@ -148,6 +144,16 @@ public String toString() return "[lm=" + _lastModified + ",sz=" + _size + ",s=" + _status + "]"; } } + + private class ScanTask implements Runnable + { + @Override + public void run() + { + scan(); + schedule(); + } + } /** * Visitor @@ -183,9 +189,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th if (rootIncludesExcludes != null && !rootIncludesExcludes.isEmpty()) { //accepted if not explicitly excluded and either is explicitly included or there are no explicit inclusions - Boolean result = rootIncludesExcludes.test(dir); - if (Boolean.TRUE == result) - accepted = true; + accepted = rootIncludesExcludes.test(dir); } else { @@ -217,9 +221,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO if (rootIncludesExcludes != null && !rootIncludesExcludes.isEmpty()) { //accepted if not explicitly excluded and either is explicitly included or there are no explicit inclusions - Boolean result = rootIncludesExcludes.test(file); - if (Boolean.TRUE == result) - accepted = true; + accepted = rootIncludesExcludes.test(file); } else if (_filter == null || _filter.accept(f.getParentFile(), f.getName())) accepted = true; @@ -259,7 +261,6 @@ public interface Listener /** * Notification of exact file changes in the last scan. - * */ public interface DiscreteListener extends Listener { @@ -272,7 +273,6 @@ public interface DiscreteListener extends Listener /** * Notification of files that changed in the last scan. - * */ public interface BulkListener extends Listener { @@ -312,12 +312,11 @@ public int getScanInterval() * @param scanInterval pause between scans in seconds, or 0 for no scan after the initial scan. */ public void setScanInterval(int scanInterval) - { + { if (isRunning()) throw new IllegalStateException("Scanner started"); _scanInterval = scanInterval; - schedule(); } public void setScanDirs(List dirs) @@ -506,7 +505,7 @@ public void removeListener(Listener listener) * Start the scanning action. */ @Override - public void doStart() + public void doStart() throws Exception { if (LOG.isDebugEnabled()) LOG.debug("Scanner start: rprtExists={}, depth={}, rprtDirs={}, interval={}, filter={}, scannables={}", @@ -523,40 +522,21 @@ public void doStart() //just register the list of existing files and only report changes _prevScan = scanFiles(); } + + + //Create the scheduler and start it + _scheduler = new ScheduledExecutorScheduler("Scanner-" + __scannerId++, true, 1); + _scheduler.start(); + + //schedule the scan schedule(); } - public TimerTask newTimerTask() - { - return new TimerTask() - { - @Override - public void run() - { - scan(); - } - }; - } - - public Timer newTimer() - { - return new Timer("Scanner-" + __scannerId++, true); - } - - public void schedule() + private void schedule() { - if (isRunning()) + if (isRunning() && getScanInterval() > 0) { - if (_timer != null) - _timer.cancel(); - if (_task != null) - _task.cancel(); - if (getScanInterval() > 0) - { - _timer = newTimer(); - _task = newTimerTask(); - _timer.schedule(_task, 1010L * getScanInterval(), 1010L * getScanInterval()); - } + _task = _scheduler.schedule(new ScanTask(), 1010L * getScanInterval(), TimeUnit.MILLISECONDS); } } @@ -566,12 +546,20 @@ public void schedule() @Override public void doStop() { - if (_timer != null) - _timer.cancel(); + try + { + if (_scheduler != null) + _scheduler.stop(); + } + catch (Exception e) + { + LOG.warn("Error stopping scheduler", e); + } + if (_task != null) _task.cancel(); + _scheduler = null; _task = null; - _timer = null; } /** @@ -604,10 +592,27 @@ public boolean exists(String path) return false; } + /** + * Hint to the scanner to perform a scan cycle as soon as possible. + * NOTE that the scan is not guaranteed to have happened by the + * time this method returns. + */ + public void nudge() + { + if (!isRunning()) + throw new IllegalStateException("Scanner not running"); + + _scheduler.schedule(() -> + { + scan(); + + }, 0, TimeUnit.MILLISECONDS); + } + /** * Perform a pass of the scanner and report changes */ - public void scan() + void scan() { int cycle = _scanCount.incrementAndGet(); reportScanStart(cycle); @@ -620,7 +625,7 @@ public void scan() /** * Scan all of the given paths. */ - public Map scanFiles() + private Map scanFiles() { Map currentScan = new HashMap<>(); for (Path p : _scannables.keySet()) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java index 225c09a91305..097c4da8f207 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java @@ -20,7 +20,6 @@ import java.io.File; import java.io.IOException; -import java.util.Collections; import java.util.function.Consumer; import org.eclipse.jetty.util.Scanner; @@ -122,8 +121,8 @@ public void scan() if (LOG.isDebugEnabled()) LOG.debug("scanning"); - _scanner.scan(); - _scanner.scan(); + _scanner.nudge(); + _scanner.nudge(); } @ManagedOperation(value = "Reload the SSL Keystore", impact = "ACTION") diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java index 09b5b0261d69..93476a328bb3 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java @@ -26,6 +26,7 @@ import java.nio.file.PathMatcher; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -129,6 +130,12 @@ public boolean equals(Object obj) return ((Event)obj)._filename.equals(_filename) && ((Event)obj)._notification == _notification; } + @Override + public int hashCode() + { + return Objects.hash(_filename, _notification); + } + @Override public String toString() { @@ -278,8 +285,10 @@ public void fileAdded(String filename) throws Exception scanner.scan(); scanner.scan(); //2 scans for file to be considered settled - assertThat(queue.size(), Matchers.equalTo(2)); - for (Event e : queue) + List results = new ArrayList<>(); + queue.drainTo(results); + assertThat(results.size(), Matchers.equalTo(2)); + for (Event e : results) { assertTrue(e._filename.endsWith("ttt.txt") || e._filename.endsWith("xxx.txt")); } @@ -295,7 +304,7 @@ public void testAddedChangeRemove() throws Exception _scanner.scan(); _scanner.scan(); - Event event = _queue.poll(); + Event event = _queue.poll(5, TimeUnit.SECONDS); assertNotNull(event, "Event should not be null"); assertEquals(_directory + "/a0", event._filename); assertEquals(Notification.ADDED, event._notification); @@ -325,7 +334,7 @@ public void testAddedChangeRemove() throws Exception Event a3 = new Event(_directory + "/a3", Notification.REMOVED); assertThat(actualEvents, Matchers.containsInAnyOrder(a1, a3)); assertTrue(_queue.isEmpty()); - + // Now a2 is stable _scanner.scan(); event = _queue.poll(); @@ -366,7 +375,7 @@ public void testAddedChangeRemove() throws Exception // delete a1 and a2 delete("a1"); delete("a2"); - + //Immediate notification of deletes. _scanner.scan(); a1 = new Event(_directory + "/a1", Notification.REMOVED); @@ -376,7 +385,7 @@ public void testAddedChangeRemove() throws Exception assertEquals(2, actualEvents.size()); assertThat(actualEvents, Matchers.containsInAnyOrder(a1, a2)); assertTrue(_queue.isEmpty()); - + // recreate a2 touch("a2"); @@ -389,7 +398,7 @@ public void testAddedChangeRemove() throws Exception //Now a2 is reported as ADDED. _scanner.scan(); event = _queue.poll(); - assertTrue(event != null); + assertNotNull(event); assertEquals(_directory + "/a2", event._filename); assertEquals(Notification.ADDED, event._notification); assertTrue(_queue.isEmpty()); From e39ec6cab4c153d1c7e9fe03a956b0937975fc65 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 2 Dec 2020 08:02:09 +0100 Subject: [PATCH 06/11] Issue #5086 Fix error on addFile Signed-off-by: Jan Bartel --- .../java/org/eclipse/jetty/util/Scanner.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index c322ecc1589c..70fd1fc78276 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -349,11 +349,16 @@ public void addFile(Path p) if (p == null) throw new IllegalStateException("Null path"); - File f = p.toFile(); - if (!f.exists() || f.isDirectory()) + if (!Files.exists(p) || Files.isDirectory(p)) throw new IllegalStateException("Not file or doesn't exist: " + p); - - _scannables.putIfAbsent(p, null); + try + { + _scannables.putIfAbsent(p.toRealPath(), new IncludeExcludeSet<>(PathMatcherSet.class)); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } } /** @@ -370,15 +375,13 @@ public IncludeExcludeSet addDirectory(Path p) if (p == null) throw new IllegalStateException("Null path"); - File f = p.toFile(); - if (!f.exists() || !f.isDirectory()) + if (!Files.exists(p) || !Files.isDirectory(p)) throw new IllegalStateException("Not directory or doesn't exist: " + p); try { - Path real = p.toRealPath(); IncludeExcludeSet includesExcludes = new IncludeExcludeSet<>(PathMatcherSet.class); - IncludeExcludeSet prev = _scannables.putIfAbsent(real, includesExcludes); + IncludeExcludeSet prev = _scannables.putIfAbsent(p.toRealPath(), includesExcludes); if (prev != null) includesExcludes = prev; return includesExcludes; From 8fe8cb8c27c2f42802fd7b6623b8b284e65adbc7 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 2 Dec 2020 10:27:08 +0100 Subject: [PATCH 07/11] Issue #5086 Add blocking method for immediate scan. Signed-off-by: Jan Bartel --- .../java/org/eclipse/jetty/util/Scanner.java | 29 +++++++++++++++++++ .../jetty/util/ssl/KeyStoreScanner.java | 23 +++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index 70fd1fc78276..f9bd609f0959 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -611,7 +611,36 @@ public void nudge() }, 0, TimeUnit.MILLISECONDS); } + + /** + * Get the scanner to perform a scan cycle as soon as possible + * and call the Callback when the scan is finished or failed. + * + * @param complete called when the scan cycle finishes or fails. + */ + public void scan(Callback complete) + { + Scheduler s = _scheduler; + + if (!isRunning() || s == null) + complete.failed(new IllegalStateException("Scanner not running")); + + s.schedule(() -> + { + try + { + scan(); + complete.succeeded(); + } + catch (Throwable t) + { + complete.failed(t); + } + }, 0, TimeUnit.MILLISECONDS); + } + + /** * Perform a pass of the scanner and report changes */ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java index 097c4da8f207..46d04a21c923 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java @@ -20,8 +20,11 @@ import java.io.File; import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedOperation; @@ -121,8 +124,24 @@ public void scan() if (LOG.isDebugEnabled()) LOG.debug("scanning"); - _scanner.nudge(); - _scanner.nudge(); + try + { + CountDownLatch complete = new CountDownLatch(2); + Callback callback = Callback.from(complete::countDown, t -> + { + LOG.warn("Scan fail", t); + complete.countDown(); + }); + + _scanner.scan(callback); + _scanner.scan(callback); + complete.await(10, TimeUnit.SECONDS); + + } + catch (Exception e) + { + throw new RuntimeException(e); + } } @ManagedOperation(value = "Reload the SSL Keystore", impact = "ACTION") From 97b3f262ab9cbf7401765d8703e5a015decc1688 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 2 Dec 2020 12:53:23 +0100 Subject: [PATCH 08/11] Fixed scan(Callback) bug, returning early in case of failures. More cleanups in code adding more privateness, getting rid of unnecessary exceptions, making fields final, etc. Signed-off-by: Simone Bordet --- .../deploy/providers/ScanningAppProvider.java | 8 +- ...ScanningAppProviderRuntimeUpdatesTest.java | 5 -- .../java/org/eclipse/jetty/util/Scanner.java | 77 +++++++------------ .../jetty/util/ssl/KeyStoreScanner.java | 5 +- .../org/eclipse/jetty/util/ScannerTest.java | 42 +++++----- .../jetty/test/KeyStoreScannerTest.java | 2 +- 6 files changed, 54 insertions(+), 85 deletions(-) diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java index b1153d809bce..918ee18dba87 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java @@ -41,18 +41,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * - */ @ManagedObject("Abstract Provider for loading webapps") public abstract class ScanningAppProvider extends ContainerLifeCycle implements AppProvider { private static final Logger LOG = LoggerFactory.getLogger(ScanningAppProvider.class); - private Map _appMap = new HashMap(); - + private final Map _appMap = new HashMap<>(); private DeploymentManager _deploymentManager; - protected FilenameFilter _filenameFilter; + private FilenameFilter _filenameFilter; private final List _monitored = new CopyOnWriteArrayList<>(); private int _scanInterval = 10; private Scanner _scanner; diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java index 38baeb7a7837..19df28d42eca 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java @@ -78,11 +78,6 @@ public void setupEnvironment() throws Exception _providers++; ((ScanningAppProvider)provider).addScannerListener(new Scanner.ScanCycleListener() { - @Override - public void scanStarted(int cycle) - { - } - @Override public void scanEnded(int cycle) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index f9bd609f0959..b87de8978d5d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -59,13 +59,11 @@ public class Scanner extends AbstractLifeCycle * When walking a directory, a depth of 1 ensures that * the directory's descendants are visited, not just the * directory itself (as a file). - * - * @see Visitor#preVisitDirectory */ public static final int DEFAULT_SCAN_DEPTH = 1; public static final int MAX_SCAN_DEPTH = Integer.MAX_VALUE; private static final Logger LOG = LoggerFactory.getLogger(Scanner.class); - private static int __scannerId = 0; + private static final AtomicInteger __scannerId = new AtomicInteger(); private int _scanInterval; private final AtomicInteger _scanCount = new AtomicInteger(0); @@ -76,15 +74,15 @@ public class Scanner extends AbstractLifeCycle private boolean _reportExisting = true; private boolean _reportDirs = true; private Scheduler.Task _task; - private ScheduledExecutorScheduler _scheduler; + private Scheduler _scheduler; private int _scanDepth = DEFAULT_SCAN_DEPTH; - public enum Status + private enum Status { ADDED, CHANGED, REMOVED, STABLE } - public enum Notification + enum Notification { ADDED, CHANGED, REMOVED } @@ -127,12 +125,6 @@ public MetaData(long lastModified, long size) _size = size; } - @Override - public int hashCode() - { - return (int)_lastModified ^ (int)_size; - } - public boolean isModified(MetaData m) { return m._lastModified != _lastModified || m._size != _size; @@ -161,7 +153,7 @@ public void run() * A FileVisitor for walking a subtree of paths. The Scanner uses * this to examine the dirs and files it has been asked to scan. */ - class Visitor implements FileVisitor + private class Visitor implements FileVisitor { Map scanInfoMap; IncludeExcludeSet rootIncludesExcludes; @@ -284,14 +276,15 @@ public interface BulkListener extends Listener */ public interface ScanCycleListener extends Listener { - public void scanStarted(int cycle) throws Exception; + public default void scanStarted(int cycle) throws Exception + { + } - public void scanEnded(int cycle) throws Exception; + public default void scanEnded(int cycle) throws Exception + { + } } - /** - * - */ public Scanner() { } @@ -528,7 +521,7 @@ public void doStart() throws Exception //Create the scheduler and start it - _scheduler = new ScheduledExecutorScheduler("Scanner-" + __scannerId++, true, 1); + _scheduler = new ScheduledExecutorScheduler("Scanner-" + __scannerId.getAndIncrement(), true, 1); _scheduler.start(); //schedule the scan @@ -538,31 +531,23 @@ public void doStart() throws Exception private void schedule() { if (isRunning() && getScanInterval() > 0) - { _task = _scheduler.schedule(new ScanTask(), 1010L * getScanInterval(), TimeUnit.MILLISECONDS); - } } /** * Stop the scanning. */ @Override - public void doStop() + public void doStop() throws Exception { - try - { - if (_scheduler != null) - _scheduler.stop(); - } - catch (Exception e) - { - LOG.warn("Error stopping scheduler", e); - } - - if (_task != null) - _task.cancel(); - _scheduler = null; + Scheduler.Task task = _task; _task = null; + if (task != null) + task.cancel(); + Scheduler scheduler = _scheduler; + _scheduler = null; + if (scheduler != null) + scheduler.stop(); } /** @@ -604,12 +589,7 @@ public void nudge() { if (!isRunning()) throw new IllegalStateException("Scanner not running"); - - _scheduler.schedule(() -> - { - scan(); - - }, 0, TimeUnit.MILLISECONDS); + scan(Callback.NOOP); } /** @@ -620,12 +600,15 @@ public void nudge() */ public void scan(Callback complete) { - Scheduler s = _scheduler; + Scheduler scheduler = _scheduler; - if (!isRunning() || s == null) + if (!isRunning() || scheduler == null) + { complete.failed(new IllegalStateException("Scanner not running")); + return; + } - s.schedule(() -> + scheduler.schedule(() -> { try { @@ -636,11 +619,9 @@ public void scan(Callback complete) { complete.failed(t); } - - }, 0, TimeUnit.MILLISECONDS); + }, 0, TimeUnit.MILLISECONDS); } - - + /** * Perform a pass of the scanner and report changes */ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java index 46d04a21c923..23b6aa4f3ce3 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/KeyStoreScanner.java @@ -119,7 +119,7 @@ public void fileRemoved(String filename) } @ManagedOperation(value = "Scan for changes in the SSL Keystore", impact = "ACTION") - public void scan() + public boolean scan() { if (LOG.isDebugEnabled()) LOG.debug("scanning"); @@ -135,8 +135,7 @@ public void scan() _scanner.scan(callback); _scanner.scan(callback); - complete.await(10, TimeUnit.SECONDS); - + return complete.await(10, TimeUnit.SECONDS); } catch (Exception e) { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java index 93476a328bb3..8e38c6aa8c8a 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java @@ -73,31 +73,24 @@ public static void setUpBeforeClass() throws Exception _scanner.addListener(new Scanner.DiscreteListener() { @Override - public void fileRemoved(String filename) throws Exception + public void fileRemoved(String filename) { _queue.add(new Event(filename, Notification.REMOVED)); } @Override - public void fileChanged(String filename) throws Exception + public void fileChanged(String filename) { _queue.add(new Event(filename, Notification.CHANGED)); } @Override - public void fileAdded(String filename) throws Exception + public void fileAdded(String filename) { _queue.add(new Event(filename, Notification.ADDED)); } }); - _scanner.addListener(new Scanner.BulkListener() - { - @Override - public void filesChanged(Set filenames) throws Exception - { - _bulk.add(filenames); - } - }); + _scanner.addListener((Scanner.BulkListener)filenames -> _bulk.add(filenames)); _scanner.start(); _scanner.scan(); @@ -127,7 +120,12 @@ public Event(String filename, Notification notification) @Override public boolean equals(Object obj) { - return ((Event)obj)._filename.equals(_filename) && ((Event)obj)._notification == _notification; + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + Event that = (Event)obj; + return _filename.equals(that._filename) && _notification == that._notification; } @Override @@ -163,7 +161,7 @@ public void testDepth() throws Exception File y2 = new File(dir2, "yyy2.foo"); FS.touch(y2); - BlockingQueue queue = new LinkedBlockingQueue(); + BlockingQueue queue = new LinkedBlockingQueue<>(); Scanner scanner = new Scanner(); scanner.setScanInterval(0); scanner.setScanDepth(0); @@ -173,19 +171,19 @@ public void testDepth() throws Exception scanner.addListener(new Scanner.DiscreteListener() { @Override - public void fileRemoved(String filename) throws Exception + public void fileRemoved(String filename) { queue.add(new Event(filename, Notification.REMOVED)); } @Override - public void fileChanged(String filename) throws Exception + public void fileChanged(String filename) { queue.add(new Event(filename, Notification.CHANGED)); } @Override - public void fileAdded(String filename) throws Exception + public void fileAdded(String filename) { queue.add(new Event(filename, Notification.ADDED)); } @@ -243,7 +241,7 @@ public void testPatterns() throws Exception File y2 = new File(dir2, "yyy.txt"); FS.touch(y2); - BlockingQueue queue = new LinkedBlockingQueue(); + BlockingQueue queue = new LinkedBlockingQueue<>(); //only scan the *.txt files for changes Scanner scanner = new Scanner(); IncludeExcludeSet pattern = scanner.addDirectory(root.toPath()); @@ -256,19 +254,19 @@ public void testPatterns() throws Exception scanner.addListener(new Scanner.DiscreteListener() { @Override - public void fileRemoved(String filename) throws Exception + public void fileRemoved(String filename) { queue.add(new Event(filename, Notification.REMOVED)); } @Override - public void fileChanged(String filename) throws Exception + public void fileChanged(String filename) { queue.add(new Event(filename, Notification.CHANGED)); } @Override - public void fileAdded(String filename) throws Exception + public void fileAdded(String filename) { queue.add(new Event(filename, Notification.ADDED)); } @@ -350,7 +348,7 @@ public void testAddedChangeRemove() throws Exception // not stable after 1scan so nothing should not be seen yet. _scanner.scan(); event = _queue.poll(); - assertTrue(event == null); + assertNull(event); // Keep a2 unstable Thread.sleep(1100); // make sure time in seconds changes @@ -468,7 +466,7 @@ public void testSizeChange() throws Exception } } - private void delete(String string) throws IOException + private void delete(String string) { File file = new File(_directory, string); if (file.exists()) diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/KeyStoreScannerTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/KeyStoreScannerTest.java index 57b9390c9c98..8fb48f94f1d0 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/KeyStoreScannerTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/KeyStoreScannerTest.java @@ -126,7 +126,7 @@ public void testKeystoreHotReload() throws Exception // Switch to use newKeystore which has a later expiry date. useKeystore("newKeystore"); - keystoreScanner.scan(); + assertTrue(keystoreScanner.scan()); // The scanner should have detected the updated keystore, expiry should be renewed. X509Certificate cert2 = getCertificateFromServer(); From fe0e076055a02d4659a345cbef18a8d2ead07ad0 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 2 Dec 2020 17:47:56 +0100 Subject: [PATCH 09/11] Using capital case for static final field. Signed-off-by: Simone Bordet --- jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index b87de8978d5d..caba9bf7f54a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -63,7 +63,7 @@ public class Scanner extends AbstractLifeCycle public static final int DEFAULT_SCAN_DEPTH = 1; public static final int MAX_SCAN_DEPTH = Integer.MAX_VALUE; private static final Logger LOG = LoggerFactory.getLogger(Scanner.class); - private static final AtomicInteger __scannerId = new AtomicInteger(); + private static final AtomicInteger SCANNER_IDS = new AtomicInteger(); private int _scanInterval; private final AtomicInteger _scanCount = new AtomicInteger(0); @@ -521,7 +521,7 @@ public void doStart() throws Exception //Create the scheduler and start it - _scheduler = new ScheduledExecutorScheduler("Scanner-" + __scannerId.getAndIncrement(), true, 1); + _scheduler = new ScheduledExecutorScheduler("Scanner-" + SCANNER_IDS.getAndIncrement(), true, 1); _scheduler.start(); //schedule the scan From f0a2ab4fedef6bc062e833128abf2479ac9d927a Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 2 Dec 2020 18:21:18 +0100 Subject: [PATCH 10/11] Issue #5675 Update some osgi test dependencies (#5676) * Issue #5675 Update some osgi test dependencies Signed-off-by: Jan Bartel --- jetty-osgi/jetty-osgi-boot-jsp/pom.xml | 4 +- jetty-osgi/jetty-osgi-boot-warurl/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot/pom.xml | 7 +- jetty-osgi/jetty-osgi-httpservice/pom.xml | 2 +- jetty-osgi/pom.xml | 9 ++- jetty-osgi/test-jetty-osgi-context/pom.xml | 4 +- jetty-osgi/test-jetty-osgi-server/pom.xml | 4 +- jetty-osgi/test-jetty-osgi-webapp/pom.xml | 4 +- jetty-osgi/test-jetty-osgi/pom.xml | 78 ++++++++++++++++--- .../test/TestJettyOSGiAnnotationParser.java | 8 +- .../TestJettyOSGiBootWithAnnotations.java | 1 - .../TestJettyOSGiBootWithJavaxWebSocket.java | 5 +- .../test/TestJettyOSGiClasspathResources.java | 6 +- .../eclipse/jetty/osgi/test/TestOSGiUtil.java | 2 + 14 files changed, 97 insertions(+), 39 deletions(-) diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index e7b389449aca..f37b815c26db 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -23,11 +23,11 @@ provided - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index 68711d1b499c..34ac1ada51ab 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -18,7 +18,7 @@ jetty-util - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index a71677c60783..9da0d60dd08f 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -29,11 +29,11 @@ jetty-jmx - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services @@ -81,7 +81,8 @@ javax.transaction.xa;version="1.1.0";resolution:=optional, org.objectweb.asm;version="$(version;=;${asm.version})";resolution:=optional, org.osgi.framework, - org.osgi.service.cm;version="1.2.0", + org.osgi.service.cm;version="1.4.0", + org.osgi.service.event;version="1.4.0", org.osgi.service.packageadmin, org.osgi.service.startlevel;version="1.0.0", org.osgi.service.url;version="1.0.0", diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index fbbd0993190e..8a0281ec6709 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -25,7 +25,7 @@ servlet - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi provided diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index 6938f97d0063..44f799430d9b 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -12,8 +12,9 @@ pom - 3.6.0.v20100517 - 3.2.100.v20100503 + 3.16.0 + 3.9.0 + 3.5.300 1.0.0-v20070606 @@ -134,7 +135,7 @@ ${project.version} - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services ${osgi-services-version} @@ -151,7 +152,7 @@ - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi ${osgi-version} diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml index 35cee1f9b047..8b9042b26775 100644 --- a/jetty-osgi/test-jetty-osgi-context/pom.xml +++ b/jetty-osgi/test-jetty-osgi-context/pom.xml @@ -18,12 +18,12 @@ ${project.version} - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi provided - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services provided diff --git a/jetty-osgi/test-jetty-osgi-server/pom.xml b/jetty-osgi/test-jetty-osgi-server/pom.xml index 238a56c62ca4..5ac811ed6225 100644 --- a/jetty-osgi/test-jetty-osgi-server/pom.xml +++ b/jetty-osgi/test-jetty-osgi-server/pom.xml @@ -18,12 +18,12 @@ ${project.version} - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi provided - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services provided diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml index b13056f51573..704d39b62403 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml +++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml @@ -18,12 +18,12 @@ jetty-webapp - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi provided - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services provided diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 39f70d5688f6..d9c84977a7d2 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -14,7 +14,10 @@ https://download.eclipse.org/jetty/orbit/ target/distribution 4.13.1 - 2.6.1 + 2.6.2 + 5.2.0 + 1.8.3 + 3.0.0 1.2 @@ -37,17 +40,38 @@ pax-exam-container-forked ${exam.version} test + + + biz.aQute.bnd + bndlib + + + org.ops4j.pax.tinybundles + tinybundles + + + + + org.ops4j.pax.tinybundles + tinybundles + ${tinybundles.version} org.ops4j.pax.swissbox pax-swissbox-framework - 1.8.3 + ${swissbox.version} test + + + org.ops4j.base + ops4j-base-monitors + + org.ops4j.pax.swissbox pax-swissbox-tracker - 1.8.3 + ${swissbox.version} test @@ -71,13 +95,19 @@ org.ops4j.pax.url pax-url-wrap - 2.6.1 + ${url.version} test + + + biz.aQute.bnd + bndlib + + biz.aQute.bnd - bndlib - 2.4.0 + biz.aQute.bndlib + ${bnd.version} org.osgi @@ -88,13 +118,19 @@ org.eclipse.platform org.eclipse.osgi - 3.16.0 + ${osgi-version} test org.eclipse.platform org.eclipse.osgi.services - 3.9.0 + ${osgi-services-version} + test + + + org.eclipse.platform + org.eclipse.osgi.util + ${osgi-util-version} test @@ -106,11 +142,11 @@ test - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services @@ -122,11 +158,11 @@ test - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi - org.eclipse.osgi + org.eclipse.platform org.eclipse.osgi.services @@ -432,6 +468,24 @@ asm-commons test + + org.ow2.asm + asm-tree + test + ${asm.version} + + + org.ow2.asm + asm-analysis + test + ${asm.version} + + + org.ow2.asm + asm-util + test + ${asm.version} + org.eclipse.jetty.http2 http2-client diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiAnnotationParser.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiAnnotationParser.java index 688bdc6c5245..478b016d5d18 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiAnnotationParser.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiAnnotationParser.java @@ -25,14 +25,12 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; import aQute.bnd.osgi.Constants; import org.eclipse.jetty.annotations.ClassInheritanceHandler; import org.eclipse.jetty.osgi.annotations.AnnotationParser; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Configuration; @@ -46,6 +44,8 @@ import static org.junit.Assert.assertTrue; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; + + /** * TestJettyOSGiAnnotationParser * @@ -64,8 +64,8 @@ public static Option[] configure() options.add(TestOSGiUtil.optionalRemoteDebug()); options.add(CoreOptions.junitBundles()); options.addAll(TestOSGiUtil.coreJettyDependencies()); - options.add(mavenBundle().groupId("biz.aQute.bnd").artifactId("bndlib").versionAsInProject().start()); - options.add(mavenBundle().groupId("org.ops4j.pax.tinybundles").artifactId("tinybundles").version("2.1.1").start()); + options.add(mavenBundle().groupId("biz.aQute.bnd").artifactId("biz.aQute.bndlib").version("3.5.0").start()); + options.add(mavenBundle().groupId("org.ops4j.pax.tinybundles").artifactId("tinybundles").versionAsInProject().start()); return options.toArray(new Option[options.size()]); } diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java index ba97ba924ce0..c0e31db27575 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.osgi.test; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJavaxWebSocket.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJavaxWebSocket.java index 07f85b2dd5a7..67bef8a622ba 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJavaxWebSocket.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJavaxWebSocket.java @@ -93,8 +93,9 @@ public static List