Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-10.0.x-5739-Remove-distribution-from-doco
This commit is contained in:
commit
41c2e9cb6d
|
@ -24,6 +24,7 @@ import java.net.MalformedURLException;
|
|||
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 class ServerProxyImpl implements ServerProxy
|
|||
}
|
||||
|
||||
@Override
|
||||
public void filesChanged(List<String> changedFileNames)
|
||||
public void filesChanged(Set<String> changedFileNames)
|
||||
{
|
||||
boolean isScanned = false;
|
||||
try
|
||||
|
|
|
@ -41,20 +41,15 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
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<String, App> _appMap = new HashMap<String, App>();
|
||||
|
||||
private final Map<String, App> _appMap = new HashMap<>();
|
||||
private DeploymentManager _deploymentManager;
|
||||
protected FilenameFilter _filenameFilter;
|
||||
private FilenameFilter _filenameFilter;
|
||||
private final List<Resource> _monitored = new CopyOnWriteArrayList<>();
|
||||
private boolean _recursive = false;
|
||||
private int _scanInterval = 10;
|
||||
private Scanner _scanner;
|
||||
|
||||
|
@ -140,7 +135,6 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
|
|||
_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
|
||||
|
@ -237,12 +231,6 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
|
|||
return _scanInterval;
|
||||
}
|
||||
|
||||
@ManagedAttribute("recursive scanning supported")
|
||||
public boolean isRecursive()
|
||||
{
|
||||
return _recursive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeploymentManager(DeploymentManager deploymentManager)
|
||||
{
|
||||
|
@ -295,11 +283,6 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
|
|||
}
|
||||
}
|
||||
|
||||
protected void setRecursive(boolean recursive)
|
||||
{
|
||||
_recursive = recursive;
|
||||
}
|
||||
|
||||
public void setScanInterval(int scanInterval)
|
||||
{
|
||||
_scanInterval = scanInterval;
|
||||
|
@ -312,7 +295,7 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
|
|||
getMonitoredResources().stream().map((r) -> r.getURI().toASCIIString())
|
||||
.collect(Collectors.joining(", ", "[", "]"))
|
||||
);
|
||||
_scanner.scan();
|
||||
_scanner.nudge();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -76,10 +76,10 @@ public class ScanningAppProviderRuntimeUpdatesTest
|
|||
if (provider instanceof ScanningAppProvider)
|
||||
{
|
||||
_providers++;
|
||||
((ScanningAppProvider)provider).addScannerListener(new Scanner.ScanListener()
|
||||
((ScanningAppProvider)provider).addScannerListener(new Scanner.ScanCycleListener()
|
||||
{
|
||||
@Override
|
||||
public void scan()
|
||||
public void scanEnded(int cycle)
|
||||
{
|
||||
_scans.incrementAndGet();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.io.File;
|
|||
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 @@ public class JettyRunMojo extends AbstractUnassembledWebAppMojo
|
|||
}
|
||||
scanner.addListener(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(List<String> changes)
|
||||
public void filesChanged(Set<String> changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.io.IOException;
|
|||
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 class JettyRunWarMojo extends AbstractWebAppMojo
|
|||
configureScanTargetPatterns(scanner);
|
||||
scanner.addListener(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(List<String> changes)
|
||||
public void filesChanged(Set<String> changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
<!-- Servlet Deps -->
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<artifactId>jetty-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
<artifactId>jetty-jmx</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -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",
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<artifactId>servlet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<osgi-version>3.7.1</osgi-version>
|
||||
<osgi-services-version>3.2.100.v20100503</osgi-services-version>
|
||||
<osgi-version>3.16.0</osgi-version>
|
||||
<osgi-services-version>3.9.0</osgi-services-version>
|
||||
<osgi-util-version>3.5.300</osgi-util-version>
|
||||
<equinox-http-servlet-version>1.0.0-v20070606</equinox-http-servlet-version>
|
||||
</properties>
|
||||
|
||||
|
@ -129,7 +130,7 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<version>${osgi-services-version}</version>
|
||||
<exclusions>
|
||||
|
@ -146,7 +147,7 @@
|
|||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<version>${osgi-version}</version>
|
||||
</dependency>
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
<artifactId>jetty-webapp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
<jetty-orbit-url>https://download.eclipse.org/jetty/orbit/</jetty-orbit-url>
|
||||
<assembly-directory>target/distribution</assembly-directory>
|
||||
<pax.exam.version>4.13.1</pax.exam.version>
|
||||
<pax.url.version>2.6.1</pax.url.version>
|
||||
<pax.url.version>2.6.2</pax.url.version>
|
||||
<bnd.version>5.2.0</bnd.version>
|
||||
<swissbox.version>1.8.3</swissbox.version>
|
||||
<tinybundles.version>3.0.0</tinybundles.version>
|
||||
<injection.bundle.version>1.2</injection.bundle.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
@ -42,18 +45,33 @@
|
|||
<groupId>biz.aQute.bnd</groupId>
|
||||
<artifactId>bndlib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.ops4j.pax.tinybundles</groupId>
|
||||
<artifactId>tinybundles</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ops4j.pax.tinybundles</groupId>
|
||||
<artifactId>tinybundles</artifactId>
|
||||
<version>${tinybundles.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ops4j.pax.swissbox</groupId>
|
||||
<artifactId>pax-swissbox-framework</artifactId>
|
||||
<version>1.8.3</version>
|
||||
<version>${swissbox.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.ops4j.base</groupId>
|
||||
<artifactId>ops4j-base-monitors</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ops4j.pax.swissbox</groupId>
|
||||
<artifactId>pax-swissbox-tracker</artifactId>
|
||||
<version>1.8.3</version>
|
||||
<version>${swissbox.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -89,7 +107,7 @@
|
|||
<dependency>
|
||||
<groupId>biz.aQute.bnd</groupId>
|
||||
<artifactId>biz.aQute.bndlib</artifactId>
|
||||
<version>5.1.2</version>
|
||||
<version>${bnd.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.osgi</groupId>
|
||||
|
@ -100,13 +118,19 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<version>3.16.0</version>
|
||||
<version>${osgi-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<version>${osgi-services-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.util</artifactId>
|
||||
<version>${osgi-util-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
@ -124,11 +148,11 @@
|
|||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
|
@ -140,11 +164,11 @@
|
|||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
|
@ -458,6 +482,24 @@
|
|||
<scope>test</scope>
|
||||
<version>${asm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-tree</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${asm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-analysis</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${asm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-util</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${asm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-client</artifactId>
|
||||
|
|
|
@ -26,14 +26,12 @@ import java.nio.file.Path;
|
|||
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;
|
||||
|
@ -47,6 +45,8 @@ import org.osgi.framework.BundleContext;
|
|||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
|
||||
|
||||
|
||||
/**
|
||||
* TestJettyOSGiAnnotationParser
|
||||
*
|
||||
|
@ -65,7 +65,7 @@ public class TestJettyOSGiAnnotationParser
|
|||
options.add(TestOSGiUtil.optionalRemoteDebug());
|
||||
options.add(CoreOptions.junitBundles());
|
||||
options.addAll(TestOSGiUtil.coreJettyDependencies());
|
||||
|
||||
|
||||
//get a reference to a pre-prepared module-info
|
||||
Path path = Paths.get("src", "test", "resources", "module-info.clazz");
|
||||
File moduleInfo = path.toFile();
|
||||
|
|
|
@ -91,7 +91,9 @@ public class TestJettyOSGiBootWithJavaxWebSocket
|
|||
public static List<Option> extraDependencies()
|
||||
{
|
||||
List<Option> res = new ArrayList<>();
|
||||
res.add(mavenBundle().groupId("biz.aQute.bnd").artifactId("biz.aQute.bndlib").versionAsInProject().start());
|
||||
//Need an earlier version of bndlib because of tinybundles
|
||||
res.add(mavenBundle().groupId("biz.aQute.bnd").artifactId("biz.aQute.bndlib").version("3.5.0").start());
|
||||
res.add(mavenBundle().groupId("org.ops4j.pax.tinybundles").artifactId("tinybundles").versionAsInProject().start());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@ import org.osgi.framework.BundleContext;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
|
||||
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
|
||||
|
||||
|
@ -75,8 +74,8 @@ public class TestJettyOSGiClasspathResources
|
|||
options.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-client").versionAsInProject().start());
|
||||
|
||||
//Note: we have to back down the version of bnd used here because tinybundles expects only this version
|
||||
options.add(mavenBundle().groupId("biz.aQute.bnd").artifactId("bndlib").version("2.4.0").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());
|
||||
options.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("test-jetty-osgi-webapp-resources").type("war").versionAsInProject());
|
||||
options.add(CoreOptions.cleanCaches(true));
|
||||
return options.toArray(new Option[options.size()]);
|
||||
|
|
|
@ -155,6 +155,8 @@ public class TestOSGiUtil
|
|||
loggingPropertiesBundle.add(FragmentActivator.class);
|
||||
res.add(CoreOptions.streamBundle(loggingPropertiesBundle.build()).noStart());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.toolchain").artifactId("jetty-servlet-api").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.platform").artifactId("org.eclipse.osgi.util").versionAsInProject());
|
||||
res.add(mavenBundle().groupId("org.eclipse.platform").artifactId("org.eclipse.osgi.services").versionAsInProject());
|
||||
res.add(mavenBundle().groupId("org.ow2.asm").artifactId("asm").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.ow2.asm").artifactId("asm-commons").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.ow2.asm").artifactId("asm-tree").versionAsInProject().start());
|
||||
|
|
|
@ -28,22 +28,22 @@ import java.nio.file.Files;
|
|||
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.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.AutoLock;
|
||||
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -59,35 +59,33 @@ 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 SCANNER_IDS = new AtomicInteger();
|
||||
|
||||
private final AutoLock _lock = new AutoLock();
|
||||
private int _scanInterval;
|
||||
private int _scanCount = 0;
|
||||
private final List<Listener> _listeners = new ArrayList<>();
|
||||
private final Map<String, TimeNSize> _prevScan = new HashMap<>();
|
||||
private final Map<String, TimeNSize> _currentScan = new HashMap<>();
|
||||
private final AtomicInteger _scanCount = new AtomicInteger(0);
|
||||
private final List<Listener> _listeners = new CopyOnWriteArrayList<>();
|
||||
private Map<String, MetaData> _prevScan;
|
||||
private FilenameFilter _filter;
|
||||
private final Map<Path, IncludeExcludeSet<PathMatcher, Path>> _scannables = new HashMap<>();
|
||||
private volatile boolean _running = false;
|
||||
private final Map<Path, IncludeExcludeSet<PathMatcher, Path>> _scannables = new ConcurrentHashMap<>();
|
||||
private boolean _reportExisting = true;
|
||||
private boolean _reportDirs = true;
|
||||
private Timer _timer;
|
||||
private TimerTask _task;
|
||||
private Scheduler.Task _task;
|
||||
private Scheduler _scheduler;
|
||||
private int _scanDepth = DEFAULT_SCAN_DEPTH;
|
||||
|
||||
public enum Notification
|
||||
private enum Status
|
||||
{
|
||||
ADDED, CHANGED, REMOVED, STABLE
|
||||
}
|
||||
|
||||
enum Notification
|
||||
{
|
||||
ADDED, CHANGED, REMOVED
|
||||
}
|
||||
|
||||
private final Map<String, Notification> _notifications = new HashMap<>();
|
||||
|
||||
/**
|
||||
* PathMatcherSet
|
||||
|
@ -110,42 +108,42 @@ public class Scanner extends AbstractLifeCycle
|
|||
}
|
||||
|
||||
/**
|
||||
* 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, STABLE)
|
||||
*/
|
||||
static class TimeNSize
|
||||
private 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
public boolean isModified(MetaData m)
|
||||
{
|
||||
return (int)_lastModified ^ (int)_size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
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 + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private class ScanTask implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
scan();
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,13 +153,13 @@ public class Scanner extends AbstractLifeCycle
|
|||
* 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<Path>
|
||||
private class Visitor implements FileVisitor<Path>
|
||||
{
|
||||
Map<String, TimeNSize> scanInfoMap;
|
||||
Map<String, MetaData> scanInfoMap;
|
||||
IncludeExcludeSet<PathMatcher,Path> rootIncludesExcludes;
|
||||
Path root;
|
||||
|
||||
public Visitor(Path root, IncludeExcludeSet<PathMatcher,Path> rootIncludesExcludes, Map<String, TimeNSize> scanInfoMap)
|
||||
public Visitor(Path root, IncludeExcludeSet<PathMatcher,Path> rootIncludesExcludes, Map<String, MetaData> scanInfoMap)
|
||||
{
|
||||
this.root = root;
|
||||
this.rootIncludesExcludes = rootIncludesExcludes;
|
||||
|
@ -183,9 +181,7 @@ public class Scanner extends AbstractLifeCycle
|
|||
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
|
||||
{
|
||||
|
@ -195,7 +191,7 @@ public class Scanner extends AbstractLifeCycle
|
|||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -217,9 +213,7 @@ public class Scanner extends AbstractLifeCycle
|
|||
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;
|
||||
|
@ -227,7 +221,7 @@ public class Scanner extends AbstractLifeCycle
|
|||
|
||||
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 +251,9 @@ public class Scanner extends AbstractLifeCycle
|
|||
{
|
||||
}
|
||||
|
||||
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 +263,12 @@ public class Scanner extends AbstractLifeCycle
|
|||
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<String> filenames) throws Exception;
|
||||
public void filesChanged(Set<String> filenames) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,14 +276,15 @@ public class Scanner extends AbstractLifeCycle
|
|||
*/
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
@ -300,10 +296,7 @@ public class Scanner extends AbstractLifeCycle
|
|||
*/
|
||||
public int getScanInterval()
|
||||
{
|
||||
try (AutoLock l = _lock.lock())
|
||||
{
|
||||
return _scanInterval;
|
||||
}
|
||||
return _scanInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -313,61 +306,51 @@ public class Scanner extends AbstractLifeCycle
|
|||
*/
|
||||
public void setScanInterval(int scanInterval)
|
||||
{
|
||||
try (AutoLock l = _lock.lock())
|
||||
{
|
||||
_scanInterval = scanInterval;
|
||||
schedule();
|
||||
}
|
||||
if (isRunning())
|
||||
throw new IllegalStateException("Scanner started");
|
||||
|
||||
_scanInterval = scanInterval;
|
||||
}
|
||||
|
||||
public void setScanDirs(List<File> dirs)
|
||||
{
|
||||
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.
|
||||
*
|
||||
* @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");
|
||||
|
||||
if (p == null)
|
||||
throw new IllegalStateException("Null path");
|
||||
|
||||
File f = p.toFile();
|
||||
if (!f.exists() || f.isDirectory())
|
||||
throw new IllegalStateException("Not file or doesn't exist: " + f.getCanonicalPath());
|
||||
|
||||
try (AutoLock l = _lock.lock())
|
||||
if (!Files.exists(p) || Files.isDirectory(p))
|
||||
throw new IllegalStateException("Not file or doesn't exist: " + p);
|
||||
try
|
||||
{
|
||||
_scannables.put(p, null);
|
||||
_scannables.putIfAbsent(p.toRealPath(), new IncludeExcludeSet<>(PathMatcherSet.class));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,82 +359,32 @@ public class Scanner extends AbstractLifeCycle
|
|||
*
|
||||
* @param p the directory to scan.
|
||||
* @return an IncludeExcludeSet to which the caller can add PathMatcher patterns to match
|
||||
* @throws IOException
|
||||
*/
|
||||
public IncludeExcludeSet<PathMatcher, Path> addDirectory(Path p) throws IOException
|
||||
public IncludeExcludeSet<PathMatcher, Path> 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());
|
||||
if (!Files.exists(p) || !Files.isDirectory(p))
|
||||
throw new IllegalStateException("Not directory or doesn't exist: " + p);
|
||||
|
||||
try (AutoLock l = _lock.lock())
|
||||
try
|
||||
{
|
||||
IncludeExcludeSet<PathMatcher, Path> includesExcludes = _scannables.get(p);
|
||||
if (includesExcludes == null)
|
||||
{
|
||||
includesExcludes = new IncludeExcludeSet<>(PathMatcherSet.class);
|
||||
_scannables.put(p.toRealPath(), includesExcludes);
|
||||
}
|
||||
IncludeExcludeSet<PathMatcher, Path> includesExcludes = new IncludeExcludeSet<>(PathMatcherSet.class);
|
||||
IncludeExcludeSet<PathMatcher, Path> prev = _scannables.putIfAbsent(p.toRealPath(), includesExcludes);
|
||||
if (prev != null)
|
||||
includesExcludes = prev;
|
||||
return includesExcludes;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<File> getScanDirs()
|
||||
{
|
||||
ArrayList<File> 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<Path> getScannables()
|
||||
{
|
||||
return _scannables.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param recursive True if scanning is recursive
|
||||
* @see #setScanDepth(int)
|
||||
*/
|
||||
@Deprecated
|
||||
public void setRecursive(boolean recursive)
|
||||
{
|
||||
_scanDepth = recursive ? Integer.MAX_VALUE : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if scanning is recursive
|
||||
* @see #getScanDepth()
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean getRecursive()
|
||||
{
|
||||
return _scanDepth > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scanDepth.
|
||||
*
|
||||
* @return the scanDepth
|
||||
*/
|
||||
public int getScanDepth()
|
||||
{
|
||||
return _scanDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scanDepth.
|
||||
*
|
||||
* @param scanDepth the scanDepth to set
|
||||
*/
|
||||
public void setScanDepth(int scanDepth)
|
||||
{
|
||||
_scanDepth = scanDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a filter to files found in the scan directory.
|
||||
|
@ -476,6 +409,34 @@ public class Scanner extends AbstractLifeCycle
|
|||
return _filter;
|
||||
}
|
||||
|
||||
public Set<Path> getScannables()
|
||||
{
|
||||
return Collections.unmodifiableSet(_scannables.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scanDepth.
|
||||
*
|
||||
* @return the scanDepth
|
||||
*/
|
||||
public int getScanDepth()
|
||||
{
|
||||
return _scanDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scanDepth.
|
||||
*
|
||||
* @param scanDepth the scanDepth to set
|
||||
*/
|
||||
public void setScanDepth(int scanDepth)
|
||||
{
|
||||
if (isRunning())
|
||||
throw new IllegalStateException("Scanner started");
|
||||
|
||||
_scanDepth = scanDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not an initial scan will report all files as being
|
||||
* added.
|
||||
|
@ -485,6 +446,8 @@ public class Scanner extends AbstractLifeCycle
|
|||
*/
|
||||
public void setReportExistingFilesOnStartup(boolean reportExisting)
|
||||
{
|
||||
if (isRunning())
|
||||
throw new IllegalStateException("Scanner started");
|
||||
_reportExisting = reportExisting;
|
||||
}
|
||||
|
||||
|
@ -500,6 +463,8 @@ public class Scanner extends AbstractLifeCycle
|
|||
*/
|
||||
public void setReportDirs(boolean dirs)
|
||||
{
|
||||
if (isRunning())
|
||||
throw new IllegalStateException("Scanner started");
|
||||
_reportDirs = dirs;
|
||||
}
|
||||
|
||||
|
@ -517,10 +482,7 @@ public class Scanner extends AbstractLifeCycle
|
|||
{
|
||||
if (listener == null)
|
||||
return;
|
||||
try (AutoLock l = _lock.lock())
|
||||
{
|
||||
_listeners.add(listener);
|
||||
}
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -532,99 +494,62 @@ public class Scanner extends AbstractLifeCycle
|
|||
{
|
||||
if (listener == null)
|
||||
return;
|
||||
try (AutoLock l = _lock.lock())
|
||||
{
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the scanning action.
|
||||
*/
|
||||
@Override
|
||||
public void doStart()
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
try (AutoLock l = _lock.lock())
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scanner start: rprtExists={}, depth={}, rprtDirs={}, interval={}, filter={}, scannables={}",
|
||||
_reportExisting, _scanDepth, _reportDirs, _scanInterval, _filter, _scannables);
|
||||
|
||||
if (_reportExisting)
|
||||
{
|
||||
if (_running)
|
||||
return;
|
||||
|
||||
_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 files exist at startup, report them
|
||||
scan();
|
||||
scan(); // scan twice so files reported as stable
|
||||
}
|
||||
}
|
||||
|
||||
public TimerTask newTimerTask()
|
||||
{
|
||||
return new TimerTask()
|
||||
else
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
scan();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Timer newTimer()
|
||||
{
|
||||
return new Timer("Scanner-" + __scannerId++, true);
|
||||
}
|
||||
|
||||
public void schedule()
|
||||
{
|
||||
if (_running)
|
||||
{
|
||||
if (_timer != null)
|
||||
_timer.cancel();
|
||||
if (_task != null)
|
||||
_task.cancel();
|
||||
if (getScanInterval() > 0)
|
||||
{
|
||||
_timer = newTimer();
|
||||
_task = newTimerTask();
|
||||
_timer.schedule(_task, 1010L * getScanInterval(), 1010L * getScanInterval());
|
||||
}
|
||||
//just register the list of existing files and only report changes
|
||||
_prevScan = scanFiles();
|
||||
}
|
||||
|
||||
|
||||
//Create the scheduler and start it
|
||||
_scheduler = new ScheduledExecutorScheduler("Scanner-" + SCANNER_IDS.getAndIncrement(), true, 1);
|
||||
_scheduler.start();
|
||||
|
||||
//schedule the scan
|
||||
schedule();
|
||||
}
|
||||
|
||||
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 (AutoLock l = _lock.lock())
|
||||
{
|
||||
if (_running)
|
||||
{
|
||||
_running = false;
|
||||
if (_timer != null)
|
||||
_timer.cancel();
|
||||
if (_task != null)
|
||||
_task.cancel();
|
||||
_task = null;
|
||||
_timer = null;
|
||||
}
|
||||
}
|
||||
Scheduler.Task task = _task;
|
||||
_task = null;
|
||||
if (task != null)
|
||||
task.cancel();
|
||||
Scheduler scheduler = _scheduler;
|
||||
_scheduler = null;
|
||||
if (scheduler != null)
|
||||
scheduler.stop();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear the list of scannables. The scanner must first
|
||||
* be in the stopped state.
|
||||
|
@ -633,13 +558,12 @@ public class Scanner extends AbstractLifeCycle
|
|||
{
|
||||
if (!isStopped())
|
||||
throw new IllegalStateException("Not stopped");
|
||||
|
||||
|
||||
//clear the scannables
|
||||
_scannables.clear();
|
||||
|
||||
|
||||
//clear the previous scans
|
||||
_currentScan.clear();
|
||||
_prevScan.clear();
|
||||
_prevScan = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -656,151 +580,163 @@ public class Scanner extends AbstractLifeCycle
|
|||
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");
|
||||
scan(Callback.NOOP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 scheduler = _scheduler;
|
||||
|
||||
if (!isRunning() || scheduler == null)
|
||||
{
|
||||
complete.failed(new IllegalStateException("Scanner not running"));
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.schedule(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
scan();
|
||||
complete.succeeded();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
complete.failed(t);
|
||||
}
|
||||
}, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a pass of the scanner and report changes
|
||||
*/
|
||||
public void scan()
|
||||
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<String, MetaData> currentScan = scanFiles();
|
||||
reportDifferences(currentScan, _prevScan == null ? Collections.emptyMap() : Collections.unmodifiableMap(_prevScan));
|
||||
_prevScan = currentScan;
|
||||
reportScanEnd(cycle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan all of the given paths.
|
||||
*/
|
||||
public void scanFiles()
|
||||
private Map<String, MetaData> scanFiles()
|
||||
{
|
||||
try (AutoLock l = _lock.lock())
|
||||
Map<String, MetaData> 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<String, TimeNSize> currentScan, Map<String, TimeNSize> oldScan)
|
||||
private void reportDifferences(Map<String, MetaData> currentScan, Map<String, MetaData> oldScan)
|
||||
{
|
||||
try (AutoLock l = _lock.lock())
|
||||
Map<String, Notification> changes = new HashMap<>();
|
||||
|
||||
//Handle deleted files
|
||||
Set<String> 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<String> oldScanKeys = new HashSet<>(oldScan.keySet());
|
||||
|
||||
// Look for new and changed files
|
||||
for (Entry<String, TimeNSize> entry : currentScan.entrySet())
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for deleted files
|
||||
for (String file : oldScan.keySet())
|
||||
{
|
||||
if (!currentScan.containsKey(file))
|
||||
{
|
||||
Notification old = _notifications.put(file, Notification.REMOVED);
|
||||
if (old == Notification.ADDED)
|
||||
_notifications.remove(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("scanned {}: {}", _scannables.keySet(), _notifications);
|
||||
|
||||
// Process notifications
|
||||
// Only process notifications that are for stable files (ie same in old and current scan).
|
||||
List<String> bulkChanges = new ArrayList<>();
|
||||
for (Iterator<Entry<String, Notification>> iter = _notifications.entrySet().iterator(); iter.hasNext(); )
|
||||
{
|
||||
|
||||
Entry<String, Notification> 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;
|
||||
}
|
||||
}
|
||||
if (!bulkChanges.isEmpty())
|
||||
reportBulkChanges(bulkChanges);
|
||||
changes.put(file, Notification.REMOVED);
|
||||
}
|
||||
|
||||
// Handle new and changed files
|
||||
for (String file : currentScan.keySet())
|
||||
{
|
||||
MetaData current = currentScan.get(file);
|
||||
MetaData previous = oldScan.get(file);
|
||||
|
||||
if (previous == null)
|
||||
{
|
||||
//New file - don't immediately
|
||||
//notify this, wait until the size has
|
||||
//settled down then notify the add.
|
||||
current._status = Status.ADDED;
|
||||
}
|
||||
else if (current.isModified(previous))
|
||||
{
|
||||
//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());
|
||||
|
||||
//Call the DiscreteListeners
|
||||
for (Map.Entry<String, Notification> entry : changes.entrySet())
|
||||
{
|
||||
switch (entry.getValue())
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
//Call the BulkListeners
|
||||
reportBulkChanges(changes.keySet());
|
||||
}
|
||||
|
||||
private void warn(Object listener, String filename, Throwable th)
|
||||
|
@ -857,6 +793,9 @@ public class Scanner extends AbstractLifeCycle
|
|||
*/
|
||||
private void reportChange(String filename)
|
||||
{
|
||||
if (filename == null)
|
||||
return;
|
||||
|
||||
for (Listener l : _listeners)
|
||||
{
|
||||
try
|
||||
|
@ -876,8 +815,11 @@ public class Scanner extends AbstractLifeCycle
|
|||
*
|
||||
* @param filenames names of all files added/changed/removed
|
||||
*/
|
||||
private void reportBulkChanges(List<String> filenames)
|
||||
private void reportBulkChanges(Set<String> filenames)
|
||||
{
|
||||
if (filenames == null || filenames.isEmpty())
|
||||
return;
|
||||
|
||||
for (Listener l : _listeners)
|
||||
{
|
||||
try
|
||||
|
@ -894,6 +836,8 @@ public class Scanner extends AbstractLifeCycle
|
|||
|
||||
/**
|
||||
* Call ScanCycleListeners with start of scan
|
||||
*
|
||||
* @param cycle scan count
|
||||
*/
|
||||
private void reportScanStart(int cycle)
|
||||
{
|
||||
|
@ -902,9 +846,7 @@ public class Scanner extends AbstractLifeCycle
|
|||
try
|
||||
{
|
||||
if (listener instanceof ScanCycleListener)
|
||||
{
|
||||
((ScanCycleListener)listener).scanStarted(cycle);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -915,6 +857,8 @@ public class Scanner extends AbstractLifeCycle
|
|||
|
||||
/**
|
||||
* Call ScanCycleListeners with end of scan.
|
||||
*
|
||||
* @param cycle scan count
|
||||
*/
|
||||
private void reportScanEnd(int cycle)
|
||||
{
|
||||
|
@ -923,9 +867,8 @@ public class Scanner extends AbstractLifeCycle
|
|||
try
|
||||
{
|
||||
if (listener instanceof ScanCycleListener)
|
||||
{
|
||||
((ScanCycleListener)listener).scanEnded(cycle);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -20,9 +20,11 @@ package org.eclipse.jetty.util.ssl;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
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;
|
||||
|
@ -77,7 +79,7 @@ public class KeyStoreScanner extends ContainerLifeCycle implements Scanner.Discr
|
|||
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);
|
||||
|
@ -117,13 +119,23 @@ public class KeyStoreScanner extends ContainerLifeCycle implements Scanner.Discr
|
|||
}
|
||||
|
||||
@ManagedOperation(value = "Scan for changes in the SSL Keystore", impact = "ACTION")
|
||||
public void scan()
|
||||
public boolean scan(long waitMillis)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("scanning");
|
||||
|
||||
_scanner.scan();
|
||||
_scanner.scan();
|
||||
CompletableFuture<Boolean> cf = new CompletableFuture<>();
|
||||
try
|
||||
{
|
||||
// Perform 2 scans to be sure that the scan is stable.
|
||||
_scanner.scan(Callback.from(() ->
|
||||
_scanner.scan(Callback.from(() -> cf.complete(true), cf::completeExceptionally)), cf::completeExceptionally));
|
||||
return cf.get(waitMillis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ManagedOperation(value = "Reload the SSL Keystore", impact = "ACTION")
|
||||
|
@ -135,7 +147,8 @@ public class KeyStoreScanner extends ContainerLifeCycle implements Scanner.Discr
|
|||
try
|
||||
{
|
||||
sslContextFactory.reload(scf ->
|
||||
{});
|
||||
{
|
||||
});
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,10 @@ import java.io.IOException;
|
|||
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.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -36,12 +39,12 @@ import org.hamcrest.Matchers;
|
|||
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;
|
||||
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 +52,8 @@ public class ScannerTest
|
|||
{
|
||||
static File _directory;
|
||||
static Scanner _scanner;
|
||||
static BlockingQueue<Event> _queue = new LinkedBlockingQueue<Event>();
|
||||
static BlockingQueue<List<String>> _bulk = new LinkedBlockingQueue<List<String>>();
|
||||
static BlockingQueue<Event> _queue = new LinkedBlockingQueue<>();
|
||||
static BlockingQueue<Set<String>> _bulk = new LinkedBlockingQueue<>();
|
||||
|
||||
@BeforeAll
|
||||
public static void setUpBeforeClass() throws Exception
|
||||
|
@ -63,38 +66,31 @@ public class ScannerTest
|
|||
_directory = testDir.toPath().toRealPath().toFile();
|
||||
|
||||
_scanner = new Scanner();
|
||||
_scanner.addScanDir(_directory);
|
||||
_scanner.addDirectory(_directory.toPath());
|
||||
_scanner.setScanInterval(0);
|
||||
_scanner.setReportDirs(false);
|
||||
_scanner.setReportExistingFilesOnStartup(false);
|
||||
_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(List<String> filenames) throws Exception
|
||||
{
|
||||
_bulk.add(filenames);
|
||||
}
|
||||
});
|
||||
_scanner.addListener((Scanner.BulkListener)filenames -> _bulk.add(filenames));
|
||||
|
||||
_scanner.start();
|
||||
_scanner.scan();
|
||||
|
@ -120,6 +116,29 @@ public class ScannerTest
|
|||
_filename = filename;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
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
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(_filename, _notification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return ("File: " + _filename + ":" + _notification);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -142,7 +161,7 @@ public class ScannerTest
|
|||
File y2 = new File(dir2, "yyy2.foo");
|
||||
FS.touch(y2);
|
||||
|
||||
BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();
|
||||
BlockingQueue<Event> queue = new LinkedBlockingQueue<>();
|
||||
Scanner scanner = new Scanner();
|
||||
scanner.setScanInterval(0);
|
||||
scanner.setScanDepth(0);
|
||||
|
@ -152,19 +171,19 @@ public class ScannerTest
|
|||
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));
|
||||
}
|
||||
|
@ -222,7 +241,7 @@ public class ScannerTest
|
|||
File y2 = new File(dir2, "yyy.txt");
|
||||
FS.touch(y2);
|
||||
|
||||
BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();
|
||||
BlockingQueue<Event> queue = new LinkedBlockingQueue<>();
|
||||
//only scan the *.txt files for changes
|
||||
Scanner scanner = new Scanner();
|
||||
IncludeExcludeSet<PathMatcher, Path> pattern = scanner.addDirectory(root.toPath());
|
||||
|
@ -235,19 +254,19 @@ public class ScannerTest
|
|||
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));
|
||||
}
|
||||
|
@ -264,8 +283,10 @@ public class ScannerTest
|
|||
scanner.scan();
|
||||
scanner.scan(); //2 scans for file to be considered settled
|
||||
|
||||
assertThat(queue.size(), Matchers.equalTo(2));
|
||||
for (Event e : queue)
|
||||
List<Event> 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"));
|
||||
}
|
||||
|
@ -273,7 +294,6 @@ public class ScannerTest
|
|||
|
||||
@Test
|
||||
@DisabledOnOs(WINDOWS) // TODO: needs review
|
||||
@DisabledIfSystemProperty(named = "env", matches = "ci") // TODO: SLOW, needs review
|
||||
public void testAddedChangeRemove() throws Exception
|
||||
{
|
||||
touch("a0");
|
||||
|
@ -282,7 +302,7 @@ public class ScannerTest
|
|||
_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);
|
||||
|
@ -296,31 +316,31 @@ public class ScannerTest
|
|||
// 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");
|
||||
|
||||
// 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();
|
||||
assertTrue(event != null);
|
||||
assertEquals(_directory + "/a1", event._filename);
|
||||
assertEquals(Notification.ADDED, event._notification);
|
||||
List<Event> 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
|
||||
_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");
|
||||
|
@ -328,7 +348,7 @@ public class ScannerTest
|
|||
// 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
|
||||
|
@ -337,7 +357,7 @@ public class ScannerTest
|
|||
// 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 +365,7 @@ public class ScannerTest
|
|||
// 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 +373,32 @@ public class ScannerTest
|
|||
// delete a1 and a2
|
||||
delete("a1");
|
||||
delete("a2");
|
||||
// not stable after 1scan so nothing should not be seen yet.
|
||||
_scanner.scan();
|
||||
event = _queue.poll();
|
||||
assertTrue(event == null);
|
||||
|
||||
// readd a2
|
||||
touch("a2");
|
||||
|
||||
// only a1 is stable so it should be seen.
|
||||
//Immediate notification of deletes.
|
||||
_scanner.scan();
|
||||
event = _queue.poll();
|
||||
assertTrue(event != null);
|
||||
assertEquals(_directory + "/a1", 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());
|
||||
|
||||
// Now a2 is stable and is a changed file rather than a remove
|
||||
// recreate a2
|
||||
touch("a2");
|
||||
|
||||
// a2 not stable yet, shouldn't be seen
|
||||
_scanner.scan();
|
||||
event = _queue.poll();
|
||||
assertTrue(event != null);
|
||||
assertNull(event);
|
||||
assertTrue(_queue.isEmpty());
|
||||
|
||||
//Now a2 is reported as ADDED.
|
||||
_scanner.scan();
|
||||
event = _queue.poll();
|
||||
assertNotNull(event);
|
||||
assertEquals(_directory + "/a2", event._filename);
|
||||
assertEquals(Notification.CHANGED, event._notification);
|
||||
assertEquals(Notification.ADDED, event._notification);
|
||||
assertTrue(_queue.isEmpty());
|
||||
}
|
||||
|
||||
|
@ -386,9 +410,9 @@ public class ScannerTest
|
|||
_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 +428,7 @@ public class ScannerTest
|
|||
// Not stable yet so no notification.
|
||||
_scanner.scan();
|
||||
event = _queue.poll();
|
||||
assertTrue(event == null);
|
||||
assertNull(event);
|
||||
|
||||
// Modify size only
|
||||
out.write('x');
|
||||
|
@ -414,12 +438,12 @@ public class ScannerTest
|
|||
// 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,18 +455,18 @@ public class ScannerTest
|
|||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
private void delete(String string) throws IOException
|
||||
private void delete(String string)
|
||||
{
|
||||
File file = new File(_directory, string);
|
||||
if (file.exists())
|
||||
|
|
|
@ -126,7 +126,7 @@ public class KeyStoreScannerTest
|
|||
|
||||
// Switch to use newKeystore which has a later expiry date.
|
||||
useKeystore("newKeystore");
|
||||
keystoreScanner.scan();
|
||||
assertTrue(keystoreScanner.scan(5000));
|
||||
|
||||
// The scanner should have detected the updated keystore, expiry should be renewed.
|
||||
X509Certificate cert2 = getCertificateFromServer();
|
||||
|
@ -146,7 +146,7 @@ public class KeyStoreScannerTest
|
|||
try (StacklessLogging ignored = new StacklessLogging(KeyStoreScanner.class))
|
||||
{
|
||||
useKeystore("badKeystore");
|
||||
keystoreScanner.scan();
|
||||
keystoreScanner.scan(5000);
|
||||
}
|
||||
|
||||
// The good keystore is removed, now the bad keystore now causes an exception.
|
||||
|
@ -167,7 +167,7 @@ public class KeyStoreScannerTest
|
|||
{
|
||||
Path keystorePath = keystoreDir.resolve("keystore");
|
||||
assertTrue(Files.deleteIfExists(keystorePath));
|
||||
keystoreScanner.scan();
|
||||
keystoreScanner.scan(5000);
|
||||
}
|
||||
|
||||
// The good keystore is removed, having no keystore causes an exception.
|
||||
|
@ -175,7 +175,7 @@ public class KeyStoreScannerTest
|
|||
|
||||
// Switch to use keystore2 which has a later expiry date.
|
||||
useKeystore("newKeystore");
|
||||
keystoreScanner.scan();
|
||||
keystoreScanner.scan(5000);
|
||||
X509Certificate cert2 = getCertificateFromServer();
|
||||
assertThat(getExpiryYear(cert2), is(2020));
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ public class KeyStoreScannerTest
|
|||
// Change the symlink to point to the newKeystore file location which has a later expiry date.
|
||||
Files.delete(keystorePath);
|
||||
Files.createSymbolicLink(keystorePath, useKeystore("newKeystore"));
|
||||
keystoreScanner.scan();
|
||||
keystoreScanner.scan(5000);
|
||||
|
||||
// The scanner should have detected the updated keystore, expiry should be renewed.
|
||||
X509Certificate cert2 = getCertificateFromServer();
|
||||
|
@ -232,7 +232,7 @@ public class KeyStoreScannerTest
|
|||
// Change the target file of the symlink to the newKeystore which has a later expiry date.
|
||||
Files.copy(newKeystoreSrc, target, StandardCopyOption.REPLACE_EXISTING);
|
||||
System.err.println("### Triggering scan");
|
||||
keystoreScanner.scan();
|
||||
keystoreScanner.scan(5000);
|
||||
|
||||
// The scanner should have detected the updated keystore, expiry should be renewed.
|
||||
X509Certificate cert2 = getCertificateFromServer();
|
||||
|
|
Loading…
Reference in New Issue