diff --git a/jetty-server/src/main/config/modules/ext.mod b/jetty-server/src/main/config/modules/ext.mod
index 1207bddc391..56b10f7ea42 100644
--- a/jetty-server/src/main/config/modules/ext.mod
+++ b/jetty-server/src/main/config/modules/ext.mod
@@ -1,9 +1,9 @@
#
-# Module to add all lib/ext/*.jar files to classpath
+# Module to add all lib/ext/**.jar files to classpath
#
[lib]
-regex:lib/ext/.*\.jar$
+lib/ext/**.jar
[files]
lib/
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java
index 8fb78424149..2c22ce37aa4 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java
@@ -19,21 +19,21 @@
package org.eclipse.jetty.start;
import java.io.File;
-import java.io.FileFilter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.file.FileVisitOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.List;
-import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.eclipse.jetty.start.FS.RelativeRegexFilter;
-
/**
* File access for ${jetty.home}
, ${jetty.base}
, directories.
*
@@ -45,6 +45,9 @@ import org.eclipse.jetty.start.FS.RelativeRegexFilter;
*/
public class BaseHome
{
+ private final static EnumSet SEARCH_VISIT_OPTIONS = EnumSet.of(FileVisitOption.FOLLOW_LINKS);;
+ private final static int MAX_SEARCH_DEPTH = 30;
+
private File homeDir;
private File baseDir;
@@ -119,7 +122,7 @@ public class BaseHome
*
* - If exists relative to
${jetty.base}
, return that reference
* - If exists relative to
${jetty.home}
, return that reference
- * - Otherwise return absolute path reference
+ * - Otherwise return absolute path reference (standard java logic)
*
*
* @param path
@@ -151,6 +154,140 @@ public class BaseHome
return new File(rpath);
}
+ /**
+ * Get a List of {@link Path}s from a provided pattern.
+ *
+ * Resolution Steps:
+ *
+ * - If the pattern starts with "regex:" or "glob:" then a standard {@link PathMatcher} is built using
+ * {@link java.nio.file.FileSystem#getPathMatcher(String)} as a file search.
+ * - If pattern starts with a known filesystem root (using information from {@link java.nio.file.FileSystem#getRootDirectories()}) then this is assumed to
+ * be a absolute file system pattern.
+ * - All other patterns are treated as relative to BaseHome information:
+ *
+ * - Search ${jetty.home} first
+ * - Search ${jetty.base} for overrides
+ *
+ *
+ *
+ *
+ * Pattern examples:
+ *
+ * lib/logging/*.jar
+ * - Relative pattern, not recursive, search
${jetty.home}
then ${jetty.base}
for lib/logging/*.jar content
+ *
+ * lib/**/*-dev.jar
+ * - Relative pattern, recursive search
${jetty.home}
then ${jetty.base}
for files under lib
ending in
+ * -dev.jar
+ *
+ *
+ * etc/jetty.xml
+ * Relative pattern, no glob, search for ${jetty.home}/etc/jetty.xml
then ${jetty.base}/etc/jetty.xml
+ *
+ * glob:/opt/app/common/*-corp.jar
+ * PathMapper pattern, glob, search /opt/app/common/
for *-corp.jar
+ *
+ *
+ *
+ *
+ * Notes:
+ *
+ * - FileSystem case sensitivity is implementation specific (eg: linux is case-sensitive, windows is case-insensitive).
+ * See {@link java.nio.file.FileSystem#getPathMatcher(String)} for more details
+ * - Pattern slashes are implementation neutral (use '/' always and you'll be fine)
+ * - Recursive searching is limited to 30 levels deep (not configurable)
+ * - File System loops are detected and skipped
+ *
+ *
+ * @param pattern
+ * the pattern to search.
+ * @return the collection of paths found
+ * @throws IOException
+ * if error during search operation
+ */
+ public List getPaths(String pattern) throws IOException
+ {
+ List hits = new ArrayList<>();
+
+ if (PathMatchers.isAbsolute(pattern))
+ {
+ Path root = PathMatchers.getSearchRoot(pattern);
+ PathMatcher matcher = PathMatchers.getMatcher(pattern);
+
+ if (FS.isValidDirectory(root))
+ {
+ PathFinder finder = new PathFinder();
+ finder.setFileMatcher(matcher);
+ finder.setBase(root);
+ Files.walkFileTree(root,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder);
+ hits.addAll(finder.getHits());
+ }
+ }
+ else
+ {
+ Path relativePath = PathMatchers.getSearchRoot(pattern);
+ PathMatcher matcher = PathMatchers.getMatcher(pattern);
+ PathFinder finder = new PathFinder();
+ finder.setFileMatcher(matcher);
+
+ Path homePath = homeDir.toPath().resolve(relativePath);
+
+ if (FS.isValidDirectory(homePath))
+ {
+ finder.setBase(homePath);
+ Files.walkFileTree(homePath,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder);
+ }
+
+ if (isBaseDifferent())
+ {
+ Path basePath = baseDir.toPath().resolve(relativePath);
+ if (FS.isValidDirectory(basePath))
+ {
+ finder.setBase(basePath);
+ Files.walkFileTree(basePath,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder);
+ }
+ }
+ hits.addAll(finder.getHits());
+ }
+
+ Collections.sort(hits,new NaturalSort.Paths());
+ return hits;
+ }
+
+ /**
+ * Search specified Path with pattern and return hits
+ *
+ * @param dir
+ * the path to a directory to start search from
+ * @param searchDepth
+ * the number of directories deep to perform the search
+ * @param pattern
+ * the raw pattern to use for the search (must be relative)
+ * @return the list of Paths found
+ * @throws IOException
+ * if unable to search the path
+ */
+ public List getPaths(Path dir, int searchDepth, String pattern) throws IOException
+ {
+ if (PathMatchers.isAbsolute(pattern))
+ {
+ throw new RuntimeException("Pattern cannot be absolute: " + pattern);
+ }
+
+ List hits = new ArrayList<>();
+ if (FS.isValidDirectory(dir))
+ {
+ PathMatcher matcher = PathMatchers.getMatcher(pattern);
+ PathFinder finder = new PathFinder();
+ finder.setFileMatcher(matcher);
+ finder.setBase(dir);
+ Files.walkFileTree(dir,SEARCH_VISIT_OPTIONS,searchDepth,finder);
+ hits.addAll(finder.getHits());
+ Collections.sort(hits,new NaturalSort.Paths());
+ }
+ return hits;
+ }
+
public String getHome()
{
return homeDir.getAbsolutePath();
@@ -213,183 +350,6 @@ public class BaseHome
return homeDir.compareTo(baseDir) != 0;
}
- /**
- * Get all of the files that are in a specific relative directory.
- *
- * If the same found path exists in both ${jetty.base}
and ${jetty.home}
, then the one in ${jetty.base}
is returned
- * (it overrides the one in ${jetty.home})
- *
- * @param relPathToDirectory
- * the relative path to the directory
- * @return the list of files found.
- */
- public List listFiles(String relPathToDirectory)
- {
- return listFiles(relPathToDirectory,FS.AllFilter.INSTANCE);
- }
-
- /**
- * Get all of the files that are in a specific relative directory, with applied {@link FileFilter}
- *
- * If the same found path exists in both ${jetty.base}
and ${jetty.home}
, then the one in ${jetty.base}
is returned
- * (it overrides the one in ${jetty.home})
- *
- * @param relPathToDirectory
- * the relative path to the directory
- * @param filter
- * the filter to use
- * @return the list of files found.
- */
- public List listFiles(String relPathToDirectory, FileFilter filter)
- {
- Objects.requireNonNull(filter,"FileFilter cannot be null");
-
- File homePath = new File(homeDir,FS.separators(relPathToDirectory));
- List homeFiles = new ArrayList<>();
- if (FS.canReadDirectory(homePath))
- {
- homeFiles.addAll(Arrays.asList(homePath.listFiles(filter)));
- }
-
- if (isBaseDifferent())
- {
- // merge
- File basePath = new File(baseDir,FS.separators(relPathToDirectory));
- List ret = new ArrayList<>();
- if (FS.canReadDirectory(basePath))
- {
- File baseFiles[] = basePath.listFiles(filter);
-
- if (baseFiles != null)
- {
- for (File base : baseFiles)
- {
- String relpath = toRelativePath(baseDir,base);
- File home = new File(homeDir,FS.separators(relpath));
- if (home.exists())
- {
- homeFiles.remove(home);
- }
- ret.add(base);
- }
- }
- }
-
- // add any remaining home files.
- ret.addAll(homeFiles);
-
- Collections.sort(ret,new NaturalSort.Files());
- return ret;
- }
- else
- {
- // simple return
- Collections.sort(homeFiles,new NaturalSort.Files());
- return homeFiles;
- }
- }
-
- /**
- * Get all of the files that are in a specific relative directory, with applied regex.
- *
- * If the same found path exists in both ${jetty.base}
and ${jetty.home}
, then the one in ${jetty.base}
is returned
- * (it overrides the one in ${jetty.home})
- *
- * All regex paths are assumed to be in unix notation (use of "/"
to separate paths, as "\"
is used to escape in regex)
- *
- * @param regex
- * the regex to use to match against the found files.
- * @return the list of files found.
- */
- public List listFilesRegex(String regex)
- {
- Objects.requireNonNull(regex,"Glob cannot be null");
-
- Pattern pattern = Pattern.compile(regex);
-
- List homeFiles = new ArrayList<>();
- if (FS.canReadDirectory(homeDir))
- {
- StartLog.debug("Finding files in ${jetty.home} that match: %s",regex);
- recurseDir(homeFiles,homeDir,new FS.RelativeRegexFilter(homeDir,pattern));
- StartLog.debug("Found %,d files",homeFiles.size());
- }
-
- if (isBaseDifferent())
- {
- // merge
- List ret = new ArrayList<>();
- if (FS.canReadDirectory(baseDir))
- {
- List baseFiles = new ArrayList<>();
- StartLog.debug("Finding files in ${jetty.base} that match: %s",regex);
- recurseDir(baseFiles,baseDir,new FS.RelativeRegexFilter(baseDir,pattern));
- StartLog.debug("Found %,d files",baseFiles.size());
-
- for (File base : baseFiles)
- {
- String relpath = toRelativePath(baseDir,base);
- File home = new File(homeDir,FS.separators(relpath));
- if (home.exists())
- {
- homeFiles.remove(home);
- }
- ret.add(base);
- }
- }
-
- // add any remaining home files.
- ret.addAll(homeFiles);
- StartLog.debug("Merged Files: %,d files%n",ret.size());
-
- Collections.sort(ret,new NaturalSort.Files());
- return ret;
- }
- else
- {
- // simple return
- Collections.sort(homeFiles,new NaturalSort.Files());
- return homeFiles;
- }
- }
-
- private void recurseDir(List files, File dir, RelativeRegexFilter filter)
- {
- // find matches first
- files.addAll(Arrays.asList(dir.listFiles(filter)));
-
- // now dive down into sub-directories
- for (File subdir : dir.listFiles(FS.DirFilter.INSTANCE))
- {
- recurseDir(files,subdir,filter);
- }
- }
-
- /**
- * Collect the list of files in both ${jetty.base}
and ${jetty.home}
, even if the same file shows up in both places.
- */
- public List rawListFiles(String relPathToDirectory, FileFilter filter)
- {
- Objects.requireNonNull(filter,"FileFilter cannot be null");
-
- List ret = new ArrayList<>();
-
- // Home Dir
- File homePath = new File(homeDir,FS.separators(relPathToDirectory));
- ret.addAll(Arrays.asList(homePath.listFiles(filter)));
-
- if (isBaseDifferent())
- {
- // Base Dir
- File basePath = new File(baseDir,FS.separators(relPathToDirectory));
- ret.addAll(Arrays.asList(basePath.listFiles(filter)));
- }
-
- // Sort
- Collections.sort(ret,new NaturalSort.Files());
- return ret;
- }
-
public void setBaseDir(File dir)
{
try
@@ -416,12 +376,6 @@ public class BaseHome
}
}
- // TODO - inline
- private String toRelativePath(File dir, File path)
- {
- return FS.toRelativePath(dir,path);
- }
-
/**
* Convenience method for toShortForm(file.getCanonicalPath())
*/
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java b/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java
index 5fd41b92dd5..de5f02676a6 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java
@@ -22,11 +22,15 @@ import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
import java.util.Locale;
import java.util.regex.Pattern;
public class FS
{
+ @Deprecated
public static class AllFilter implements FileFilter
{
public static final AllFilter INSTANCE = new AllFilter();
@@ -37,7 +41,8 @@ public class FS
return true;
}
}
-
+
+ @Deprecated
public static class DirFilter implements FileFilter
{
public static final DirFilter INSTANCE = new DirFilter();
@@ -48,7 +53,8 @@ public class FS
return path.isDirectory();
}
}
-
+
+ @Deprecated
public static class RelativeRegexFilter implements FileFilter
{
private final File baseDir;
@@ -65,12 +71,13 @@ public class FS
{
// get relative path
String relativePath = FS.toRelativePath(baseDir,path);
-
+
// see if it matches
return (pattern.matcher(relativePath).matches());
}
}
+ @Deprecated
public static class FilenameRegexFilter implements FileFilter
{
private final Pattern pattern;
@@ -87,6 +94,7 @@ public class FS
}
}
+ @Deprecated
public static class FileNamesFilter implements FileFilter
{
private final String filenames[];
@@ -114,6 +122,7 @@ public class FS
}
}
+ @Deprecated
public static class IniFilter extends FilenameRegexFilter
{
public IniFilter()
@@ -122,6 +131,7 @@ public class FS
}
}
+ @Deprecated
public static class XmlFilter extends FilenameRegexFilter
{
public XmlFilter()
@@ -130,11 +140,36 @@ public class FS
}
}
+ public static boolean isValidDirectory(Path path)
+ {
+ LinkOption lopts[] = new LinkOption[0];
+ if (!Files.exists(path,lopts))
+ {
+ // doesn't exist, not a valid directory
+ return false;
+ }
+
+ if (!Files.isDirectory(path,lopts))
+ {
+ // not a directory (as expected)
+ StartLog.warn("Not a directory: " + path);
+ return false;
+ }
+
+ return true;
+ }
+
public static boolean canReadDirectory(File path)
{
return (path.exists() && path.isDirectory() && path.canRead());
}
+ public static boolean canReadDirectory(Path path)
+ {
+ LinkOption lopts[] = new LinkOption[0];
+ return Files.exists(path,lopts) && Files.isDirectory(path,lopts) && Files.isReadable(path);
+ }
+
public static boolean canReadFile(File path)
{
return (path.exists() && path.isFile() && path.canRead());
@@ -168,7 +203,7 @@ public class FS
throw new IOException("Unable to create directory: " + dir.getAbsolutePath());
}
}
-
+
public static void ensureDirectoryWritable(File dir) throws IOException
{
if (!dir.exists())
@@ -194,7 +229,7 @@ public class FS
{
return filename.toLowerCase(Locale.ENGLISH).endsWith(".xml");
}
-
+
public static String toRelativePath(File baseDir, File path)
{
return baseDir.toURI().relativize(path.toURI()).toASCIIString();
@@ -216,4 +251,9 @@ public class FS
}
return ret.toString();
}
+
+ public static boolean exists(Path path)
+ {
+ return Files.exists(path,new LinkOption[0]);
+ }
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
index c196affc580..e41ed7b417a 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
@@ -18,9 +18,7 @@
package org.eclipse.jetty.start;
-import static org.eclipse.jetty.start.UsageException.ERR_INVOKE_MAIN;
-import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED;
-import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN;
+import static org.eclipse.jetty.start.UsageException.*;
import java.io.BufferedReader;
import java.io.File;
@@ -39,6 +37,7 @@ import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URL;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -534,17 +533,12 @@ public class Main
File start_d = baseHome.getBaseFile("start.d");
if (FS.canReadDirectory(start_d))
{
- List files = new ArrayList<>();
- for (File file : start_d.listFiles(new FS.IniFilter()))
+ List paths = baseHome.getPaths(start_d.toPath(),1,"*.ini");
+ Collections.sort(paths,new NaturalSort.Paths());
+ for (Path path: paths)
{
- files.add(file);
- }
-
- Collections.sort(files,new NaturalSort.Files());
- for (File file : files)
- {
- StartLog.debug("Reading ${jetty.base}/start.d/%s - %s",file.getName(),file);
- args.parse(baseHome,new StartIni(file));
+ StartLog.debug("Reading ${jetty.base}/start.d/%s - %s",path.getFileName(),path);
+ args.parse(baseHome,new StartIni(path));
}
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
index 95bd8076f46..2bf6b4c5aba 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
@@ -21,6 +21,7 @@ package org.eclipse.jetty.start;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -45,7 +46,7 @@ public class Modules implements Iterable
* ex: modules/npn/npn-1.7.0_01.mod (property expansion resolves to non-existent file)
*/
private Set missingModules = new HashSet();
-
+
private int maxDepth = -1;
private Set asNameSet(Set moduleSet)
@@ -294,10 +295,10 @@ public class Modules implements Iterable
private void findParents(Module module, Map ret)
{
- ret.put(module.getName(), module);
+ ret.put(module.getName(),module);
for (Module parent : module.getParentEdges())
{
- ret.put(parent.getName(), parent);
+ ret.put(parent.getName(),parent);
findParents(parent,ret);
}
}
@@ -371,13 +372,13 @@ public class Modules implements Iterable
public void registerAll(BaseHome basehome, StartArgs args) throws IOException
{
- for (File file : basehome.listFiles("modules",new FS.FilenameRegexFilter("^.*\\.mod$")))
+ for (Path path : basehome.getPaths("modules/*.mod"))
{
- registerModule(basehome,args,file);
+ registerModule(basehome,args,path.toFile());
}
// load missing post-expanded dependent modules
- boolean done = false;
+ boolean done = false;
while (!done)
{
done = true;
@@ -399,14 +400,14 @@ public class Modules implements Iterable
for (String missingParent : missingParents)
{
File file = basehome.getFile("modules/" + missingParent + ".mod");
- if ( FS.canReadFile(file) )
+ if (FS.canReadFile(file))
{
Module module = registerModule(basehome,args,file);
updateParentReferencesTo(module);
}
else
{
- StartLog.debug("Missing module definition: [ Mod: %s | File: %s]", missingParent, file);
+ StartLog.debug("Missing module definition: [ Mod: %s | File: %s]",missingParent,file);
missingModules.add(missingParent);
}
}
@@ -440,7 +441,7 @@ public class Modules implements Iterable
*/
public List resolveEnabled()
{
- Map active = new HashMap();
+ Map active = new HashMap();
for (Module module : modules.values())
{
@@ -455,20 +456,20 @@ public class Modules implements Iterable
*
* Ex: npn should match anything under npn/
*/
- for ( String missing : missingModules )
+ for (String missing : missingModules)
{
- for (String activeModule: active.keySet())
- {
- if ( missing.startsWith(activeModule) )
+ for (String activeModule : active.keySet())
+ {
+ if (missing.startsWith(activeModule))
{
- StartLog.warn("** Unable to continue, required dependency missing. [%s]", missing);
+ StartLog.warn("** Unable to continue, required dependency missing. [%s]",missing);
StartLog.warn("** As configured, Jetty is unable to start due to a missing enabled module dependency.");
StartLog.warn("** This may be due to a transitive dependency akin to spdy on npn, which resolves based on the JDK in use.");
return Collections.emptyList();
}
}
}
-
+
List ordered = new ArrayList<>();
ordered.addAll(active.values());
Collections.sort(ordered,new Module.DepthComparator());
@@ -477,7 +478,7 @@ public class Modules implements Iterable
public Set resolveParentModulesOf(String moduleName)
{
- Map ret = new HashMap<>();
+ Map ret = new HashMap<>();
Module module = get(moduleName);
findParents(module,ret);
return ret.keySet();
@@ -524,4 +525,26 @@ public class Modules implements Iterable
m.setParentNames(resolvedParents);
}
}
+
+ @Override
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.append("Modules[");
+ str.append("count=").append(modules.size());
+ str.append(",<");
+ boolean delim = false;
+ for (String name : modules.keySet())
+ {
+ if (delim)
+ {
+ str.append(',');
+ }
+ str.append(name);
+ delim = true;
+ }
+ str.append(">");
+ str.append("]");
+ return str.toString();
+ }
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/NaturalSort.java b/jetty-start/src/main/java/org/eclipse/jetty/start/NaturalSort.java
index 042b326370d..838a96d9216 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/NaturalSort.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/NaturalSort.java
@@ -19,6 +19,7 @@
package org.eclipse.jetty.start;
import java.io.File;
+import java.nio.file.Path;
import java.text.CollationKey;
import java.text.Collator;
import java.util.Comparator;
@@ -28,6 +29,19 @@ import java.util.Comparator;
*/
public class NaturalSort
{
+ public static class Paths implements Comparator
+ {
+ private final Collator collator = Collator.getInstance();
+
+ @Override
+ public int compare(Path o1, Path o2)
+ {
+ CollationKey key1 = collator.getCollationKey(o1.toString());
+ CollationKey key2 = collator.getCollationKey(o2.toString());
+ return key1.compareTo(key2);
+ }
+ }
+
public static class Files implements Comparator
{
private final Collator collator = Collator.getInstance();
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/PathFinder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/PathFinder.java
new file mode 100644
index 00000000000..10c52197bcf
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/PathFinder.java
@@ -0,0 +1,161 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.start;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystemLoopException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class PathFinder extends SimpleFileVisitor
+{
+ private boolean includeDirsInResults = false;
+ private Map hits = new HashMap<>();
+ private Path basePath = null;
+ private PathMatcher dirMatcher = PathMatchers.getNonHidden();
+ private PathMatcher fileMatcher = PathMatchers.getNonHidden();
+
+ private void addHit(Path path)
+ {
+ String relPath = basePath.relativize(path).toString();
+ StartLog.debug("addHit(" + path + ") = [" + relPath + "," + path + "]");
+ hits.put(relPath,path);
+ }
+
+ public PathMatcher getDirMatcher()
+ {
+ return dirMatcher;
+ }
+
+ public PathMatcher getFileMatcher()
+ {
+ return fileMatcher;
+ }
+
+ public List getHitList()
+ {
+ List ret = new ArrayList<>();
+ for (Path path : hits.values())
+ {
+ ret.add(path.toFile());
+ }
+ return ret;
+ }
+
+ public Collection getHits()
+ {
+ return hits.values();
+ }
+
+ public boolean isIncludeDirsInResults()
+ {
+ return includeDirsInResults;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
+ {
+ if (dirMatcher.matches(dir))
+ {
+ StartLog.debug("Following dir: " + dir);
+ if (includeDirsInResults)
+ {
+ addHit(dir);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ else
+ {
+ StartLog.debug("Skipping dir: " + dir);
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+
+ /**
+ * Set the active basePath, used for resolving relative paths.
+ *
+ * When a hit arrives for a subsequent find that has the same relative path as a prior hit, the new hit overrides the prior path as the active hit.
+ *
+ * @param basePath
+ * the basePath to tag all hits with
+ */
+ public void setBase(Path basePath)
+ {
+ this.basePath = basePath;
+ }
+
+ public void setDirMatcher(PathMatcher dirMatcher)
+ {
+ this.dirMatcher = dirMatcher;
+ }
+
+ public void setFileMatcher(PathMatcher fileMatcher)
+ {
+ this.fileMatcher = fileMatcher;
+ }
+
+ public void setFileMatcher(String pattern)
+ {
+ this.fileMatcher = PathMatchers.getMatcher(pattern);
+ }
+
+ public void setIncludeDirsInResults(boolean includeDirsInResults)
+ {
+ this.includeDirsInResults = includeDirsInResults;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
+ {
+ if (fileMatcher.matches(file))
+ {
+ StartLog.debug("Found file: " + file);
+ addHit(file);
+ }
+ else
+ {
+ StartLog.debug("Ignoring file: " + file);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
+ {
+ if (exc instanceof FileSystemLoopException)
+ {
+ StartLog.warn("skipping detected filesystem loop: " + file);
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ else
+ {
+ StartLog.warn(exc);
+ return super.visitFileFailed(file,exc);
+ }
+ }
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/PathMatchers.java b/jetty-start/src/main/java/org/eclipse/jetty/start/PathMatchers.java
new file mode 100644
index 00000000000..609c8b211aa
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/PathMatchers.java
@@ -0,0 +1,208 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.start;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+
+/**
+ * Common PathMatcher implementations.
+ */
+public class PathMatchers
+{
+ private static class NonHiddenMatcher implements PathMatcher
+ {
+ @Override
+ public boolean matches(Path path)
+ {
+ try
+ {
+ return !Files.isHidden(path);
+ }
+ catch (IOException e)
+ {
+ StartLog.debug(e);
+ return false;
+ }
+ }
+ }
+
+ private static final char GLOB_CHARS[] = "*?".toCharArray();
+ private static final char SYNTAXED_GLOB_CHARS[] = "{}[]|:".toCharArray();
+ private static final Path EMPTY_PATH = new File(".").toPath();
+
+ /**
+ * Convert a pattern to a Path object.
+ *
+ * @param pattern
+ * the raw pattern (can contain "glob:" or "regex:" syntax indicator)
+ * @return the Path version of the pattern provided.
+ */
+ private static Path asPath(String pattern)
+ {
+ String test = pattern;
+ if (test.startsWith("glob:"))
+ {
+ test = test.substring("glob:".length());
+ }
+ else if (test.startsWith("regex:"))
+ {
+ test = test.substring("regex:".length());
+ }
+ return new File(test).toPath();
+ }
+
+ public static PathMatcher getMatcher(String pattern)
+ {
+ FileSystem fs = FileSystems.getDefault();
+
+ // If using FileSystem.getPathMatcher() with "glob:" or "regex:"
+ // use FileSystem default pattern behavior
+ if (pattern.startsWith("glob:") || pattern.startsWith("regex:"))
+ {
+ StartLog.debug("Using Standard " + fs.getClass().getName() + " pattern: " + pattern);
+ return fs.getPathMatcher(pattern);
+ }
+
+ // If the pattern starts with a root path then its assumed to
+ // be a full system path
+ for (Path root : fs.getRootDirectories())
+ {
+ StartLog.debug("root: " + root);
+ if (pattern.startsWith(root.toString()))
+ {
+ String pat = "glob:" + pattern;
+ StartLog.debug("Using absolute path pattern: " + pat);
+ return fs.getPathMatcher(pat);
+ }
+ }
+
+ // Doesn't start with filesystem root, then assume the pattern
+ // is a relative file path pattern.
+ String pat = "glob:**/" + pattern;
+ StartLog.debug("Using relative path pattern: " + pat);
+ return fs.getPathMatcher(pat);
+ }
+
+ public static PathMatcher getNonHidden()
+ {
+ return new NonHiddenMatcher();
+ }
+
+ /**
+ * Provide the non-glob / non-regex prefix on the pattern as a Path reference.
+ *
+ * @param pattern
+ * the pattern to test
+ * @return the Path representing the search root for the pattern provided.
+ */
+ public static Path getSearchRoot(final String pattern)
+ {
+ Path path = asPath(pattern);
+ Path test = path.getRoot();
+
+ boolean isSyntaxed = pattern.startsWith("glob:") || pattern.startsWith("regex:");
+
+ int len = path.getNameCount();
+ for (int i = 0; i < len; i++)
+ {
+ Path part = path.getName(i);
+ if (isGlob(part.toString(),isSyntaxed))
+ {
+ // found a glob part, return prior parts now
+ break;
+ }
+
+ // is this the last entry?
+ if (i == (len - 1))
+ {
+ // always return prior entries
+ break;
+ }
+
+ if (test == null)
+ {
+ test = part;
+ }
+ else
+ {
+ test = test.resolve(part);
+ }
+ }
+
+ if (test == null)
+ {
+ return EMPTY_PATH;
+ }
+ return test;
+ }
+
+ /**
+ * Tests if provided pattern is an absolute reference (or not)
+ *
+ * @param pattern
+ * the pattern to test
+ * @return true if pattern is an absolute reference.
+ */
+ public static boolean isAbsolute(final String pattern)
+ {
+ return asPath(pattern).isAbsolute();
+ }
+
+ /**
+ * Determine if part is a glob pattern.
+ *
+ * @param part
+ * the string to check
+ * @param syntaxed
+ * true if overall pattern is syntaxed with "glob:"
or "regex:"
+ * @return true if part has glob characters
+ */
+ private static boolean isGlob(String part, boolean syntaxed)
+ {
+ int len = part.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = part.charAt(i);
+ for (char g : GLOB_CHARS)
+ {
+ if (c == g)
+ {
+ return true;
+ }
+ }
+ if (syntaxed)
+ {
+ for (char g : SYNTAXED_GLOB_CHARS)
+ {
+ if (c == g)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
index 9892127b83a..eb419bbc01d 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
@@ -21,9 +21,9 @@ package org.eclipse.jetty.start;
import static org.eclipse.jetty.start.UsageException.*;
import java.io.File;
-import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -325,66 +325,10 @@ public class StartArgs
StartLog.debug("rawlibref = " + rawlibref);
String libref = properties.expand(rawlibref);
StartLog.debug("expanded = " + libref);
-
- if (libref.startsWith("regex:"))
+
+ for (Path libpath : baseHome.getPaths(libref))
{
- String regex = libref.substring("regex:".length());
- for (File libfile : baseHome.listFilesRegex(regex))
- {
- classpath.addComponent(libfile);
- }
- continue;
- }
-
- libref = FS.separators(libref);
-
- // Any globs here?
- if (libref.contains("*"))
- {
- // Glob Reference
- int idx = libref.lastIndexOf(File.separatorChar);
-
- String relativePath = "/";
- String filenameRef = libref;
- if (idx >= 0)
- {
- relativePath = libref.substring(0,idx);
- filenameRef = libref.substring(idx + 1);
- }
-
- StringBuilder regex = new StringBuilder();
- regex.append('^');
- for (char c : filenameRef.toCharArray())
- {
- switch (c)
- {
- case '*':
- regex.append(".*");
- break;
- case '.':
- regex.append("\\.");
- break;
- default:
- regex.append(c);
- }
- }
- regex.append('$');
- StartLog.debug("regex = " + regex);
-
- FileFilter filter = new FS.FilenameRegexFilter(regex.toString());
-
- List libs = baseHome.listFiles(relativePath,filter);
- StartLog.debug("found " + libs.size() + " libs");
- for (File libfile : libs)
- {
- classpath.addComponent(libfile);
- }
- }
- else
- {
- // Straight Reference
- File libfile = baseHome.getFile(libref);
- classpath.addComponent(libfile);
+ classpath.addComponent(libpath.toFile());
}
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java
index c2635aeb72d..192e74adfdb 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java
@@ -21,6 +21,7 @@ package org.eclipse.jetty.start;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.Path;
/**
* Simple Start .INI handler
@@ -32,6 +33,11 @@ public class StartIni extends TextFile
super(file);
}
+ public StartIni(Path path) throws FileNotFoundException, IOException
+ {
+ this(path.toFile());
+ }
+
@Override
public void addUniqueLine(String line)
{
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java
index ef3ac686e2b..b2c19cbd50a 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java
@@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.*;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -32,7 +33,55 @@ import org.junit.Test;
public class BaseHomeTest
{
- private void assertFileList(BaseHome hb, String message, List expected, List files)
+ public static void assertPathList(BaseHome hb, String message, List expected, PathFinder finder)
+ {
+ List actual = new ArrayList<>();
+ for (Path path : finder.getHits())
+ {
+ actual.add(hb.toShortForm(path.toFile()));
+ }
+
+ if (actual.size() != expected.size())
+ {
+ System.out.printf("Actual Path(s): %,d hits%n",actual.size());
+ for (String path : actual)
+ {
+ System.out.printf(" %s%n",path);
+ }
+ System.out.printf("Expected Path(s): %,d entries%n",expected.size());
+ for (String path : expected)
+ {
+ System.out.printf(" %s%n",path);
+ }
+ }
+ Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));
+ }
+
+ public static void assertPathList(BaseHome hb, String message, List expected, List paths)
+ {
+ List actual = new ArrayList<>();
+ for (Path path : paths)
+ {
+ actual.add(hb.toShortForm(path.toFile()));
+ }
+
+ if (actual.size() != expected.size())
+ {
+ System.out.printf("Actual Path(s): %,d hits%n",actual.size());
+ for (String path : actual)
+ {
+ System.out.printf(" %s%n",path);
+ }
+ System.out.printf("Expected Path(s): %,d entries%n",expected.size());
+ for (String path : expected)
+ {
+ System.out.printf(" %s%n",path);
+ }
+ }
+ Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));
+ }
+
+ public static void assertFileList(BaseHome hb, String message, List expected, List files)
{
List actual = new ArrayList<>();
for (File file : files)
@@ -42,15 +91,6 @@ public class BaseHomeTest
Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));
}
- private void toOsSeparators(List expected)
- {
- for (int i = 0; i < expected.size(); i++)
- {
- String fixed = FS.separators(expected.get(i));
- expected.set(i,fixed);
- }
- }
-
@Test
public void testGetFile_OnlyHome() throws IOException
{
@@ -68,13 +108,13 @@ public class BaseHomeTest
}
@Test
- public void testListFiles_OnlyHome() throws IOException
+ public void testGetPaths_OnlyHome() throws IOException
{
File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
File baseDir = null;
BaseHome hb = new BaseHome(homeDir,baseDir);
- List files = hb.listFiles("/start.d");
+ List paths = hb.getPaths("start.d/*");
List expected = new ArrayList<>();
expected.add("${jetty.home}/start.d/jmx.ini");
@@ -82,19 +122,19 @@ public class BaseHomeTest
expected.add("${jetty.home}/start.d/jsp.ini");
expected.add("${jetty.home}/start.d/logging.ini");
expected.add("${jetty.home}/start.d/ssl.ini");
- toOsSeparators(expected);
+ FSTest.toOsSeparators(expected);
- assertFileList(hb,"Files found",expected,files);
+ assertPathList(hb,"Paths found",expected,paths);
}
@Test
- public void testListFiles_Filtered_OnlyHome() throws IOException
+ public void testGetPaths_OnlyHome_InisOnly() throws IOException
{
File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
File baseDir = null;
BaseHome hb = new BaseHome(homeDir,baseDir);
- List files = hb.listFiles("/start.d",new FS.IniFilter());
+ List paths = hb.getPaths("start.d/*.ini");
List expected = new ArrayList<>();
expected.add("${jetty.home}/start.d/jmx.ini");
@@ -102,19 +142,19 @@ public class BaseHomeTest
expected.add("${jetty.home}/start.d/jsp.ini");
expected.add("${jetty.home}/start.d/logging.ini");
expected.add("${jetty.home}/start.d/ssl.ini");
- toOsSeparators(expected);
+ FSTest.toOsSeparators(expected);
- assertFileList(hb,"Files found",expected,files);
+ assertPathList(hb,"Paths found",expected,paths);
}
@Test
- public void testListFiles_Both() throws IOException
+ public void testGetPaths_Both() throws IOException
{
File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
File baseDir = MavenTestingUtils.getTestResourceDir("hb.1/base");
BaseHome hb = new BaseHome(homeDir,baseDir);
- List files = hb.listFiles("/start.d");
+ List paths = hb.getPaths("start.d/*.ini");
List expected = new ArrayList<>();
expected.add("${jetty.base}/start.d/jmx.ini");
@@ -123,9 +163,9 @@ public class BaseHomeTest
expected.add("${jetty.base}/start.d/logging.ini");
expected.add("${jetty.home}/start.d/ssl.ini");
expected.add("${jetty.base}/start.d/myapp.ini");
- toOsSeparators(expected);
+ FSTest.toOsSeparators(expected);
- assertFileList(hb,"Files found",expected,files);
+ assertPathList(hb,"Paths found",expected,paths);
}
@Test
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/FSTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/FSTest.java
new file mode 100644
index 00000000000..e44fb5cbe65
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/FSTest.java
@@ -0,0 +1,62 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.start;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class FSTest
+{
+ @Test
+ public void testCanReadDirectory()
+ {
+ File targetDir = MavenTestingUtils.getTargetDir();
+ Assert.assertTrue("Can read dir: " + targetDir,FS.canReadDirectory(targetDir));
+ }
+
+ @Test
+ public void testCanReadDirectory_NotDir()
+ {
+ File bogusFile = MavenTestingUtils.getTestResourceFile("bogus.xml");
+ Assert.assertFalse("Can read dir: " + bogusFile,FS.canReadDirectory(bogusFile));
+ }
+
+ @Test
+ public void testCanReadFile()
+ {
+ File pom = MavenTestingUtils.getProjectFile("pom.xml");
+ Assert.assertTrue("Can read file: " + pom,FS.canReadFile(pom));
+ }
+
+ /**
+ * Utility method used by other test cases
+ */
+ public static void toOsSeparators(List expected)
+ {
+ for (int i = 0; i < expected.size(); i++)
+ {
+ String fixed = FS.separators(expected.get(i));
+ expected.set(i,fixed);
+ }
+ }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
index 222f760f8fb..5fe9b1a363b 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
@@ -98,7 +98,7 @@ public class MainTest
List cmdLineArgs = new ArrayList<>();
addUseCasesHome(cmdLineArgs);
-
+
// JVM args
cmdLineArgs.add("--exec");
cmdLineArgs.add("-Xms1024m");
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
index 27d5726c42a..6ce160cd9d1 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
@@ -35,7 +35,7 @@ public class ModulesTest
{
private final static List TEST_SOURCE = Collections.singletonList("");
private StartArgs DEFAULT_ARGS = new StartArgs(new String[] { "jetty.version=TEST" }).parseCommandLine();
-
+
@Test
public void testLoadAllModules() throws IOException
{
@@ -43,10 +43,26 @@ public class ModulesTest
BaseHome basehome = new BaseHome(homeDir,homeDir);
Modules modules = new Modules();
- modules.registerAll(basehome, DEFAULT_ARGS);
- Assert.assertThat("Module count",modules.count(),is(30));
+ modules.registerAll(basehome,DEFAULT_ARGS);
+
+ List moduleNames = new ArrayList<>();
+ for (Module mod : modules)
+ {
+ // skip npn-boot in this test (as its behavior is jdk specific)
+ if (mod.getName().equals("npn-boot"))
+ {
+ continue;
+ }
+ moduleNames.add(mod.getName());
+ }
+
+ String expected[] = { "jmx", "client", "stats", "spdy", "deploy", "debug", "security", "npn", "ext", "websocket", "rewrite", "ipaccess", "xinetd",
+ "proxy", "webapp", "jndi", "lowresources", "https", "plus", "requestlog", "jsp", "monitor", "xml", "servlet", "jaas", "http", "base", "server",
+ "annotations" };
+
+ Assert.assertThat("Module count: " + moduleNames,moduleNames.size(),is(expected.length));
}
-
+
@Test
public void testEnableRegexSimple() throws IOException
{
@@ -54,11 +70,11 @@ public class ModulesTest
BaseHome basehome = new BaseHome(homeDir,homeDir);
Modules modules = new Modules();
- modules.registerAll(basehome, DEFAULT_ARGS);
+ modules.registerAll(basehome,DEFAULT_ARGS);
modules.enable("[sj]{1}.*",TEST_SOURCE);
-
+
String expected[] = { "jmx", "stats", "spdy", "security", "jndi", "jsp", "servlet", "jaas", "server" };
-
+
Assert.assertThat("Enabled Module count",modules.resolveEnabled().size(),is(expected.length));
}
@@ -70,7 +86,7 @@ public class ModulesTest
// Register modules
Modules modules = new Modules();
- modules.registerAll(basehome, DEFAULT_ARGS);
+ modules.registerAll(basehome,DEFAULT_ARGS);
modules.buildGraph();
// Enable 2 modules
@@ -108,12 +124,12 @@ public class ModulesTest
List actualLibs = modules.normalizeLibs(active);
Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
-
+
// Assert XML List
List expectedXmls = new ArrayList<>();
expectedXmls.add("etc/jetty.xml");
expectedXmls.add("etc/jetty-http.xml");
-
+
List actualXmls = modules.normalizeXmls(active);
Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
}
@@ -126,7 +142,7 @@ public class ModulesTest
// Register modules
Modules modules = new Modules();
- modules.registerAll(basehome, DEFAULT_ARGS);
+ modules.registerAll(basehome,DEFAULT_ARGS);
modules.buildGraph();
// modules.dump();
@@ -136,7 +152,7 @@ public class ModulesTest
// Collect active module list
List active = modules.resolveEnabled();
-
+
// Assert names are correct, and in the right order
List expectedNames = new ArrayList<>();
expectedNames.add("base");
@@ -174,10 +190,10 @@ public class ModulesTest
expectedLibs.add("lib/jetty-annotations-${jetty.version}.jar");
expectedLibs.add("lib/annotations/*.jar");
expectedLibs.add("lib/websocket/*.jar");
-
+
List actualLibs = modules.normalizeLibs(active);
Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
-
+
// Assert XML List
List expectedXmls = new ArrayList<>();
expectedXmls.add("etc/jetty.xml");
@@ -185,7 +201,7 @@ public class ModulesTest
expectedXmls.add("etc/jetty-plus.xml");
expectedXmls.add("etc/jetty-annotations.xml");
expectedXmls.add("etc/jetty-websockets.xml");
-
+
List actualXmls = modules.normalizeXmls(active);
Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java
new file mode 100644
index 00000000000..bc14d322001
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java
@@ -0,0 +1,87 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.start;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.junit.Test;
+
+public class PathFinderTest
+{
+ @Test
+ public void testFindInis() throws IOException
+ {
+ File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
+ Path homePath = homeDir.toPath();
+
+ PathFinder finder = new PathFinder();
+ finder.setFileMatcher("glob:**/*.ini");
+ finder.setBase(homePath);
+
+ Files.walkFileTree(homePath,EnumSet.of(FileVisitOption.FOLLOW_LINKS),30,finder);
+
+ List expected = new ArrayList<>();
+ expected.add("${jetty.home}/start.d/jmx.ini");
+ expected.add("${jetty.home}/start.d/jndi.ini");
+ expected.add("${jetty.home}/start.d/jsp.ini");
+ expected.add("${jetty.home}/start.d/logging.ini");
+ expected.add("${jetty.home}/start.d/ssl.ini");
+ expected.add("${jetty.home}/start.ini");
+ FSTest.toOsSeparators(expected);
+
+ BaseHome hb = new BaseHome(homeDir,null);
+ BaseHomeTest.assertPathList(hb,"Files found",expected,finder);
+ }
+
+ @Test
+ public void testFindMods() throws IOException
+ {
+ File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
+
+ List expected = new ArrayList<>();
+ File modulesDir = new File(homeDir,"modules");
+ for (File file : modulesDir.listFiles())
+ {
+ if (file.getName().endsWith(".mod"))
+ {
+ expected.add("${jetty.home}/modules/" + file.getName());
+ }
+ }
+ FSTest.toOsSeparators(expected);
+
+ Path modulesPath = modulesDir.toPath();
+
+ PathFinder finder = new PathFinder();
+ finder.setFileMatcher(PathMatchers.getMatcher("modules/*.mod"));
+ finder.setBase(modulesPath);
+
+ Files.walkFileTree(modulesPath,EnumSet.of(FileVisitOption.FOLLOW_LINKS),1,finder);
+
+ BaseHome hb = new BaseHome(homeDir,null);
+ BaseHomeTest.assertPathList(hb,"Files found",expected,finder);
+ }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PathMatchersTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PathMatchersTest.java
new file mode 100644
index 00000000000..460f88d2a65
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PathMatchersTest.java
@@ -0,0 +1,105 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.start;
+
+import static org.hamcrest.Matchers.*;
+
+import java.nio.file.Path;
+
+import org.eclipse.jetty.toolchain.test.OS;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PathMatchersTest
+{
+ private void assertIsAbsolute(String pattern, boolean expected)
+ {
+ Assert.assertThat("isAbsolute(\"" + pattern + "\")",PathMatchers.isAbsolute(pattern),is(expected));
+ }
+
+ @Test
+ public void testIsAbsolute()
+ {
+ if (OS.IS_UNIX)
+ {
+ assertIsAbsolute("/opt/app",true);
+ assertIsAbsolute("/opt/florb",true);
+ assertIsAbsolute("/home/user/benfranklin",true);
+ assertIsAbsolute("glob:/home/user/benfranklin/*.jar",true);
+ assertIsAbsolute("glob:/**/*.jar",true);
+ assertIsAbsolute("regex:/*-[^dev].ini",true);
+ }
+
+ if (OS.IS_WINDOWS)
+ {
+ assertIsAbsolute("C:\\\\System32",true);
+ assertIsAbsolute("C:\\\\Program Files",true);
+ }
+ }
+
+ @Test
+ public void testIsNotAbsolute()
+ {
+ assertIsAbsolute("etc",false);
+ assertIsAbsolute("lib",false);
+ assertIsAbsolute("${user.dir}",false);
+ assertIsAbsolute("**/*.jar",false);
+ assertIsAbsolute("glob:*.ini",false);
+ assertIsAbsolute("regex:*-[^dev].ini",false);
+ }
+
+ private void assertSearchRoot(String pattern, String expectedSearchRoot)
+ {
+ Path actual = PathMatchers.getSearchRoot(pattern);
+ String expectedNormal = FS.separators(expectedSearchRoot);
+ Assert.assertThat(".getSearchRoot(\"" + pattern + "\")",actual.toString(),is(expectedNormal));
+ }
+
+ @Test
+ public void testGetSearchRoot()
+ {
+ if (OS.IS_UNIX)
+ {
+ // absolute first
+ assertSearchRoot("/opt/app/*.jar","/opt/app");
+ assertSearchRoot("/lib/jvm/**/jre/lib/*.jar","/lib/jvm");
+ assertSearchRoot("glob:/var/lib/*.xml","/var/lib");
+ assertSearchRoot("glob:/var/lib/*.{xml,java}","/var/lib");
+ assertSearchRoot("glob:/opt/corporate/lib-{dev,prod}/*.ini","/opt/corporate");
+ assertSearchRoot("regex:/opt/jetty/.*/lib-(dev|prod)/*.ini","/opt/jetty");
+
+ assertSearchRoot("/*.ini","/");
+ assertSearchRoot("/etc/jetty.conf","/etc");
+ assertSearchRoot("/common.conf","/");
+ }
+
+ if (OS.IS_WINDOWS)
+ {
+ // absolute patterns (complete with required windows slash escaping)
+ assertSearchRoot("C:\\\\corp\\\\lib\\\\*.jar","C:\\corp\\lib");
+ assertSearchRoot("D:\\\\lib\\\\**\\\\jre\\\\lib\\\\*.jar","C:\\lib");
+ }
+
+ // some relative paths
+ assertSearchRoot("lib/*.jar","lib");
+ assertSearchRoot("etc/jetty.xml","etc");
+ assertSearchRoot("start.ini",".");
+ assertSearchRoot("start.d/",".");
+ }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
index ec419cfc432..28ce62f71c0 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
@@ -76,7 +76,6 @@ public class TestUseCases
@Test
public void testWithSpdyBadNpnVersion() throws Exception
{
- //StartLog.enableDebug();
assertUseCase("home","base.enable.spdy.bad.npn.version","assert-enable-spdy-bad-npn-version.txt","java.version=1.7.0_01");
}
diff --git a/jetty-start/src/test/resources/usecases/home/modules/ext.mod b/jetty-start/src/test/resources/usecases/home/modules/ext.mod
index c84697a5631..66c051911db 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/ext.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/ext.mod
@@ -3,7 +3,7 @@
#
[lib]
-regex:lib/ext/.*\.jar$
+lib/ext/**.jar
[files]
lib/