* Issue #2266 Rework Scanner and use it for Jetty Maven Plugin Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
parent
37aa5a17e0
commit
aefbdfca58
|
@ -141,6 +141,7 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
|
||||||
_scanner.setRecursive(_recursive);
|
_scanner.setRecursive(_recursive);
|
||||||
_scanner.setFilenameFilter(_filenameFilter);
|
_scanner.setFilenameFilter(_filenameFilter);
|
||||||
_scanner.setReportDirs(true);
|
_scanner.setReportDirs(true);
|
||||||
|
_scanner.setScanDepth(1); //consider direct dir children of monitored dir
|
||||||
_scanner.addListener(_scannerListener);
|
_scanner.addListener(_scannerListener);
|
||||||
_scanner.start();
|
_scanner.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,11 @@ public class WebAppProvider extends ScanningAppProvider
|
||||||
String lowername = name.toLowerCase(Locale.ENGLISH);
|
String lowername = name.toLowerCase(Locale.ENGLISH);
|
||||||
|
|
||||||
File file = new File(dir, name);
|
File file = new File(dir, name);
|
||||||
|
Resource r = Resource.newResource(file);
|
||||||
|
if (getMonitoredResources().contains(r) && r.isDirectory())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore hidden files
|
// ignore hidden files
|
||||||
if (lowername.startsWith("."))
|
if (lowername.startsWith("."))
|
||||||
|
|
|
@ -50,6 +50,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
import org.eclipse.jetty.util.PathWatcher;
|
||||||
|
import org.eclipse.jetty.util.Scanner;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||||
|
@ -222,7 +223,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
||||||
/**
|
/**
|
||||||
* A scanner to check for changes to the webapp
|
* A scanner to check for changes to the webapp
|
||||||
*/
|
*/
|
||||||
protected PathWatcher scanner;
|
protected Scanner scanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scanner to check ENTER hits on the console
|
* A scanner to check ENTER hits on the console
|
||||||
|
@ -458,7 +459,25 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
||||||
// start the scanner thread (if necessary) on the main webapp
|
// start the scanner thread (if necessary) on the main webapp
|
||||||
if (isScanningEnabled())
|
if (isScanningEnabled())
|
||||||
{
|
{
|
||||||
scanner = new PathWatcher();
|
scanner = new Scanner();
|
||||||
|
scanner.setScanInterval(scanIntervalSeconds);
|
||||||
|
scanner.setScanDepth(Scanner.MAX_SCAN_DEPTH); //always fully walk directory hierarchies
|
||||||
|
scanner.setReportExistingFilesOnStartup(false);
|
||||||
|
scanner.addListener(new Scanner.BulkListener()
|
||||||
|
{
|
||||||
|
public void filesChanged(List<String> changes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
|
||||||
|
restartWebApp(reconfigure);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
getLog().error("Error reconfiguring/restarting webapp after change in watched files",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
configureScanner();
|
configureScanner();
|
||||||
startScanner();
|
startScanner();
|
||||||
}
|
}
|
||||||
|
@ -523,7 +542,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
||||||
|
|
||||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(path.toFile()));
|
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(path.toFile()));
|
||||||
getLog().info("Applying context xml file " + contextXml);
|
getLog().info("Applying context xml file " + contextXml);
|
||||||
xmlConfiguration.configure(webApp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//If no contextPath was specified, go with default of project artifactid
|
//If no contextPath was specified, go with default of project artifactid
|
||||||
|
@ -562,8 +580,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
||||||
if (!isScanningEnabled())
|
if (!isScanningEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scanner.setNotifyExistingOnStart(false);
|
|
||||||
|
|
||||||
scanner.start();
|
scanner.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -41,8 +42,7 @@ import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
import org.apache.maven.project.MavenProject;
|
import org.apache.maven.project.MavenProject;
|
||||||
import org.eclipse.jetty.maven.plugin.utils.MavenProjectHelper;
|
import org.eclipse.jetty.maven.plugin.utils.MavenProjectHelper;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||||
|
@ -145,9 +145,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
|
|
||||||
protected Resource originalBaseResource;
|
protected Resource originalBaseResource;
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws MojoExecutionException, MojoFailureException
|
public void execute() throws MojoExecutionException, MojoFailureException
|
||||||
{
|
{
|
||||||
|
@ -157,8 +154,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify the configuration given in the pom.
|
* Verify the configuration given in the pom.
|
||||||
*
|
|
||||||
* @see AbstractJettyMojo#checkPomConfiguration()
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean checkPomConfiguration() throws MojoExecutionException
|
public boolean checkPomConfiguration() throws MojoExecutionException
|
||||||
|
@ -229,9 +224,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
super.finishConfigurationBeforeStart();
|
super.finishConfigurationBeforeStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void configureWebApplication() throws Exception
|
public void configureWebApplication() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -317,9 +309,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
getLog().info("Webapp directory = " + webAppSourceDirectory.getCanonicalPath());
|
getLog().info("Webapp directory = " + webAppSourceDirectory.getCanonicalPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void configureScanner()
|
public void configureScanner()
|
||||||
throws MojoExecutionException
|
throws MojoExecutionException
|
||||||
|
@ -332,36 +321,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
{
|
{
|
||||||
throw new MojoExecutionException("Error forming scan list", e);
|
throw new MojoExecutionException("Error forming scan list", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner.addListener(new PathWatcher.EventListListener()
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPathWatchEvents(List<PathWatchEvent> events)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
boolean reconfigure = false;
|
|
||||||
if (events != null)
|
|
||||||
{
|
|
||||||
for (PathWatchEvent e : events)
|
|
||||||
{
|
|
||||||
if (e.getPath().equals(project.getFile().toPath()))
|
|
||||||
{
|
|
||||||
reconfigure = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
restartWebApp(reconfigure);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
getLog().error("Error reconfiguring/restarting webapp after change in watched files", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void gatherScannables() throws Exception
|
public void gatherScannables() throws Exception
|
||||||
|
@ -369,33 +328,37 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
if (webApp.getDescriptor() != null)
|
if (webApp.getDescriptor() != null)
|
||||||
{
|
{
|
||||||
Resource r = Resource.newResource(webApp.getDescriptor());
|
Resource r = Resource.newResource(webApp.getDescriptor());
|
||||||
scanner.watch(r.getFile().toPath());
|
scanner.addFile(r.getFile().toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getJettyEnvXml() != null)
|
if (webApp.getJettyEnvXml() != null)
|
||||||
scanner.watch(new File(webApp.getJettyEnvXml()).toPath());
|
scanner.addFile(new File(webApp.getJettyEnvXml()).toPath());
|
||||||
|
|
||||||
if (webApp.getDefaultsDescriptor() != null)
|
if (webApp.getDefaultsDescriptor() != null)
|
||||||
{
|
{
|
||||||
if (!WebAppContext.WEB_DEFAULTS_XML.equals(webApp.getDefaultsDescriptor()))
|
if (!WebAppContext.WEB_DEFAULTS_XML.equals(webApp.getDefaultsDescriptor()))
|
||||||
scanner.watch(new File(webApp.getDefaultsDescriptor()).toPath());
|
scanner.addFile(new File(webApp.getDefaultsDescriptor()).toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getOverrideDescriptor() != null)
|
if (webApp.getOverrideDescriptor() != null)
|
||||||
{
|
{
|
||||||
scanner.watch(new File(webApp.getOverrideDescriptor()).toPath());
|
scanner.addFile(new File(webApp.getOverrideDescriptor()).toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory, "WEB-INF"));
|
File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory, "WEB-INF"));
|
||||||
if (jettyWebXmlFile != null)
|
if (jettyWebXmlFile != null)
|
||||||
{
|
{
|
||||||
scanner.watch(jettyWebXmlFile.toPath());
|
scanner.addFile(jettyWebXmlFile.toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//make sure each of the war artifacts is added to the scanner
|
//make sure each of the war artifacts is added to the scanner
|
||||||
for (Artifact a : getWarArtifacts())
|
for (Artifact a : getWarArtifacts())
|
||||||
{
|
{
|
||||||
scanner.watch(a.getFile().toPath());
|
File f = a.getFile();
|
||||||
|
if (a.getFile().isDirectory())
|
||||||
|
scanner.addDirectory(f.toPath());
|
||||||
|
else
|
||||||
|
scanner.addFile(f.toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//handle the explicit extra scan targets
|
//handle the explicit extra scan targets
|
||||||
|
@ -405,87 +368,81 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
{
|
{
|
||||||
if (f.isDirectory())
|
if (f.isDirectory())
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(f.toPath());
|
scanner.addDirectory(f.toPath());
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
|
||||||
scanner.watch(config);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
scanner.watch(f.toPath());
|
scanner.addFile(f.toPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scanner.addFile(project.getFile().toPath());
|
||||||
|
|
||||||
//handle the extra scan patterns
|
//handle the extra scan patterns
|
||||||
if (scanTargetPatterns != null)
|
if (scanTargetPatterns != null)
|
||||||
{
|
{
|
||||||
for (ScanTargetPattern p : scanTargetPatterns)
|
for (ScanTargetPattern p : scanTargetPatterns)
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(p.getDirectory().toPath());
|
IncludeExcludeSet<PathMatcher, Path> includesExcludes = scanner.addDirectory(p.getDirectory().toPath());
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
p.configureIncludesExcludeSet(includesExcludes);
|
||||||
for (String pattern : p.getExcludes())
|
|
||||||
{
|
|
||||||
config.addExcludeGlobRelative(pattern);
|
|
||||||
}
|
|
||||||
for (String pattern : p.getIncludes())
|
|
||||||
{
|
|
||||||
config.addIncludeGlobRelative(pattern);
|
|
||||||
}
|
|
||||||
scanner.watch(config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner.watch(project.getFile().toPath());
|
|
||||||
|
|
||||||
if (webApp.getTestClasses() != null && webApp.getTestClasses().exists())
|
if (webApp.getTestClasses() != null && webApp.getTestClasses().exists())
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(webApp.getTestClasses().toPath());
|
Path p = webApp.getTestClasses().toPath();
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
IncludeExcludeSet<PathMatcher, Path> includeExcludeSet = scanner.addDirectory(p);
|
||||||
|
|
||||||
if (scanTestClassesPattern != null)
|
if (scanTestClassesPattern != null)
|
||||||
{
|
{
|
||||||
for (String p : scanTestClassesPattern.getExcludes())
|
for (String s : scanTestClassesPattern.getExcludes())
|
||||||
{
|
{
|
||||||
config.addExcludeGlobRelative(p);
|
if (!s.startsWith("glob:"))
|
||||||
|
s = "glob:" + s;
|
||||||
|
includeExcludeSet.exclude(p.getFileSystem().getPathMatcher(s));
|
||||||
}
|
}
|
||||||
for (String p : scanTestClassesPattern.getIncludes())
|
for (String s : scanTestClassesPattern.getIncludes())
|
||||||
{
|
{
|
||||||
config.addIncludeGlobRelative(p);
|
if (!s.startsWith("glob:"))
|
||||||
|
s = "glob:" + s;
|
||||||
|
includeExcludeSet.include(p.getFileSystem().getPathMatcher(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scanner.watch(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getClasses() != null && webApp.getClasses().exists())
|
if (webApp.getClasses() != null && webApp.getClasses().exists())
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(webApp.getClasses().toPath());
|
Path p = webApp.getClasses().toPath();
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
IncludeExcludeSet<PathMatcher, Path> includeExcludes = scanner.addDirectory(p);
|
||||||
if (scanClassesPattern != null)
|
if (scanClassesPattern != null)
|
||||||
{
|
{
|
||||||
for (String p : scanClassesPattern.getExcludes())
|
for (String s : scanClassesPattern.getExcludes())
|
||||||
{
|
{
|
||||||
config.addExcludeGlobRelative(p);
|
if (!s.startsWith("glob:"))
|
||||||
|
s = "glob:" + s;
|
||||||
|
includeExcludes.exclude(p.getFileSystem().getPathMatcher(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String p : scanClassesPattern.getIncludes())
|
for (String s : scanClassesPattern.getIncludes())
|
||||||
{
|
{
|
||||||
config.addIncludeGlobRelative(p);
|
if (!s.startsWith("glob:"))
|
||||||
|
s = "glob:" + s;
|
||||||
|
includeExcludes.include(p.getFileSystem().getPathMatcher(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scanner.watch(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getWebInfLib() != null)
|
if (webApp.getWebInfLib() != null)
|
||||||
{
|
{
|
||||||
for (File f : webApp.getWebInfLib())
|
for (File f : webApp.getWebInfLib())
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(f.toPath());
|
if (f.isDirectory())
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
scanner.addDirectory(f.toPath());
|
||||||
scanner.watch(config);
|
else
|
||||||
|
scanner.addFile(f.toPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||||
{
|
{
|
||||||
|
@ -661,9 +618,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
return Resource.newResource(dir.getCanonicalPath());
|
return Resource.newResource(dir.getCanonicalPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private List<Artifact> getWarArtifacts()
|
private List<Artifact> getWarArtifacts()
|
||||||
{
|
{
|
||||||
if (warArtifacts != null)
|
if (warArtifacts != null)
|
||||||
|
@ -704,9 +658,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected String getJavaBin()
|
protected String getJavaBin()
|
||||||
{
|
{
|
||||||
String[] javaexes = new String[]
|
String[] javaexes = new String[]
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
package org.eclipse.jetty.maven.plugin;
|
package org.eclipse.jetty.maven.plugin;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.maven.plugin.MojoExecutionException;
|
import org.apache.maven.plugin.MojoExecutionException;
|
||||||
import org.apache.maven.plugin.MojoFailureException;
|
import org.apache.maven.plugin.MojoFailureException;
|
||||||
|
@ -28,8 +28,6 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||||
import org.apache.maven.plugins.annotations.Mojo;
|
import org.apache.maven.plugins.annotations.Mojo;
|
||||||
import org.apache.maven.plugins.annotations.Parameter;
|
import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
|
||||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -55,9 +53,6 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
||||||
@Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}", required = true)
|
@Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}", required = true)
|
||||||
private File war;
|
private File war;
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws MojoExecutionException, MojoFailureException
|
public void execute() throws MojoExecutionException, MojoFailureException
|
||||||
{
|
{
|
||||||
|
@ -71,70 +66,55 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
||||||
super.finishConfigurationBeforeStart();
|
super.finishConfigurationBeforeStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see AbstractJettyMojo#configureScanner()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void configureScanner() throws MojoExecutionException
|
public void configureScanner() throws MojoExecutionException
|
||||||
{
|
{
|
||||||
scanner.watch(project.getFile().toPath());
|
try
|
||||||
|
{
|
||||||
|
scanner.addFile(project.getFile().toPath());
|
||||||
File webInfDir = new File(war, "WEB-INF");
|
File webInfDir = new File(war, "WEB-INF");
|
||||||
File webXml = new File(webInfDir, "web.xml");
|
File webXml = new File(webInfDir, "web.xml");
|
||||||
if (webXml.exists())
|
if (webXml.exists())
|
||||||
scanner.watch(webXml.toPath());
|
scanner.addFile(webXml.toPath());
|
||||||
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
|
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
|
||||||
if (jettyWebXmlFile != null)
|
if (jettyWebXmlFile != null)
|
||||||
scanner.watch(jettyWebXmlFile.toPath());
|
scanner.addFile(jettyWebXmlFile.toPath());
|
||||||
File jettyEnvXmlFile = new File(webInfDir, "jetty-env.xml");
|
File jettyEnvXmlFile = new File(webInfDir, "jetty-env.xml");
|
||||||
if (jettyEnvXmlFile.exists())
|
if (jettyEnvXmlFile.exists())
|
||||||
scanner.watch(jettyEnvXmlFile.toPath());
|
scanner.addFile(jettyEnvXmlFile.toPath());
|
||||||
|
|
||||||
File classes = new File(webInfDir, "classes");
|
File classes = new File(webInfDir, "classes");
|
||||||
if (classes.exists())
|
if (classes.exists())
|
||||||
{
|
{
|
||||||
PathWatcher.Config classesConfig = new PathWatcher.Config(classes.toPath());
|
try
|
||||||
classesConfig.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
{
|
||||||
scanner.watch(classesConfig);
|
scanner.addDirectory(webApp.getClasses().toPath());
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new MojoExecutionException("Error scanning classes", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File lib = new File(webInfDir, "lib");
|
File lib = new File(webInfDir, "lib");
|
||||||
if (lib.exists())
|
if (lib.exists())
|
||||||
{
|
|
||||||
PathWatcher.Config libConfig = new PathWatcher.Config(lib.toPath());
|
|
||||||
libConfig.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
|
||||||
scanner.watch(libConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
scanner.addListener(new PathWatcher.EventListListener()
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPathWatchEvents(List<PathWatchEvent> events)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boolean reconfigure = false;
|
scanner.addDirectory(lib.toPath());
|
||||||
for (PathWatchEvent e : events)
|
}
|
||||||
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
if (e.getPath().equals(project.getFile().toPath()))
|
throw new MojoExecutionException("Error scanning lib", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
reconfigure = true;
|
throw new MojoExecutionException("Error configuring scanner", e);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
restartWebApp(reconfigure);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
getLog().error("Error reconfiguring/restarting webapp after change in watched files", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||||
{
|
{
|
||||||
|
@ -161,9 +141,6 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
||||||
getLog().info("Restart completed.");
|
getLog().info("Restart completed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void configureWebApplication() throws Exception
|
public void configureWebApplication() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
package org.eclipse.jetty.maven.plugin;
|
package org.eclipse.jetty.maven.plugin;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.maven.plugin.MojoExecutionException;
|
import org.apache.maven.plugin.MojoExecutionException;
|
||||||
import org.apache.maven.plugin.MojoFailureException;
|
import org.apache.maven.plugin.MojoFailureException;
|
||||||
|
@ -28,8 +28,6 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||||
import org.apache.maven.plugins.annotations.Mojo;
|
import org.apache.maven.plugins.annotations.Mojo;
|
||||||
import org.apache.maven.plugins.annotations.Parameter;
|
import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
|
||||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -56,9 +54,6 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
||||||
@Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.war", required = true)
|
@Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.war", required = true)
|
||||||
private File war;
|
private File war;
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.apache.maven.plugin.Mojo#execute()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws MojoExecutionException, MojoFailureException
|
public void execute() throws MojoExecutionException, MojoFailureException
|
||||||
{
|
{
|
||||||
|
@ -80,45 +75,20 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
||||||
webApp.setWar(war.getCanonicalPath());
|
webApp.setWar(war.getCanonicalPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see AbstractJettyMojo#configureScanner()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void configureScanner() throws MojoExecutionException
|
public void configureScanner() throws MojoExecutionException
|
||||||
{
|
|
||||||
scanner.watch(project.getFile().toPath());
|
|
||||||
scanner.watch(war.toPath());
|
|
||||||
|
|
||||||
scanner.addListener(new PathWatcher.EventListListener()
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPathWatchEvents(List<PathWatchEvent> events)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boolean reconfigure = false;
|
scanner.addFile(project.getFile().toPath());
|
||||||
for (PathWatchEvent e : events)
|
scanner.addFile(war.toPath());
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
if (e.getPath().equals(project.getFile().toPath()))
|
throw new MojoExecutionException("Error configuring scanner", e);
|
||||||
{
|
|
||||||
reconfigure = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
restartWebApp(reconfigure);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
getLog().error("Error reconfiguring/restarting webapp after change in watched files", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* ScanPattern
|
* ScanPattern
|
||||||
*
|
*
|
||||||
* A pattern of includes and excludes.
|
* Ant-style pattern of includes and excludes.
|
||||||
*/
|
*/
|
||||||
public class ScanPattern
|
public class ScanPattern
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,9 +19,13 @@
|
||||||
package org.eclipse.jetty.maven.plugin;
|
package org.eclipse.jetty.maven.plugin;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ScanTargetPattern
|
* ScanTargetPattern
|
||||||
*
|
*
|
||||||
|
@ -87,4 +91,21 @@ public class ScanTargetPattern
|
||||||
{
|
{
|
||||||
return (_pattern == null ? Collections.emptyList() : _pattern.getExcludes());
|
return (_pattern == null ? Collections.emptyList() : _pattern.getExcludes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void configureIncludesExcludeSet(IncludeExcludeSet<PathMatcher, Path> includesExcludes)
|
||||||
|
{
|
||||||
|
for (String include:getIncludes())
|
||||||
|
{
|
||||||
|
if (!include.startsWith("glob:"))
|
||||||
|
include = "glob:" + include;
|
||||||
|
includesExcludes.include(_directory.toPath().getFileSystem().getPathMatcher(include));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String exclude:getExcludes())
|
||||||
|
{
|
||||||
|
if (!exclude.startsWith("glob:"))
|
||||||
|
exclude = "glob:" + exclude;
|
||||||
|
includesExcludes.exclude(_directory.toPath().getFileSystem().getPathMatcher(exclude));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,16 @@ package org.eclipse.jetty.util;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.FileVisitor;
|
||||||
|
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.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -32,6 +40,7 @@ import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
@ -45,6 +54,16 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
*/
|
*/
|
||||||
public class Scanner extends AbstractLifeCycle
|
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 = Log.getLogger(Scanner.class);
|
private static final Logger LOG = Log.getLogger(Scanner.class);
|
||||||
private static int __scannerId = 0;
|
private static int __scannerId = 0;
|
||||||
private int _scanInterval;
|
private int _scanInterval;
|
||||||
|
@ -53,13 +72,13 @@ public class Scanner extends AbstractLifeCycle
|
||||||
private final Map<String, TimeNSize> _prevScan = new HashMap<>();
|
private final Map<String, TimeNSize> _prevScan = new HashMap<>();
|
||||||
private final Map<String, TimeNSize> _currentScan = new HashMap<>();
|
private final Map<String, TimeNSize> _currentScan = new HashMap<>();
|
||||||
private FilenameFilter _filter;
|
private FilenameFilter _filter;
|
||||||
private final List<File> _scanDirs = new ArrayList<>();
|
private final Map<Path, IncludeExcludeSet<PathMatcher, Path>> _scannables = new HashMap<>();
|
||||||
private volatile boolean _running = false;
|
private volatile boolean _running = false;
|
||||||
private boolean _reportExisting = true;
|
private boolean _reportExisting = true;
|
||||||
private boolean _reportDirs = true;
|
private boolean _reportDirs = true;
|
||||||
private Timer _timer;
|
private Timer _timer;
|
||||||
private TimerTask _task;
|
private TimerTask _task;
|
||||||
private int _scanDepth = 0;
|
private int _scanDepth = DEFAULT_SCAN_DEPTH;
|
||||||
|
|
||||||
public enum Notification
|
public enum Notification
|
||||||
{
|
{
|
||||||
|
@ -68,6 +87,31 @@ public class Scanner extends AbstractLifeCycle
|
||||||
|
|
||||||
private final Map<String, Notification> _notifications = new HashMap<>();
|
private final Map<String, Notification> _notifications = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PathMatcherSet
|
||||||
|
*
|
||||||
|
* A set of PathMatchers for testing Paths against path matching patterns via
|
||||||
|
* @see IncludeExcludeSet
|
||||||
|
*/
|
||||||
|
static class PathMatcherSet extends HashSet<PathMatcher> implements Predicate<Path>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean test(Path p)
|
||||||
|
{
|
||||||
|
for (PathMatcher pm : this)
|
||||||
|
{
|
||||||
|
if (pm.matches(p))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TimeNSize
|
||||||
|
*
|
||||||
|
* Metadata about a file: Last modified time and file size.
|
||||||
|
*/
|
||||||
static class TimeNSize
|
static class TimeNSize
|
||||||
{
|
{
|
||||||
final long _lastModified;
|
final long _lastModified;
|
||||||
|
@ -103,6 +147,105 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visitor
|
||||||
|
*
|
||||||
|
* A FileVisitor for walking a subtree of paths. The Scanner uses
|
||||||
|
* this to examine the dirs and files it has been asked to scan.
|
||||||
|
*/
|
||||||
|
public class Visitor implements FileVisitor<Path>
|
||||||
|
{
|
||||||
|
Map<String, TimeNSize> scanInfoMap;
|
||||||
|
IncludeExcludeSet<PathMatcher,Path> rootIncludesExcludes;
|
||||||
|
Path root;
|
||||||
|
|
||||||
|
public Visitor(Path root, IncludeExcludeSet<PathMatcher,Path> rootIncludesExcludes, Map<String, TimeNSize> scanInfoMap)
|
||||||
|
{
|
||||||
|
this.root = root;
|
||||||
|
this.rootIncludesExcludes = rootIncludesExcludes;
|
||||||
|
this.scanInfoMap = scanInfoMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
|
||||||
|
{
|
||||||
|
if (!Files.exists(dir))
|
||||||
|
return FileVisitResult.SKIP_SUBTREE;
|
||||||
|
|
||||||
|
File f = dir.toFile();
|
||||||
|
|
||||||
|
//if we want to report directories and we haven't already seen it
|
||||||
|
if (_reportDirs && !scanInfoMap.containsKey(f.getCanonicalPath()))
|
||||||
|
{
|
||||||
|
boolean accepted = false;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_filter == null || _filter.accept(f.getParentFile(), f.getName()))
|
||||||
|
accepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accepted)
|
||||||
|
{
|
||||||
|
scanInfoMap.put(f.getCanonicalPath(), new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length()));
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("scan accepted dir {} mod={}", f, f.lastModified());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
|
||||||
|
{
|
||||||
|
if (!Files.exists(file))
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
|
||||||
|
File f = file.toFile();
|
||||||
|
boolean accepted = false;
|
||||||
|
|
||||||
|
if (f.isFile() || (f.isDirectory() && _reportDirs && !scanInfoMap.containsKey(f.getCanonicalPath())))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else if (_filter == null || _filter.accept(f.getParentFile(), f.getName()))
|
||||||
|
accepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accepted)
|
||||||
|
{
|
||||||
|
scanInfoMap.put(f.getCanonicalPath(), new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length()));
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("scan accepted {} mod={}", f, f.lastModified());
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
|
||||||
|
{
|
||||||
|
LOG.warn(exc);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
|
||||||
|
{
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener
|
* Listener
|
||||||
*
|
*
|
||||||
|
@ -171,36 +314,110 @@ public class Scanner extends AbstractLifeCycle
|
||||||
|
|
||||||
public void setScanDirs(List<File> dirs)
|
public void setScanDirs(List<File> dirs)
|
||||||
{
|
{
|
||||||
_scanDirs.clear();
|
_scannables.clear();
|
||||||
_scanDirs.addAll(dirs);
|
if (dirs == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (File f:dirs)
|
||||||
|
{
|
||||||
|
addScanDir(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public synchronized void addScanDir(File dir)
|
public synchronized void addScanDir(File dir)
|
||||||
{
|
{
|
||||||
_scanDirs.add(dir);
|
if (dir == null)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (dir.isDirectory())
|
||||||
|
addDirectory(dir.toPath());
|
||||||
|
else
|
||||||
|
addFile(dir.toPath());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 synchronized void addFile(Path p) throws IOException
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
_scannables.put(p, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a directory to be scanned. The directory must not be null and must exist.
|
||||||
|
*
|
||||||
|
* @param p the directory to scan.
|
||||||
|
* @return an IncludeExcludeSet to which the caller can add PathMatcher patterns to match
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized IncludeExcludeSet<PathMatcher, Path> addDirectory(Path p)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
|
||||||
|
IncludeExcludeSet<PathMatcher, Path> includesExcludes = _scannables.get(p);
|
||||||
|
if (includesExcludes == null)
|
||||||
|
{
|
||||||
|
includesExcludes = new IncludeExcludeSet<>(PathMatcherSet.class);
|
||||||
|
_scannables.put(p.toRealPath(), includesExcludes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return includesExcludes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public List<File> getScanDirs()
|
public List<File> getScanDirs()
|
||||||
{
|
{
|
||||||
return Collections.unmodifiableList(_scanDirs);
|
ArrayList<File> files = new ArrayList<>();
|
||||||
|
for (Path p : _scannables.keySet())
|
||||||
|
files.add(p.toFile());
|
||||||
|
return Collections.unmodifiableList(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Path> getScannables()
|
||||||
|
{
|
||||||
|
return _scannables.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param recursive True if scanning is recursive
|
* @param recursive True if scanning is recursive
|
||||||
* @see #setScanDepth(int)
|
* @see #setScanDepth(int)
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setRecursive(boolean recursive)
|
public void setRecursive(boolean recursive)
|
||||||
{
|
{
|
||||||
_scanDepth = recursive ? -1 : 0;
|
_scanDepth = recursive ? Integer.MAX_VALUE : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if scanning is fully recursive (scandepth==-1)
|
* @return True if scanning is recursive
|
||||||
* @see #getScanDepth()
|
* @see #getScanDepth()
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean getRecursive()
|
public boolean getRecursive()
|
||||||
{
|
{
|
||||||
return _scanDepth == -1;
|
return _scanDepth > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,6 +446,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
*
|
*
|
||||||
* @param filter the filename filter to use
|
* @param filter the filename filter to use
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setFilenameFilter(FilenameFilter filter)
|
public void setFilenameFilter(FilenameFilter filter)
|
||||||
{
|
{
|
||||||
_filter = filter;
|
_filter = filter;
|
||||||
|
@ -239,6 +457,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
*
|
*
|
||||||
* @return the filename filter
|
* @return the filename filter
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public FilenameFilter getFilenameFilter()
|
public FilenameFilter getFilenameFilter()
|
||||||
{
|
{
|
||||||
return _filter;
|
return _filter;
|
||||||
|
@ -310,6 +529,9 @@ public class Scanner extends AbstractLifeCycle
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_running = true;
|
_running = true;
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Scanner start: rprtExists={}, depth={}, rprtDirs={}, interval={}, filter={}, scannables={}",
|
||||||
|
_reportExisting, _scanDepth, _reportDirs, _scanInterval, _filter, _scannables);
|
||||||
|
|
||||||
if (_reportExisting)
|
if (_reportExisting)
|
||||||
{
|
{
|
||||||
|
@ -378,15 +600,32 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the list of scannables. The scanner must first
|
||||||
|
* be in the stopped state.
|
||||||
|
*/
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
if (!isStopped())
|
||||||
|
throw new IllegalStateException("Not stopped");
|
||||||
|
|
||||||
|
//clear the scannables
|
||||||
|
_scannables.clear();
|
||||||
|
|
||||||
|
//clear the previous scans
|
||||||
|
_currentScan.clear();
|
||||||
|
_prevScan.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param path tests if the path exists
|
* @param path tests if the path exists
|
||||||
* @return true if the path exists in one of the scandirs
|
* @return true if the path exists in one of the scandirs
|
||||||
*/
|
*/
|
||||||
public boolean exists(String path)
|
public boolean exists(String path)
|
||||||
{
|
{
|
||||||
for (File dir : _scanDirs)
|
for (Path p : _scannables.keySet())
|
||||||
{
|
{
|
||||||
if (new File(dir, path).exists())
|
if (p.resolve(path).toFile().exists())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -419,18 +658,16 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively scan all files in the designated directories.
|
* Scan all of the given paths.
|
||||||
*/
|
*/
|
||||||
public synchronized void scanFiles()
|
public synchronized void scanFiles()
|
||||||
{
|
{
|
||||||
_currentScan.clear();
|
_currentScan.clear();
|
||||||
for (File dir : _scanDirs)
|
for (Path p : _scannables.keySet())
|
||||||
{
|
|
||||||
if ((dir != null) && (dir.exists()))
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
scanFile(dir.getCanonicalFile(), _currentScan, 0);
|
Files.walkFileTree(p, EnumSet.allOf(FileVisitOption.class),_scanDepth, new Visitor(p, _scannables.get(p), _currentScan));
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
|
@ -438,7 +675,6 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report the adds/changes/removes to the registered listeners
|
* Report the adds/changes/removes to the registered listeners
|
||||||
|
@ -449,7 +685,6 @@ public class Scanner extends AbstractLifeCycle
|
||||||
private synchronized void reportDifferences(Map<String, TimeNSize> currentScan, Map<String, TimeNSize> oldScan)
|
private synchronized void reportDifferences(Map<String, TimeNSize> currentScan, Map<String, TimeNSize> oldScan)
|
||||||
{
|
{
|
||||||
// scan the differences and add what was found to the map of notifications:
|
// scan the differences and add what was found to the map of notifications:
|
||||||
|
|
||||||
Set<String> oldScanKeys = new HashSet<>(oldScan.keySet());
|
Set<String> oldScanKeys = new HashSet<>(oldScan.keySet());
|
||||||
|
|
||||||
// Look for new and changed files
|
// Look for new and changed files
|
||||||
|
@ -489,16 +724,16 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("scanned " + _scanDirs + ": " + _notifications);
|
LOG.debug("scanned " + _scannables.keySet() + ": " + _notifications);
|
||||||
|
|
||||||
// Process notifications
|
// Process notifications
|
||||||
// Only process notifications that are for stable files (ie same in old and current scan).
|
// Only process notifications that are for stable files (ie same in old and current scan).
|
||||||
List<String> bulkChanges = new ArrayList<>();
|
List<String> bulkChanges = new ArrayList<>();
|
||||||
for (Iterator<Entry<String, Notification>> iter = _notifications.entrySet().iterator(); iter.hasNext(); )
|
for (Iterator<Entry<String, Notification>> iter = _notifications.entrySet().iterator(); iter.hasNext(); )
|
||||||
{
|
{
|
||||||
|
|
||||||
Entry<String, Notification> entry = iter.next();
|
Entry<String, Notification> entry = iter.next();
|
||||||
String file = entry.getKey();
|
String file = entry.getKey();
|
||||||
|
|
||||||
// Is the file stable?
|
// Is the file stable?
|
||||||
if (oldScan.containsKey(file))
|
if (oldScan.containsKey(file))
|
||||||
{
|
{
|
||||||
|
@ -529,57 +764,6 @@ public class Scanner extends AbstractLifeCycle
|
||||||
reportBulkChanges(bulkChanges);
|
reportBulkChanges(bulkChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get last modified time on a single file or recurse if
|
|
||||||
* the file is a directory.
|
|
||||||
*
|
|
||||||
* @param f file or directory
|
|
||||||
* @param scanInfoMap map of filenames to last modified times
|
|
||||||
*/
|
|
||||||
private void scanFile(File f, Map<String, TimeNSize> scanInfoMap, int depth)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!f.exists())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (f.isFile() || depth > 0 && _reportDirs && f.isDirectory())
|
|
||||||
{
|
|
||||||
if (_filter == null || _filter.accept(f.getParentFile(), f.getName()))
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("scan accepted {}", f);
|
|
||||||
String name = f.getCanonicalPath();
|
|
||||||
scanInfoMap.put(name, new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("scan rejected {}", f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it is a directory, scan if it is a known directory or the depth is OK.
|
|
||||||
if (f.isDirectory() && (depth < _scanDepth || _scanDepth == -1 || _scanDirs.contains(f)))
|
|
||||||
{
|
|
||||||
File[] files = f.listFiles();
|
|
||||||
if (files != null)
|
|
||||||
{
|
|
||||||
for (File file : files)
|
|
||||||
{
|
|
||||||
scanFile(file, scanInfoMap, depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LOG.warn("Error listing files in directory {}", f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOG.warn("Error scanning watched files", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void warn(Object listener, String filename, Throwable th)
|
private void warn(Object listener, String filename, Throwable th)
|
||||||
{
|
{
|
||||||
LOG.warn(listener + " failed on '" + filename, th);
|
LOG.warn(listener + " failed on '" + filename, th);
|
||||||
|
@ -648,6 +832,11 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report the list of filenames for which changes were detected.
|
||||||
|
*
|
||||||
|
* @param filenames names of all files added/changed/removed
|
||||||
|
*/
|
||||||
private void reportBulkChanges(List<String> filenames)
|
private void reportBulkChanges(List<String> filenames)
|
||||||
{
|
{
|
||||||
for (Listener l : _listeners)
|
for (Listener l : _listeners)
|
||||||
|
@ -665,7 +854,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* signal any scan cycle listeners that a scan has started
|
* Call ScanCycleListeners with start of scan
|
||||||
*/
|
*/
|
||||||
private void reportScanStart(int cycle)
|
private void reportScanStart(int cycle)
|
||||||
{
|
{
|
||||||
|
@ -686,7 +875,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sign
|
* Call ScanCycleListeners with end of scan.
|
||||||
*/
|
*/
|
||||||
private void reportScanEnd(int cycle)
|
private void reportScanEnd(int cycle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,8 @@ import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
@ -30,12 +32,14 @@ import java.util.concurrent.TimeUnit;
|
||||||
import org.eclipse.jetty.toolchain.test.FS;
|
import org.eclipse.jetty.toolchain.test.FS;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.eclipse.jetty.util.Scanner.Notification;
|
import org.eclipse.jetty.util.Scanner.Notification;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
||||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
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.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -61,6 +65,8 @@ public class ScannerTest
|
||||||
_scanner = new Scanner();
|
_scanner = new Scanner();
|
||||||
_scanner.addScanDir(_directory);
|
_scanner.addScanDir(_directory);
|
||||||
_scanner.setScanInterval(0);
|
_scanner.setScanInterval(0);
|
||||||
|
_scanner.setReportDirs(false);
|
||||||
|
_scanner.setReportExistingFilesOnStartup(false);
|
||||||
_scanner.addListener(new Scanner.DiscreteListener()
|
_scanner.addListener(new Scanner.DiscreteListener()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -89,8 +95,8 @@ public class ScannerTest
|
||||||
_bulk.add(filenames);
|
_bulk.add(filenames);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_scanner.start();
|
|
||||||
|
|
||||||
|
_scanner.start();
|
||||||
_scanner.scan();
|
_scanner.scan();
|
||||||
|
|
||||||
assertTrue(_queue.isEmpty());
|
assertTrue(_queue.isEmpty());
|
||||||
|
@ -116,6 +122,155 @@ public class ScannerTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDepth() throws Exception
|
||||||
|
{
|
||||||
|
File root = new File (_directory, "root");
|
||||||
|
FS.ensureDirExists(root);
|
||||||
|
FS.touch(new File(root, "foo.foo"));
|
||||||
|
FS.touch(new File(root, "foo2.foo"));
|
||||||
|
File dir = new File(root, "xxx");
|
||||||
|
FS.ensureDirExists(dir);
|
||||||
|
File x1 = new File(dir, "xxx.foo");
|
||||||
|
FS.touch(x1);
|
||||||
|
File x2 = new File(dir, "xxx2.foo");
|
||||||
|
FS.touch(x2);
|
||||||
|
File dir2 = new File(dir, "yyy");
|
||||||
|
FS.ensureDirExists(dir2);
|
||||||
|
File y1 = new File(dir2, "yyy.foo");
|
||||||
|
FS.touch(y1);
|
||||||
|
File y2 = new File(dir2, "yyy2.foo");
|
||||||
|
FS.touch(y2);
|
||||||
|
|
||||||
|
BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();
|
||||||
|
Scanner scanner = new Scanner();
|
||||||
|
scanner.setScanInterval(0);
|
||||||
|
scanner.setScanDepth(0);
|
||||||
|
scanner.setReportDirs(true);
|
||||||
|
scanner.setReportExistingFilesOnStartup(true);
|
||||||
|
scanner.addDirectory(root.toPath());
|
||||||
|
scanner.addListener(new Scanner.DiscreteListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void fileRemoved(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.REMOVED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileChanged(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileAdded(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.ADDED));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scanner.start();
|
||||||
|
Event e = queue.take();
|
||||||
|
assertNotNull(e);
|
||||||
|
assertEquals(Notification.ADDED, e._notification);
|
||||||
|
assertTrue(e._filename.endsWith(root.getName()));
|
||||||
|
queue.clear();
|
||||||
|
scanner.stop();
|
||||||
|
scanner.reset();
|
||||||
|
|
||||||
|
//Depth one should report the dir itself and its file and dir direct children
|
||||||
|
scanner.setScanDepth(1);
|
||||||
|
scanner.addDirectory(root.toPath());
|
||||||
|
scanner.start();
|
||||||
|
assertEquals(4, queue.size());
|
||||||
|
queue.clear();
|
||||||
|
scanner.stop();
|
||||||
|
scanner.reset();
|
||||||
|
|
||||||
|
//Depth 2 should report the dir itself, all file children, xxx and xxx's children
|
||||||
|
scanner.setScanDepth(2);
|
||||||
|
scanner.addDirectory(root.toPath());
|
||||||
|
scanner.start();
|
||||||
|
|
||||||
|
assertEquals(7, queue.size());
|
||||||
|
scanner.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPatterns() throws Exception
|
||||||
|
{
|
||||||
|
//test include and exclude patterns
|
||||||
|
File root = new File(_directory, "proot");
|
||||||
|
FS.ensureDirExists(root);
|
||||||
|
|
||||||
|
File ttt = new File(root, "ttt.txt");
|
||||||
|
FS.touch(ttt);
|
||||||
|
FS.touch(new File(root, "ttt.foo"));
|
||||||
|
File dir = new File(root, "xxx");
|
||||||
|
FS.ensureDirExists(dir);
|
||||||
|
|
||||||
|
File x1 = new File(dir, "ttt.xxx");
|
||||||
|
FS.touch(x1);
|
||||||
|
File x2 = new File(dir, "xxx.txt");
|
||||||
|
FS.touch(x2);
|
||||||
|
|
||||||
|
File dir2 = new File(dir, "yyy");
|
||||||
|
FS.ensureDirExists(dir2);
|
||||||
|
File y1 = new File(dir2, "ttt.yyy");
|
||||||
|
FS.touch(y1);
|
||||||
|
File y2 = new File(dir2, "yyy.txt");
|
||||||
|
FS.touch(y2);
|
||||||
|
|
||||||
|
BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();
|
||||||
|
//only scan the *.txt files for changes
|
||||||
|
Scanner scanner = new Scanner();
|
||||||
|
IncludeExcludeSet<PathMatcher, Path> pattern = scanner.addDirectory(root.toPath());
|
||||||
|
pattern.exclude(root.toPath().getFileSystem().getPathMatcher("glob:**/*.foo"));
|
||||||
|
pattern.exclude(root.toPath().getFileSystem().getPathMatcher("glob:**/ttt.xxx"));
|
||||||
|
scanner.setScanInterval(0);
|
||||||
|
scanner.setScanDepth(2); //should never see any files from subdir yyy
|
||||||
|
scanner.setReportDirs(false);
|
||||||
|
scanner.setReportExistingFilesOnStartup(false);
|
||||||
|
scanner.addListener(new Scanner.DiscreteListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void fileRemoved(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.REMOVED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileChanged(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileAdded(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.ADDED));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scanner.start();
|
||||||
|
assertTrue(queue.isEmpty());
|
||||||
|
|
||||||
|
Thread.sleep(1100); // make sure time in seconds changes
|
||||||
|
FS.touch(ttt);
|
||||||
|
FS.touch(x2);
|
||||||
|
FS.touch(x1);
|
||||||
|
FS.touch(y2);
|
||||||
|
scanner.scan();
|
||||||
|
scanner.scan(); //2 scans for file to be considered settled
|
||||||
|
|
||||||
|
assertThat(queue.size(), Matchers.equalTo(2));
|
||||||
|
for (Event e : queue)
|
||||||
|
{
|
||||||
|
assertTrue(e._filename.endsWith("ttt.txt") || e._filename.endsWith("xxx.txt"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisabledOnOs(WINDOWS) // TODO: needs review
|
@DisabledOnOs(WINDOWS) // TODO: needs review
|
||||||
@DisabledIfSystemProperty(named = "env", matches = "ci") // TODO: SLOW, needs review
|
@DisabledIfSystemProperty(named = "env", matches = "ci") // TODO: SLOW, needs review
|
||||||
|
@ -126,6 +281,7 @@ public class ScannerTest
|
||||||
// takes 2 scans to notice a0 and check that it is stable
|
// takes 2 scans to notice a0 and check that it is stable
|
||||||
_scanner.scan();
|
_scanner.scan();
|
||||||
_scanner.scan();
|
_scanner.scan();
|
||||||
|
|
||||||
Event event = _queue.poll();
|
Event event = _queue.poll();
|
||||||
assertNotNull(event, "Event should not be null");
|
assertNotNull(event, "Event should not be null");
|
||||||
assertEquals(_directory + "/a0", event._filename);
|
assertEquals(_directory + "/a0", event._filename);
|
||||||
|
|
Loading…
Reference in New Issue