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 581bf5ad9b5..68c121ed92e 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 @@ -23,8 +23,6 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.Path; @@ -32,12 +30,17 @@ import java.nio.file.PathMatcher; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; -import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.jetty.start.config.CommandLineConfigSource; +import org.eclipse.jetty.start.config.ConfigSource; +import org.eclipse.jetty.start.config.ConfigSources; +import org.eclipse.jetty.start.config.DirConfigSource; + /** * File access for ${jetty.home}, ${jetty.base}, directories. *

@@ -49,12 +52,6 @@ import java.util.regex.Pattern; */ public class BaseHome { - private static final String JETTY_BASE = "jetty.base"; - private static final String JETTY_HOME = "jetty.home"; - - private final static EnumSet SEARCH_VISIT_OPTIONS = EnumSet.of(FileVisitOption.FOLLOW_LINKS);; - private final static int MAX_SEARCH_DEPTH = Integer.getInteger("org.eclipse.jetty.start.searchDepth",10); - public static class SearchDir { private Path dir; @@ -65,13 +62,19 @@ public class BaseHome this.name = name; } - public SearchDir setDir(String path) + public Path getDir() { - if (path != null) - { - return setDir(FS.toPath(path)); - } - return this; + return dir; + } + + public Path resolve(Path subpath) + { + return dir.resolve(subpath); + } + + public Path resolve(String subpath) + { + return dir.resolve(FS.separators(subpath)); } public SearchDir setDir(File path) @@ -92,19 +95,13 @@ public class BaseHome return this; } - public Path getDir() + public SearchDir setDir(String path) { - return dir; - } - - public Path resolve(String subpath) - { - return dir.resolve(FS.separators(subpath)); - } - - public Path resolve(Path subpath) - { - return dir.resolve(subpath); + if (path != null) + { + return setDir(FS.toPath(path)); + } + return this; } public String toShortForm(Path path) @@ -113,30 +110,37 @@ public class BaseHome return String.format("${%s}%c%s",name,File.separatorChar,relative.toString()); } } + private static final String JETTY_BASE = "jetty.base"; - private SearchDir homeDir; - private LinkedList searchDirs = new LinkedList<>(); - private SearchDir baseDir; + private static final String JETTY_HOME = "jetty.home";; + private final static EnumSet SEARCH_VISIT_OPTIONS = EnumSet.of(FileVisitOption.FOLLOW_LINKS); + + private final static int MAX_SEARCH_DEPTH = Integer.getInteger("org.eclipse.jetty.start.searchDepth",10); + + private Path homeDir; + private ConfigSources sources; + private Path baseDir; public BaseHome() { try { - // find ${jetty.base} - this.baseDir = new SearchDir(JETTY_BASE); + // find ${jetty.base} and ${jetty.home} from environment. + + // overrides from command line (and the like) come later. + // in the .initialize() step // default is ${user.dir} - this.baseDir.setDir(System.getProperty("user.dir",".")); + this.baseDir = FS.toPath(System.getProperty("user.dir",".")); // if ${jetty.base} declared, use it String jettyBase = System.getProperty(JETTY_BASE); if (jettyBase != null) { - this.baseDir.setDir(jettyBase); + this.baseDir = FS.toPath(jettyBase); } // find ${jetty.home} - this.homeDir = new SearchDir(JETTY_HOME); // default location is based on lookup for BaseHome (from jetty's start.jar) URL jarfile = this.getClass().getClassLoader().getResource("org/eclipse/jetty/start/BaseHome.class"); @@ -146,19 +150,26 @@ public class BaseHome if (m.matches()) { // ${jetty.home} is relative to found BaseHome class - this.homeDir.setDir(new File(new URI(m.group(1))).getParentFile()); + this.homeDir = new File(new URI(m.group(1))).getParentFile().toPath(); } } // if we can't locate BaseHome, then assume home == base - this.homeDir.setDir(baseDir.getDir()); + if (this.homeDir == null) + { + this.homeDir = baseDir.toAbsolutePath(); + } // if ${jetty.home} declared, use it String jettyHome = System.getProperty(JETTY_HOME); if (jettyHome != null) { - this.homeDir.setDir(jettyHome); + this.homeDir = FS.toPath(jettyHome); } + + // Resolve to absolute paths + this.homeDir = this.homeDir.toAbsolutePath(); + this.baseDir = this.baseDir.toAbsolutePath(); } catch (URISyntaxException e) { @@ -168,15 +179,18 @@ public class BaseHome public BaseHome(File homeDir, File baseDir) { - this.baseDir = new SearchDir(JETTY_BASE); - this.homeDir = new SearchDir(JETTY_HOME); + Objects.requireNonNull(homeDir,"Home Dir cannot be null"); - this.homeDir.setDir(homeDir); - this.baseDir.setDir(homeDir); // default + this.homeDir = homeDir.toPath(); + this.baseDir = homeDir.toPath(); // default if (baseDir != null) { - this.baseDir.setDir(baseDir); + this.baseDir = baseDir.toPath(); } + + // Resolve to absolute paths + this.homeDir = this.homeDir.toAbsolutePath(); + this.baseDir = this.baseDir.toAbsolutePath(); } public String getBase() @@ -188,10 +202,13 @@ public class BaseHome return baseDir.toString(); } - // TODO: change return type to Path + /** + * @deprecated use {@link #getBasePath()} + */ + @Deprecated public File getBaseDir() { - return baseDir.getDir().toFile(); + return baseDir.toFile(); } /** @@ -200,31 +217,27 @@ public class BaseHome * @param path * the path to reference * @return the file reference + * @deprecated use {@link #getBasePath(String)} */ - // TODO: change return type to Path + @Deprecated public File getBaseFile(String path) { return baseDir.resolve(path).toFile(); } - /** - * Get a specific file reference. - *

- * File references go through 3 possibly scenarios. - *

    - *
  1. If exists relative to ${jetty.base}, return that reference
  2. - *
  3. If exists relative to ${jetty.home}, return that reference
  4. - *
  5. Otherwise return absolute path reference (standard java logic)
  6. - *
- * - * @param path - * the path to get. - * @return the file reference. - */ - // TODO: deprecate in favor of getPath() version - public File getFile(String path) + public Path getBasePath() { - return getPath(path).toAbsolutePath().toFile(); + return baseDir; + } + + public Path getBasePath(String path) + { + return baseDir.resolve(path); + } + + public ConfigSources getConfigSources() + { + return this.sources; } /** @@ -240,40 +253,112 @@ public class BaseHome * @param path * the path to get. * @return the file reference. + * @deprecated use {@link #getPath(String)} + */ + @Deprecated + public File getFile(String path) + { + return getPath(path).toAbsolutePath().toFile(); + } + + public String getHome() + { + return homeDir.toString(); + } + + /** + * @deprecated use {@link #getHomePath()} + */ + @Deprecated + public File getHomeDir() + { + return homeDir.toFile(); + } + + public Path getHomePath() + { + return homeDir; + } + + /** + * Get a specific path reference. + *

+ * Path references are searched based on the config source search order. + *

    + *
  1. If provided path is an absolute reference., and exists, return that reference
  2. + *
  3. If exists relative to ${jetty.base}, return that reference
  4. + *
  5. If exists relative to and extra-start-dir locations, return that reference
  6. + *
  7. If exists relative to ${jetty.home}, return that reference
  8. + *
  9. Return standard {@link Path} reference obtained from {@link java.nio.file.FileSystem#getPath(String, String...)} (no exists check performed)
  10. + *
+ * + * @param path + * the path to get. + * @return the path reference. */ public Path getPath(final String path) { - // Relative to Base Directory First - if (isBaseDifferent()) + Path apath = FS.toPath(path); + + if (apath.isAbsolute()) { - Path file = baseDir.resolve(path); - if (FS.exists(file)) + if (FS.exists(apath)) { - return file; + return apath; } } - // Next, test for relative to all extra search paths - for (SearchDir search : searchDirs) + for (ConfigSource source : sources) { - Path file = search.resolve(path); - if (FS.exists(file)) + if (source instanceof DirConfigSource) { - return file; + DirConfigSource dirsource = (DirConfigSource)source; + Path file = dirsource.getDir().resolve(apath); + if (FS.exists(file)) + { + return file; + } } } - // Then relative to Home Directory - Path file = homeDir.resolve(path); - if (FS.exists(file)) - { - return file; - } - - // Finally, as an absolute path + // Finally, as an anonymous path return FS.toPath(path); } + /** + * 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; + } + /** * Get a List of {@link Path}s from a provided pattern. *

@@ -327,6 +412,7 @@ public class BaseHome */ public List getPaths(String pattern) throws IOException { + StartLog.debug("getPaths('%s')",pattern); List hits = new ArrayList<>(); if (PathMatchers.isAbsolute(pattern)) @@ -357,35 +443,24 @@ public class BaseHome finder.setIncludeDirsInResults(true); finder.setFileMatcher(matcher); - Path homePath = homeDir.resolve(relativePath); - - if (FS.isValidDirectory(homePath)) - { - finder.setBase(homePath); - Files.walkFileTree(homePath,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder); - } - - ListIterator iter = searchDirs.listIterator(searchDirs.size()); + // walk config sources backwards ... + ListIterator iter = sources.reverseListIterator(); while (iter.hasPrevious()) { - SearchDir search = iter.previous(); - Path dir = search.getDir(); - if (FS.isValidDirectory(dir)) + ConfigSource source = iter.previous(); + if (source instanceof DirConfigSource) { - finder.setBase(dir); - Files.walkFileTree(dir,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder); + DirConfigSource dirsource = (DirConfigSource)source; + Path dir = dirsource.getDir(); + Path deepDir = dir.resolve(relativePath); + if (FS.isValidDirectory(deepDir)) + { + finder.setBase(dir); + Files.walkFileTree(deepDir,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder); + } } } - if (isBaseDifferent()) - { - Path basePath = baseDir.resolve(relativePath); - if (FS.isValidDirectory(basePath)) - { - finder.setBase(basePath); - Files.walkFileTree(basePath,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder); - } - } hits.addAll(finder.getHits()); } @@ -393,106 +468,27 @@ public class BaseHome 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 + public void initialize(ConfigSources config) { - if (PathMatchers.isAbsolute(pattern)) + CommandLineConfigSource cmdLine = config.getCommandLineSource(); + if (cmdLine != null) { - throw new RuntimeException("Pattern cannot be absolute: " + pattern); + this.homeDir = cmdLine.getHomePath(); + this.baseDir = cmdLine.getBasePath(); } - 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.toString(); - } - - // TODO: change return type to Path - public File getHomeDir() - { - return homeDir.getDir().toFile(); - } - - public void initialize(StartArgs args) - { - Pattern jetty_home = Pattern.compile("(-D)?jetty.home=(.*)"); - Pattern jetty_base = Pattern.compile("(-D)?jetty.base=(.*)"); - - Path homePath = null; - Path basePath = null; - - FileSystem fs = FileSystems.getDefault(); - - for (String arg : args.getCommandLine()) - { - Matcher home_match = jetty_home.matcher(arg); - if (home_match.matches()) - { - homePath = fs.getPath(home_match.group(2)); - } - Matcher base_match = jetty_base.matcher(arg); - if (base_match.matches()) - { - basePath = fs.getPath(base_match.group(2)); - } - } - - if (homePath != null) - { - // logic if home is specified - this.homeDir.setDir(homePath); - if (basePath == null) - { - this.baseDir.setDir(homePath); - args.getProperties().setProperty(JETTY_BASE,this.baseDir.toString(),""); - } - else - { - this.baseDir.setDir(basePath); - } - } - else if (basePath != null) - { - // logic if home is undeclared - this.baseDir.setDir(basePath); - } - - // Update System Properties - args.addSystemProperty(JETTY_HOME,this.homeDir.toString()); - args.addSystemProperty(JETTY_BASE,this.baseDir.toString()); + this.sources = config; } public boolean isBaseDifferent() { - return homeDir.getDir().compareTo(baseDir.getDir()) != 0; + return homeDir.compareTo(baseDir) != 0; } - // TODO: deprecate (in favor of Path version) + /** + * @deprecated use {@link #setBaseDir(Path)} + */ + @Deprecated public void setBaseDir(File dir) { setBaseDir(dir.toPath()); @@ -500,11 +496,14 @@ public class BaseHome public void setBaseDir(Path dir) { - this.baseDir.setDir(dir); + this.baseDir = dir.toAbsolutePath(); System.setProperty(JETTY_BASE,dir.toString()); } - // TODO: deprecate (in favor of Path version) + /** + * @deprecated use {@link #setHomeDir(Path)} + */ + @Deprecated public void setHomeDir(File dir) { setHomeDir(dir.toPath()); @@ -512,10 +511,18 @@ public class BaseHome public void setHomeDir(Path dir) { - this.homeDir.setDir(dir); + this.homeDir = dir.toAbsolutePath(); System.setProperty(JETTY_HOME,dir.toString()); } + /** + * Convenience method for toShortForm(file.toPath()) + */ + public String toShortForm(final File path) + { + return toShortForm(path.toPath()); + } + /** * Replace/Shorten arbitrary path with property strings "${jetty.home}" or "${jetty.base}" where appropriate. * @@ -527,41 +534,30 @@ public class BaseHome { Path apath = path.toAbsolutePath(); - if (isBaseDifferent()) + for (ConfigSource source : sources) { - // is path part of ${jetty.base} ? - if (apath.startsWith(baseDir.getDir())) + if (source instanceof DirConfigSource) { - return baseDir.toShortForm(apath); + DirConfigSource dirsource = (DirConfigSource)source; + Path dir = dirsource.getDir(); + if (apath.startsWith(dir)) + { + if (dirsource.isPropertyBased()) + { + Path relative = dir.relativize(apath); + return String.format("%s%c%s",dirsource.getId(),File.separatorChar,relative.toString()); + } + else + { + return apath.toString(); + } + } } } - - // Extra search dirs - for(SearchDir search: searchDirs) - { - if(apath.startsWith(search.getDir())) - { - return search.toShortForm(apath); - } - } - - // is path part of ${jetty.home} ? - if (apath.startsWith(homeDir.getDir())) - { - return homeDir.toShortForm(apath); - } return apath.toString(); } - /** - * Convenience method for toShortForm(file.toPath()) - */ - public String toShortForm(final File path) - { - return toShortForm(path.toPath()); - } - /** * Replace/Shorten arbitrary path with property strings "${jetty.home}" or "${jetty.base}" where appropriate. * @@ -578,9 +574,4 @@ public class BaseHome return toShortForm(FS.toPath(path)); } - - public void addExtraStart(String name, File dir) - { - this.searchDirs.add(new SearchDir(name).setDir(dir)); - } } 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 87c4a76c028..abedea9c2a4 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 @@ -26,6 +26,7 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; +import java.nio.file.attribute.FileTime; import java.util.Locale; import java.util.regex.Pattern; @@ -55,29 +56,6 @@ public class FS } } - @Deprecated - public static class RelativeRegexFilter implements FileFilter - { - private final File baseDir; - private final Pattern pattern; - - public RelativeRegexFilter(File baseDir, Pattern pattern) - { - this.baseDir = baseDir; - this.pattern = pattern; - } - - @Override - public boolean accept(File path) - { - // 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 { @@ -132,6 +110,29 @@ public class FS } } + @Deprecated + public static class RelativeRegexFilter implements FileFilter + { + private final File baseDir; + private final Pattern pattern; + + public RelativeRegexFilter(File baseDir, Pattern pattern) + { + this.baseDir = baseDir; + this.pattern = pattern; + } + + @Override + public boolean accept(File path) + { + // get relative path + String relativePath = FS.toRelativePath(baseDir,path); + + // see if it matches + return (pattern.matcher(relativePath).matches()); + } + } + @Deprecated public static class XmlFilter extends FilenameRegexFilter { @@ -141,24 +142,8 @@ 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; - } + // Default Link Options + private static final LinkOption[] NO_LINK_OPTIONS = new LinkOption[0]; public static boolean canReadDirectory(File path) { @@ -167,19 +152,22 @@ public class FS public static boolean canReadDirectory(Path path) { - LinkOption lopts[] = new LinkOption[0]; - return Files.exists(path,lopts) && Files.isDirectory(path,lopts) && Files.isReadable(path); + return Files.exists(path,NO_LINK_OPTIONS) && Files.isDirectory(path,NO_LINK_OPTIONS) && Files.isReadable(path); } public static boolean canReadFile(File path) { return (path.exists() && path.isFile() && path.canRead()); } - + public static boolean canReadFile(Path path) { - LinkOption lopts[] = new LinkOption[0]; - return Files.exists(path,lopts) && Files.isRegularFile(path,lopts) && Files.isReadable(path); + return Files.exists(path,NO_LINK_OPTIONS) && Files.isRegularFile(path,NO_LINK_OPTIONS) && Files.isReadable(path); + } + + public static boolean canWrite(Path path) + { + return Files.isWritable(path); } public static void close(Closeable c) @@ -199,6 +187,16 @@ public class FS } } + public static boolean createNewFile(Path path) throws IOException + { + Path ret = Files.createFile(path); + return Files.exists(ret,NO_LINK_OPTIONS); + } + + /** + * @deprecated use {@link #ensureDirectoryExists(Path)} instead + */ + @Deprecated public static void ensureDirectoryExists(File dir) throws IOException { if (dir.exists()) @@ -210,7 +208,21 @@ public class FS throw new IOException("Unable to create directory: " + dir.getAbsolutePath()); } } + + public static void ensureDirectoryExists(Path dir) throws IOException + { + if (exists(dir)) + { + // exists already, nothing to do + return; + } + Files.createDirectories(dir); + } + /** + * @deprecated use {@link #ensureDirectoryWritable(Path)} instead + */ + @Deprecated public static void ensureDirectoryWritable(File dir) throws IOException { if (!dir.exists()) @@ -223,6 +235,27 @@ public class FS } } + public static void ensureDirectoryWritable(Path dir) throws IOException + { + if (!Files.exists(dir,NO_LINK_OPTIONS)) + { + throw new IOException("Path does not exist: " + dir.toAbsolutePath()); + } + if (!Files.isDirectory(dir,NO_LINK_OPTIONS)) + { + throw new IOException("Directory does not exist: " + dir.toAbsolutePath()); + } + if (!Files.isWritable(dir)) + { + throw new IOException("Unable to write to directory: " + dir.toAbsolutePath()); + } + } + + public static boolean exists(Path path) + { + return Files.exists(path,NO_LINK_OPTIONS); + } + public static boolean isFile(File file) { if (file == null) @@ -232,16 +265,30 @@ public class FS return file.exists() && file.isFile(); } + public static boolean isValidDirectory(Path path) + { + LinkOption lopts[] = NO_LINK_OPTIONS; + 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 isXml(String filename) { return filename.toLowerCase(Locale.ENGLISH).endsWith(".xml"); } - public static String toRelativePath(File baseDir, File path) - { - return baseDir.toURI().relativize(path.toURI()).toASCIIString(); - } - public static String separators(String path) { StringBuilder ret = new StringBuilder(); @@ -259,13 +306,33 @@ public class FS return ret.toString(); } - public static boolean exists(Path path) + public static Path toOptionalPath(String path) { - return Files.exists(path,new LinkOption[0]); + if (path == null) + { + return null; + } + return toPath(path); } public static Path toPath(String path) { return FileSystems.getDefault().getPath(FS.separators(path)); } + + public static String toRelativePath(File baseDir, File path) + { + return baseDir.toURI().relativize(path.toURI()).toASCIIString(); + } + + public static void touch(Path path) throws IOException + { + FileTime now = FileTime.fromMillis(System.currentTimeMillis()); + Files.setLastModifiedTime(path,now); + } + + public static Path toRealPath(Path path) throws IOException + { + return path.toRealPath(NO_LINK_OPTIONS); + } } 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 0a4da40bab2..33f0c23b09b 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 @@ -21,9 +21,8 @@ package org.eclipse.jetty.start; import static org.eclipse.jetty.start.UsageException.*; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -37,7 +36,10 @@ import java.net.InetAddress; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -48,6 +50,11 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.jetty.start.config.CommandLineConfigSource; +import org.eclipse.jetty.start.config.ConfigSources; +import org.eclipse.jetty.start.config.JettyBaseConfigSource; +import org.eclipse.jetty.start.config.JettyHomeConfigSource; + /** * Main start class. *

@@ -168,11 +175,12 @@ public class Main { try { - File file = baseHome.getBaseFile(arg.location); + Path file = baseHome.getBasePath(arg.location); - StartLog.debug("Module file %s %s",file.getAbsolutePath(),(file.exists()?"[Exists!]":"")); - if (file.exists()) + StartLog.debug("Module file %s %s",file.toAbsolutePath(),(FS.exists(file)?"[Exists!]":"")); + if (FS.exists(file)) { + // file already initialized / downloaded, skip it return; } @@ -182,10 +190,11 @@ public class Main System.err.println("DOWNLOAD: " + url + " to " + arg.location); - FS.ensureDirectoryExists(file.getParentFile()); + FS.ensureDirectoryExists(file.getParent()); byte[] buf = new byte[8192]; - try (InputStream in = url.openStream(); OutputStream out = new FileOutputStream(file);) + try (InputStream in = url.openStream(); + OutputStream out = Files.newOutputStream(file,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE)) { while (true) { @@ -205,11 +214,12 @@ public class Main else if (arg.location.endsWith("/")) { System.err.println("MKDIR: " + baseHome.toShortForm(file)); - file.mkdirs(); + FS.ensureDirectoryExists(file); } else + { StartLog.warn("MISSING: required file "+ baseHome.toShortForm(file)); - + } } catch (Exception e) { @@ -350,7 +360,7 @@ public class Main private void buildIni(StartArgs args, String name, boolean topLevel, boolean appendStartIni) throws IOException { // Find the start.d relative to the base directory only. - File start_d = baseHome.getBaseFile("start.d"); + Path start_d = baseHome.getBasePath("start.d"); // Is this a module? Modules modules = args.getAllModules(); @@ -362,12 +372,12 @@ public class Main } // Find any named ini file and check it follows the convention - File start_ini = baseHome.getBaseFile("start.ini"); + Path start_ini = baseHome.getBasePath("start.ini"); String short_start_ini = baseHome.toShortForm(start_ini); - File ini = new File(start_d,name + ".ini"); + Path ini = start_d.resolve(name + ".ini"); String short_ini = baseHome.toShortForm(ini); StartIni module_ini = null; - if (ini.exists()) + if (FS.exists(ini)) { module_ini = new StartIni(ini); if (module_ini.getLineMatches(Pattern.compile("--module=(.*, *)*" + name)).size() == 0) @@ -381,46 +391,30 @@ public class Main boolean has_ini_lines = module.getInitialise().size() > 0; // If it is not enabled or is transitive with ini template lines or toplevel and doesn't exist - if (!module.isEnabled() || (transitive && has_ini_lines) || (topLevel && !ini.exists() && !appendStartIni)) + if (!module.isEnabled() || (transitive && has_ini_lines) || (topLevel && !FS.exists(ini) && !appendStartIni)) { + // File BufferedWriter + BufferedWriter writer = null; String source = null; PrintWriter out = null; try { if (appendStartIni) { - if ((!start_ini.exists() && !start_ini.createNewFile()) || !start_ini.canWrite()) - { - StartLog.warn("ERROR: Bad %s! ",start_ini); - return; - } source = short_start_ini; StartLog.info("%-15s initialised in %s (appended)",name,source); - out = new PrintWriter(new FileWriter(start_ini,true)); + writer = Files.newBufferedWriter(start_ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE,StandardOpenOption.APPEND); + out = new PrintWriter(writer); } else { // Create the directory if needed FS.ensureDirectoryExists(start_d); FS.ensureDirectoryWritable(start_d); - try - { - // Create a new ini file for it - if (!ini.createNewFile()) - { - StartLog.warn("ERROR: %s cannot be initialised in %s! ",name,short_ini); - return; - } - } - catch (IOException e) - { - StartLog.warn("ERROR: Unable to create %s!",ini); - StartLog.warn(e); - return; - } source = short_ini; StartLog.info("%-15s initialised in %s (created)",name,source); - out = new PrintWriter(ini); + writer = Files.newBufferedWriter(ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE); + out = new PrintWriter(writer); } if (appendStartIni) @@ -468,7 +462,7 @@ public class Main } } } - else if (ini.exists()) + else if (FS.exists(ini)) { StartLog.info("%-15s initialised in %s",name,short_ini); } @@ -557,61 +551,49 @@ public class Main public StartArgs processCommandLine(String[] cmdLine) throws Exception { - StartArgs args = new StartArgs(cmdLine); + ConfigSources sources = new ConfigSources(); // Processing Order is important! // ------------------------------------------------------------ // 1) Directory Locations + + CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); + sources.add(cmdLineSource); + sources.add(new JettyBaseConfigSource(cmdLineSource.getBasePath())); + sources.add(new JettyHomeConfigSource(cmdLineSource.getHomePath())); // Set Home and Base at the start, as many other paths encountered // will be based off of them. - baseHome.initialize(args); - + baseHome.initialize(sources); + // ------------------------------------------------------------ // 2) Start Logging - StartLog.getInstance().initialize(baseHome,args); + StartLog.getInstance().initialize(baseHome,cmdLineSource); StartLog.debug("jetty.home=%s",baseHome.getHome()); StartLog.debug("jetty.base=%s",baseHome.getBase()); // ------------------------------------------------------------ - // 3) Load Inis - File start_ini = baseHome.getBaseFile("start.ini"); - if (FS.canReadFile(start_ini)) - { - StartLog.debug("Reading ${jetty.base}/start.ini - %s",start_ini); - args.parse(baseHome,new StartIni(start_ini)); - } - - File start_d = baseHome.getBaseFile("start.d"); - if (FS.canReadDirectory(start_d)) - { - List paths = baseHome.getPaths(start_d.toPath(),1,"*.ini"); - Collections.sort(paths,new NaturalSort.Paths()); - for (Path path: paths) - { - StartLog.debug("Reading ${jetty.base}/start.d/%s - %s",path.getFileName(),path); - args.parse(baseHome,new StartIni(path)); - } - } - - // 4) Parse everything provided. + // 3) Parse everything provided. // This would be the directory information + // the various start inis // and then the raw command line arguments StartLog.debug("Parsing collected arguments"); - args.parseCommandLine(); + StartArgs args = new StartArgs(); + args.parse(sources); - // 5) Module Registration + // ------------------------------------------------------------ + // 4) Module Registration Modules modules = new Modules(); StartLog.debug("Registering all modules"); modules.registerAll(baseHome, args); - // 6) Active Module Resolution + // ------------------------------------------------------------ + // 5) Active Module Resolution for (String enabledModule : args.getEnabledModules()) { - List sources = args.getSources(enabledModule); - modules.enable(enabledModule,sources); + List msources = args.getSources(enabledModule); + modules.enable(enabledModule,msources); } StartLog.debug("Building Module Graph"); @@ -620,11 +602,13 @@ public class Main args.setAllModules(modules); List activeModules = modules.resolveEnabled(); - // 7) Lib & XML Expansion / Resolution + // ------------------------------------------------------------ + // 6) Lib & XML Expansion / Resolution args.expandLibs(baseHome); args.expandModules(baseHome,activeModules); - // 8) Resolve Extra XMLs + // ------------------------------------------------------------ + // 7) Resolve Extra XMLs args.resolveExtraXmls(baseHome); return args; @@ -666,7 +650,7 @@ public class Main // Generate Module Graph File if (args.getModuleGraphFilename() != null) { - File outputFile = baseHome.getBaseFile(args.getModuleGraphFilename()); + Path outputFile = baseHome.getBasePath(args.getModuleGraphFilename()); System.out.printf("Generating GraphViz Graph of Jetty Modules at %s%n",baseHome.toShortForm(outputFile)); ModuleGraphWriter writer = new ModuleGraphWriter(); writer.config(args.getProperties()); @@ -712,11 +696,13 @@ public class Main // Check ini files for download possibilities for (FileArg arg : args.getFiles()) { - File file = baseHome.getBaseFile(arg.location); - if (!file.exists() && args.isDownload()) + Path file = baseHome.getBasePath(arg.location); + if (!FS.exists(file) && args.isDownload()) + { initFile(arg); + } - if (!file.exists()) + if (!FS.exists(file)) { /* Startup should NEVER fail to run on missing content. * See Bug #427204 diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java index f995be6039d..2df1b05e64b 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java @@ -19,10 +19,11 @@ package org.eclipse.jetty.start; import java.io.BufferedReader; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.text.CollationKey; import java.text.Collator; import java.util.ArrayList; @@ -75,7 +76,7 @@ public class Module } /** The file of the module */ - private File file; + private Path file; /** The name of this Module (as a filesystem reference) */ private String fileRef; /** @@ -108,12 +109,12 @@ public class Module /** List of sources that enabled this module */ private final Set sources = new HashSet<>(); - public Module(BaseHome basehome, File file) throws FileNotFoundException, IOException + public Module(BaseHome basehome, Path file) throws FileNotFoundException, IOException { this.file = file; // Strip .mod - this.fileRef = Pattern.compile(".mod$",Pattern.CASE_INSENSITIVE).matcher(file.getName()).replaceFirst(""); + this.fileRef = Pattern.compile(".mod$",Pattern.CASE_INSENSITIVE).matcher(file.getFileName().toString()).replaceFirst(""); this.logicalName = fileRef; init(basehome); @@ -306,66 +307,63 @@ public class Module return; } - try (FileReader reader = new FileReader(file)) + try (BufferedReader buf = Files.newBufferedReader(file,StandardCharsets.UTF_8)) { - try (BufferedReader buf = new BufferedReader(reader)) + String sectionType = ""; + String line; + while ((line = buf.readLine()) != null) { - String sectionType = ""; - String line; - while ((line = buf.readLine()) != null) + line = line.trim(); + + Matcher sectionMatcher = section.matcher(line); + + if (sectionMatcher.matches()) { - line = line.trim(); - - Matcher sectionMatcher = section.matcher(line); - - if (sectionMatcher.matches()) + sectionType = sectionMatcher.group(1).trim().toUpperCase(Locale.ENGLISH); + } + else + { + // blank lines and comments are valid for ini-template section + if ((line.length() == 0) || line.startsWith("#")) { - sectionType = sectionMatcher.group(1).trim().toUpperCase(Locale.ENGLISH); + if ("INI-TEMPLATE".equals(sectionType)) + { + initialise.add(line); + } } else { - // blank lines and comments are valid for ini-template section - if ((line.length() == 0) || line.startsWith("#")) + switch (sectionType) { - if ("INI-TEMPLATE".equals(sectionType)) - { + case "": + // ignore (this would be entries before first section) + break; + case "DEPEND": + parentNames.add(line); + break; + case "FILES": + files.add(line); + break; + case "INI-TEMPLATE": initialise.add(line); - } - } - else - { - switch (sectionType) - { - case "": - // ignore (this would be entries before first section) - break; - case "DEPEND": - parentNames.add(line); - break; - case "FILES": - files.add(line); - break; - case "INI-TEMPLATE": - initialise.add(line); - break; - case "LIB": - libs.add(line); - break; - case "NAME": - logicalName = line; - break; - case "OPTIONAL": - optionalParentNames.add(line); - break; - case "EXEC": - jvmArgs.add(line); - break; - case "XML": - xmls.add(line); - break; - default: - throw new IOException("Unrecognized Module section: [" + sectionType + "]"); - } + break; + case "LIB": + libs.add(line); + break; + case "NAME": + logicalName = line; + break; + case "OPTIONAL": + optionalParentNames.add(line); + break; + case "EXEC": + jvmArgs.add(line); + break; + case "XML": + xmls.add(line); + break; + default: + throw new IOException("Unrecognized Module section: [" + sectionType + "]"); } } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java b/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java index b078f51ab3d..7c612a71400 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java @@ -18,10 +18,13 @@ package org.eclipse.jetty.start; -import java.io.File; -import java.io.FileWriter; +import java.io.BufferedWriter; import java.io.IOException; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.Collection; import java.util.List; @@ -73,9 +76,10 @@ public class ModuleGraphWriter return val; } - public void write(Modules modules, File outputFile) throws IOException + public void write(Modules modules, Path outputFile) throws IOException { - try (FileWriter writer = new FileWriter(outputFile,false); PrintWriter out = new PrintWriter(writer);) + try (BufferedWriter writer = Files.newBufferedWriter(outputFile,StandardCharsets.UTF_8,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE); + PrintWriter out = new PrintWriter(writer);) { writeHeaderMessage(out,outputFile); @@ -112,7 +116,7 @@ public class ModuleGraphWriter } } - private void writeHeaderMessage(PrintWriter out, File outputFile) + private void writeHeaderMessage(PrintWriter out, Path outputFile) { out.println("/*"); out.println(" * GraphViz Graph of Jetty Modules"); @@ -121,7 +125,7 @@ public class ModuleGraphWriter out.println(" * GraphViz: http://graphviz.org/"); out.println(" * "); out.println(" * To Generate Graph image using graphviz:"); - String filename = outputFile.getName(); + String filename = outputFile.getFileName().toString(); String basename = filename.substring(0,filename.indexOf('.')); out.printf(" * $ dot -Tpng -Goverlap=false -o %s.png %s%n",basename,filename); out.println(" */"); 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 ab263cef4ba..61330ac7546 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 @@ -18,7 +18,6 @@ package org.eclipse.jetty.start; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Path; @@ -380,7 +379,7 @@ public class Modules implements Iterable { if (!modules.containsKey(name)) { - File file = basehome.getFile("modules/" + name + ".mod"); + Path file = basehome.getPath("modules/" + name + ".mod"); if (FS.canReadFile(file)) { Module parent = registerModule(basehome,args,file); @@ -395,7 +394,7 @@ public class Modules implements Iterable { for (Path path : basehome.getPaths("modules/*.mod")) { - registerModule(basehome,args,path.toFile()); + registerModule(basehome,args,path); } // load missing post-expanded dependent modules @@ -420,7 +419,7 @@ public class Modules implements Iterable for (String missingParent : missingParents) { - File file = basehome.getFile("modules/" + missingParent + ".mod"); + Path file = basehome.getPath("modules/" + missingParent + ".mod"); if (FS.canReadFile(file)) { Module module = registerModule(basehome,args,file); @@ -435,7 +434,7 @@ public class Modules implements Iterable } } - private Module registerModule(BaseHome basehome, StartArgs args, File file) throws FileNotFoundException, IOException + private Module registerModule(BaseHome basehome, StartArgs args, Path file) throws FileNotFoundException, IOException { if (!FS.canReadFile(file)) { diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java index e9ebc26d214..f760f6e8e20 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java @@ -18,8 +18,11 @@ package org.eclipse.jetty.start; +import static org.eclipse.jetty.start.UsageException.*; + import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -61,49 +64,90 @@ public final class Props implements Iterable } public static final String ORIGIN_SYSPROP = ""; + + public static String getValue(String arg) + { + int idx = arg.indexOf('='); + if (idx == (-1)) + { + throw new UsageException(ERR_BAD_ARG,"Argument is missing a required value: %s",arg); + } + String value = arg.substring(idx + 1).trim(); + if (value.length() <= 0) + { + throw new UsageException(ERR_BAD_ARG,"Argument is missing a required value: %s",arg); + } + return value; + } + + public static List getValues(String arg) + { + String v = getValue(arg); + ArrayList l = new ArrayList<>(); + for (String s : v.split(",")) + { + if (s != null) + { + s = s.trim(); + if (s.length() > 0) + { + l.add(s); + } + } + } + return l; + } private Map props = new HashMap<>(); + private List sysPropTracking = new ArrayList<>(); public void addAll(Props other) { this.props.putAll(other.props); + this.sysPropTracking.addAll(other.sysPropTracking); } - - public void addAllProperties(List args, String source) + + /** + * Add a potential argument as a property. + *

+ * If arg is not a property, ignore it. + * @param arg the argument to parse for a potential property + * @param source the source for this argument (to track origin of property from) + */ + public void addPossibleProperty(String arg, String source) { - for (String arg : args) + // Start property (syntax similar to System property) + if (arg.startsWith("-D")) { - // Start property (syntax similar to System property) - if (arg.startsWith("-D")) + String[] assign = arg.substring(2).split("=",2); + switch (assign.length) { - String[] assign = arg.substring(2).split("=",2); - switch (assign.length) - { - case 2: - setProperty(assign[0],assign[1],source); - break; - case 1: - setProperty(assign[0],"",source); - break; - default: - break; - } - continue; + case 2: + setSystemProperty(assign[0],assign[1]); + setProperty(assign[0],assign[1],source); + break; + case 1: + setSystemProperty(assign[0],""); + setProperty(assign[0],"",source); + break; + default: + break; } - - // Is this a raw property declaration? - int idx = arg.indexOf('='); - if (idx >= 0) - { - String key = arg.substring(0,idx); - String value = arg.substring(idx + 1); - - setProperty(key,value,source); - continue; - } - - // All other strings are ignored + return; } + + // Is this a raw property declaration? + int idx = arg.indexOf('='); + if (idx >= 0) + { + String key = arg.substring(0,idx); + String value = arg.substring(idx + 1); + + setProperty(key,value,source); + return; + } + + // All other strings are ignored } public String cleanReference(String property) @@ -302,4 +346,10 @@ public final class Props implements Iterable // write normal properties file props.store(stream,comments); } + + public void setSystemProperty(String key, String value) + { + System.setProperty(key,value); + sysPropTracking.add(key); + } } 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 140d84cdda7..46399e6be0e 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 @@ -25,24 +25,22 @@ 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; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.eclipse.jetty.start.Props.Prop; +import org.eclipse.jetty.start.config.ConfigSources; /** * The Arguments required to start Jetty. */ public class StartArgs { - public static final String CMD_LINE_SOURCE = ""; public static final String VERSION; static @@ -69,8 +67,6 @@ public class StartArgs private static final String SERVER_MAIN = "org.eclipse.jetty.xml.XmlConfiguration"; - private List commandLine = new ArrayList<>(); - /** List of enabled modules */ private Set modules = new HashSet<>(); /** Map of enabled modules to the source of where that activation occurred */ @@ -82,16 +78,13 @@ public class StartArgs /** List of all active [lib] sectinos from enabled modules */ private Classpath classpath; /** List of all active [xml] sections from enabled modules */ - private List xmls = new ArrayList<>(); + private List xmls = new ArrayList<>(); /** JVM arguments, found via commmand line and in all active [exec] sections from enabled modules */ private List jvmArgs = new ArrayList<>(); /** List of all xml references found directly on command line or start.ini */ private List xmlRefs = new ArrayList<>(); - /** List of extra Start Directories referenced */ - private LinkedList extraStartRefs = new LinkedList<>(); - private Props properties = new Props(); private Set systemPropertyKeys = new HashSet<>(); private List rawLibs = new ArrayList<>(); @@ -121,9 +114,8 @@ public class StartArgs private boolean exec = false; - public StartArgs(String[] commandLineArgs) + public StartArgs() { - commandLine.addAll(Arrays.asList(commandLineArgs)); classpath = new Classpath(); } @@ -142,13 +134,13 @@ public class StartArgs System.setProperty(key,value); } - private void addUniqueXmlFile(String xmlRef, File xmlfile) throws IOException + private void addUniqueXmlFile(String xmlRef, Path xmlfile) throws IOException { if (!FS.canReadFile(xmlfile)) { throw new IOException("Cannot read file: " + xmlRef); } - xmlfile = xmlfile.getCanonicalFile(); + xmlfile = FS.toRealPath(xmlfile); if (!xmls.contains(xmlfile)) { xmls.add(xmlfile); @@ -166,9 +158,9 @@ public class StartArgs return; } - for (File xml : xmls) + for (Path xml : xmls) { - System.out.printf(" %s%n",baseHome.toShortForm(xml.getAbsolutePath())); + System.out.printf(" %s%n",baseHome.toShortForm(xml.toAbsolutePath())); } } @@ -388,7 +380,7 @@ public class StartArgs for (String xmlRef : module.getXmls()) { // Straight Reference - File xmlfile = baseHome.getFile(xmlRef); + Path xmlfile = baseHome.getPath(xmlRef); addUniqueXmlFile(xmlRef,xmlfile); } @@ -411,16 +403,6 @@ public class StartArgs return classpath; } - public List getCommandLine() - { - return this.commandLine; - } - - public LinkedList getExtraStartRefs() - { - return extraStartRefs; - } - public List getFiles() { return files; @@ -484,9 +466,9 @@ public class StartArgs cmd.addRawArg(prop_file.getAbsolutePath()); } - for (File xml : xmls) + for (Path xml : xmls) { - cmd.addRawArg(xml.getAbsolutePath()); + cmd.addRawArg(xml.toAbsolutePath().toString()); } return cmd; @@ -523,40 +505,7 @@ public class StartArgs return sources.get(module); } - private String getValue(String arg) - { - int idx = arg.indexOf('='); - if (idx == (-1)) - { - throw new UsageException(ERR_BAD_ARG,"Argument is missing a required value: %s",arg); - } - String value = arg.substring(idx + 1).trim(); - if (value.length() <= 0) - { - throw new UsageException(ERR_BAD_ARG,"Argument is missing a required value: %s",arg); - } - return value; - } - - private List getValues(String arg) - { - String v = getValue(arg); - ArrayList l = new ArrayList<>(); - for (String s : v.split(",")) - { - if (s != null) - { - s = s.trim(); - if (s.length() > 0) - { - l.add(s); - } - } - } - return l; - } - - public List getXmlFiles() + public List getXmlFiles() { return xmls; } @@ -656,24 +605,6 @@ public class StartArgs return version; } - public void parse(BaseHome baseHome, StartIni ini) - { - String source; - try - { - source = baseHome.toShortForm(ini.getFile()); - } - catch (Exception e) - { - throw new UsageException(ERR_BAD_ARG,"Bad file: %s",ini); - } - - for (String line : ini) - { - parse(line,source); - } - } - public void parse(final String rawarg, String source) { if (rawarg == null) @@ -695,28 +626,25 @@ public class StartArgs if ("--help".equals(arg) || "-?".equals(arg)) { - if (!CMD_LINE_SOURCE.equals(source)) - { - throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source); - } - help = true; run = false; return; } - if ("--debug".equals(arg)) + if ("--debug".equals(arg) || arg.startsWith("--start-log-file")) { // valid, but handled in StartLog instead return; } + if (arg.startsWith("--extra-start-dir=")) + { + // valid, but handled in ConfigSources instead + return; + } + if ("--stop".equals(arg)) { - if (!CMD_LINE_SOURCE.equals(source)) - { - throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source); - } stopCommand = true; run = false; return; @@ -724,7 +652,7 @@ public class StartArgs if (arg.startsWith("--download=")) { - addFile(getValue(arg)); + addFile(Props.getValue(arg)); run = false; download = true; return; @@ -753,10 +681,6 @@ public class StartArgs if ("--dry-run".equals(arg) || "--exec-print".equals(arg)) { - if (!CMD_LINE_SOURCE.equals(source)) - { - throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source); - } dryRun = true; run = false; return; @@ -769,18 +693,10 @@ public class StartArgs return; } - // Add extra start dir - if (arg.startsWith("--extra-start-dir=")) - { - String dirRef = getValue(arg); - extraStartRefs.add(dirRef); - return; - } - // Arbitrary Libraries if (arg.startsWith("--lib=")) { - String cp = getValue(arg); + String cp = Props.getValue(arg); if (cp != null) { @@ -804,11 +720,7 @@ public class StartArgs // jetty.base build-out : add to ${jetty.base}/start.d/ if (arg.startsWith("--add-to-startd=")) { - if (!CMD_LINE_SOURCE.equals(source)) - { - throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source); - } - addToStartdIni.addAll(getValues(arg)); + addToStartdIni.addAll(Props.getValues(arg)); run = false; download = true; return; @@ -817,11 +729,7 @@ public class StartArgs // jetty.base build-out : add to ${jetty.base}/start.ini if (arg.startsWith("--add-to-start=")) { - if (!CMD_LINE_SOURCE.equals(source)) - { - throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source); - } - addToStartIni.addAll(getValues(arg)); + addToStartIni.addAll(Props.getValues(arg)); run = false; download = true; return; @@ -830,7 +738,7 @@ public class StartArgs // Enable a module if (arg.startsWith("--module=")) { - for (String moduleName : getValues(arg)) + for (String moduleName : Props.getValues(arg)) { modules.add(moduleName); List list = sources.get(moduleName); @@ -847,7 +755,7 @@ public class StartArgs // Create graphviz output of module graph if (arg.startsWith("--write-module-graph=")) { - this.moduleGraphFilename = getValue(arg); + this.moduleGraphFilename = Props.getValue(arg); run = false; return; } @@ -891,14 +799,11 @@ public class StartArgs String key = arg.substring(0,idx); String value = arg.substring(idx + 1); - if (source != CMD_LINE_SOURCE) + if (propertySource.containsKey(key)) { - if (propertySource.containsKey(key)) - { - throw new UsageException(ERR_BAD_ARG,"Property %s in %s already set in %s",key,source,propertySource.get(key)); - } - propertySource.put(key,source); + StartLog.warn("Property %s in %s already set in %s",key,source,propertySource.get(key)); } + propertySource.put(key,source); if ("OPTION".equals(key) || "OPTIONS".equals(key)) { @@ -930,26 +835,16 @@ public class StartArgs throw new UsageException(ERR_BAD_ARG,"Unrecognized argument: \"%s\" in %s",arg,source); } - public StartArgs parseCommandLine() - { - for (String line : commandLine) - { - parse(line,StartArgs.CMD_LINE_SOURCE); - } - - return this; - } - public void resolveExtraXmls(BaseHome baseHome) throws IOException { // Find and Expand XML files for (String xmlRef : xmlRefs) { // Straight Reference - File xmlfile = baseHome.getFile(xmlRef); - if (!xmlfile.exists()) + Path xmlfile = baseHome.getPath(xmlRef); + if (!FS.exists(xmlfile)) { - xmlfile = baseHome.getFile("etc/" + xmlRef); + xmlfile = baseHome.getPath("etc/" + xmlRef); } addUniqueXmlFile(xmlRef,xmlfile); } @@ -964,9 +859,7 @@ public class StartArgs public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("StartArgs [commandLine="); - builder.append(commandLine); - builder.append(", enabledModules="); + builder.append("StartArgs [enabledModules="); builder.append(modules); builder.append(", xmlRefs="); builder.append(xmlRefs); @@ -978,4 +871,8 @@ public class StartArgs return builder.toString(); } + public void parse(ConfigSources sources) + { + // TODO Auto-generated method stub + } } 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 afc2ed1e1bb..79b079cd712 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,9 +21,6 @@ package org.eclipse.jetty.start; import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.util.List; - -import org.eclipse.jetty.start.config.ConfigSource; /** * Simple Start .INI handler diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java index c411d0dae87..1f4105d7058 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java @@ -18,13 +18,15 @@ package org.eclipse.jetty.start; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; + +import org.eclipse.jetty.start.config.CommandLineConfigSource; /** * Centralized Place for logging. @@ -62,7 +64,7 @@ public class StartLog { System.err.printf("INFO: " + format + "%n",args); } - + public static void warn(String format, Object... args) { System.err.printf("WARNING: " + format + "%n",args); @@ -72,7 +74,7 @@ public class StartLog { t.printStackTrace(System.err); } - + public static boolean isDebugEnabled() { return INSTANCE.debug; @@ -80,17 +82,17 @@ public class StartLog private boolean debug = false; - public void initialize(BaseHome baseHome, StartArgs args) throws IOException + public void initialize(BaseHome baseHome, CommandLineConfigSource cmdLineSource) throws IOException { - // Debug with boolean - Pattern debugBoolPat = Pattern.compile("(-D)?debug=(.*)"); - // Log file name - Pattern logFilePat = Pattern.compile("(-D)?start-log-file=(.*)"); + String dbgProp = cmdLineSource.getProperty("debug"); + if (dbgProp != null) + { + debug = Boolean.parseBoolean(dbgProp); + } - // TODO: support backward compatible --daemon argument ?? + String logFileName = cmdLineSource.getProperty("start-log-file"); - Matcher matcher; - for (String arg : args.getCommandLine()) + for (String arg : cmdLineSource.getArgs()) { if ("--debug".equals(arg)) { @@ -98,55 +100,55 @@ public class StartLog continue; } - matcher = debugBoolPat.matcher(arg); - if (matcher.matches()) + if (arg.startsWith("--start-log-file")) { - debug = Boolean.parseBoolean(matcher.group(2)); + logFileName = Props.getValue(arg); continue; } + } - matcher = logFilePat.matcher(arg); - if (matcher.matches()) - { - String filename = matcher.group(2); - File logfile = baseHome.getBaseFile(filename); - initLogFile(logfile); - } + if (logFileName != null) + { + Path logfile = baseHome.getBasePath(logFileName); + initLogFile(logfile); } } - public void initLogFile(File logfile) throws IOException + public void initLogFile(Path logfile) throws IOException { if (logfile != null) { - File logDir = logfile.getParentFile(); - if (!logDir.exists() || !logDir.canWrite()) + try { - String err = String.format("Cannot write %s to directory %s [directory doesn't exist or is read-only]",logfile.getName(), - logDir.getAbsolutePath()); - throw new UsageException(UsageException.ERR_LOGGING,new IOException(err)); + Path logDir = logfile.getParent(); + FS.ensureDirectoryWritable(logDir); + + Path startLog = logfile; + + if (!FS.exists(startLog) && !FS.createNewFile(startLog)) + { + // Output about error is lost in majority of cases. + throw new UsageException(UsageException.ERR_LOGGING,new IOException("Unable to create: " + startLog.toAbsolutePath())); + } + + if (!FS.canWrite(startLog)) + { + // Output about error is lost in majority of cases. + throw new UsageException(UsageException.ERR_LOGGING,new IOException("Unable to write to: " + startLog.toAbsolutePath())); + } + + System.out.println("Logging to " + logfile); + + OutputStream out = Files.newOutputStream(startLog,StandardOpenOption.CREATE,StandardOpenOption.APPEND); + PrintStream logger = new PrintStream(out); + System.setOut(logger); + System.setErr(logger); + System.out.println("Establishing " + logfile + " on " + new Date()); } - - File startLog = logfile; - - if (!startLog.exists() && !startLog.createNewFile()) + catch (IOException e) { - // Output about error is lost in majority of cases. - throw new UsageException(UsageException.ERR_LOGGING,new IOException("Unable to create: " + startLog.getAbsolutePath())); + throw new UsageException(UsageException.ERR_LOGGING,e); } - - if (!startLog.canWrite()) - { - // Output about error is lost in majority of cases. - throw new UsageException(UsageException.ERR_LOGGING,new IOException("Unable to write to: " + startLog.getAbsolutePath())); - } - - System.out.println("Logging to " + logfile); - - PrintStream logger = new PrintStream(new FileOutputStream(startLog,false)); - System.setOut(logger); - System.setErr(logger); - System.out.println("Establishing " + logfile + " on " + new Date()); } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java b/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java index f38c10c36a4..6b9cba7afd0 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java @@ -18,9 +18,11 @@ package org.eclipse.jetty.start.config; +import java.nio.file.Path; import java.util.Arrays; import java.util.List; +import org.eclipse.jetty.start.FS; import org.eclipse.jetty.start.Props; /** @@ -32,24 +34,37 @@ public class CommandLineConfigSource implements ConfigSource private final List args; private final Props props; + private final Path homePath; + private final Path basePath; public CommandLineConfigSource(String rawargs[]) { this.args = Arrays.asList(rawargs); this.props = new Props(); - this.props.addAllProperties(args, CMD_LINE_SOURCE); - } - - @Override - public Props getProps() - { - return props; - } - - @Override - public String getProperty(String key) - { - return props.getString(key); + for (String arg : args) + { + this.props.addPossibleProperty(arg,CMD_LINE_SOURCE); + } + + Path home = FS.toOptionalPath(getProperty("jetty.home")); + Path base = FS.toOptionalPath(getProperty("jetty.base")); + + if (home != null) + { + // logic if home is specified + if (base == null) + { + base = home; + setProperty("jetty.base",base.toString(),""); + } + } + + this.homePath = home; + this.basePath = base; + + // Update System Properties + setSystemProperty("jetty.home",homePath.toAbsolutePath().toString()); + setSystemProperty("jetty.base",basePath.toAbsolutePath().toString()); } @Override @@ -88,12 +103,34 @@ public class CommandLineConfigSource implements ConfigSource return args; } + public Path getBasePath() + { + return basePath; + } + + public Path getHomePath() + { + return homePath; + } + @Override public String getId() { return CMD_LINE_SOURCE; } + @Override + public String getProperty(String key) + { + return props.getString(key); + } + + @Override + public Props getProps() + { + return props; + } + @Override public int getWeight() { @@ -109,6 +146,16 @@ public class CommandLineConfigSource implements ConfigSource return result; } + public void setProperty(String key, String value, String origin) + { + this.props.setProperty(key,value,origin); + } + + public void setSystemProperty(String key, String value) + { + this.props.setSystemProperty(key,value); + } + @Override public String toString() { diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java b/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java index d1cbbe1e206..5f5843e7d2c 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java @@ -80,6 +80,18 @@ public class ConfigSources implements Iterable } } + public CommandLineConfigSource getCommandLineSource() + { + for (ConfigSource source : sources) + { + if (source instanceof CommandLineConfigSource) + { + return (CommandLineConfigSource)source; + } + } + return null; + } + public Prop getProp(String key) { return props.getProp(key); @@ -111,6 +123,31 @@ public class ConfigSources implements Iterable return sources.iterator(); } + public ListIterator reverseListIterator() + { + return sources.listIterator(sources.size()); + } + + @Override + public String toString() + { + StringBuilder str = new StringBuilder(); + str.append(this.getClass().getSimpleName()); + str.append('['); + boolean delim = false; + for (ConfigSource source : sources) + { + if (delim) + { + str.append(','); + } + str.append(source.getId()); + delim = true; + } + str.append(']'); + return str.toString(); + } + private void updateProps() { props.reset(); diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java b/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java index ee6224aedf5..b3a818c3bf0 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java @@ -18,19 +18,25 @@ package org.eclipse.jetty.start.config; +import static org.eclipse.jetty.start.UsageException.*; + import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.eclipse.jetty.start.FS; +import org.eclipse.jetty.start.NaturalSort; import org.eclipse.jetty.start.PathMatchers; import org.eclipse.jetty.start.Props; +import org.eclipse.jetty.start.UsageException; import org.eclipse.jetty.start.Props.Prop; import org.eclipse.jetty.start.StartIni; +import org.eclipse.jetty.start.StartLog; /** * A Directory based {@link ConfigSource}. @@ -39,6 +45,29 @@ import org.eclipse.jetty.start.StartIni; */ public class DirConfigSource implements ConfigSource { + private static final List BANNED_ARGS; + + static + { + // Arguments that are not allowed to be in start.ini or start.d/{name}.ini files + BANNED_ARGS = new ArrayList<>(); + BANNED_ARGS.add("--help"); + BANNED_ARGS.add("-?"); + BANNED_ARGS.add("--stop"); + BANNED_ARGS.add("--dry-run"); + BANNED_ARGS.add("--exec-print"); + BANNED_ARGS.add("--list-config"); + BANNED_ARGS.add("--list-classpath"); + BANNED_ARGS.add("--list-modules"); + BANNED_ARGS.add("--write-module-graph"); + BANNED_ARGS.add("--version"); + BANNED_ARGS.add("-v"); + BANNED_ARGS.add("--download"); + BANNED_ARGS.add("--create-files"); + BANNED_ARGS.add("--add-to-startd"); + BANNED_ARGS.add("--add-to-start"); + } + private final String id; private final Path dir; private final int weight; @@ -62,7 +91,7 @@ public class DirConfigSource implements ConfigSource public DirConfigSource(String id, Path dir, int weight, boolean canHaveArgs) throws IOException { this.id = id; - this.dir = dir; + this.dir = dir.toAbsolutePath(); this.weight = weight; this.props = new Props(); @@ -75,7 +104,7 @@ public class DirConfigSource implements ConfigSource { StartIni ini = new StartIni(iniFile); args.addAll(ini.getLines()); - this.props.addAllProperties(ini.getLines(),iniFile.toString()); + parseAllArgs(ini.getLines(),iniFile.toString()); } Path startDdir = dir.resolve("start.d"); @@ -93,45 +122,74 @@ public class DirConfigSource implements ConfigSource } }; + List paths = new ArrayList<>(); + for (Path diniFile : Files.newDirectoryStream(startDdir,filter)) { if (FS.canReadFile(diniFile)) { - StartIni ini = new StartIni(diniFile); - args.addAll(ini.getLines()); - this.props.addAllProperties(ini.getLines(),diniFile.toString()); + paths.add(diniFile); } } + + Collections.sort(paths,new NaturalSort.Paths()); + + for (Path diniFile : paths) + { + StartLog.debug("Reading %s/start.d/%s - %s",id,diniFile.getFileName(),diniFile); + StartIni ini = new StartIni(diniFile); + args.addAll(ini.getLines()); + parseAllArgs(ini.getLines(),diniFile.toString()); + } } } } - @Override - public int hashCode() + private void parseAllArgs(List lines, String origin) { - final int prime = 31; - int result = 1; - result = prime * result + ((dir == null)?0:dir.hashCode()); - return result; + for (String line : lines) + { + String arg = line; + int idx = line.indexOf('='); + if (idx > 0) + { + arg = line.substring(0,idx); + } + if (BANNED_ARGS.contains(arg)) + { + throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,origin); + } + this.props.addPossibleProperty(line,origin); + } } @Override public boolean equals(Object obj) { if (this == obj) + { return true; + } if (obj == null) + { return false; + } if (getClass() != obj.getClass()) + { return false; + } DirConfigSource other = (DirConfigSource)obj; if (dir == null) { if (other.dir != null) + { return false; + } } else if (!dir.equals(other.dir)) + { return false; + } return true; } @@ -152,18 +210,6 @@ public class DirConfigSource implements ConfigSource return id; } - @Override - public int getWeight() - { - return weight; - } - - @Override - public Props getProps() - { - return props; - } - @Override public String getProperty(String key) { @@ -175,6 +221,32 @@ public class DirConfigSource implements ConfigSource return prop.value; } + @Override + public Props getProps() + { + return props; + } + + @Override + public int getWeight() + { + return weight; + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = (prime * result) + ((dir == null)?0:dir.hashCode()); + return result; + } + + public boolean isPropertyBased() + { + return id.contains("${"); + } + @Override public String toString() { 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 5514abd66ab..368668bfd9b 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 @@ -26,6 +26,9 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.start.config.ConfigSources; +import org.eclipse.jetty.start.config.JettyBaseConfigSource; +import org.eclipse.jetty.start.config.JettyHomeConfigSource; import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.junit.Assert; @@ -92,18 +95,22 @@ public class BaseHomeTest } @Test - public void testGetFile_OnlyHome() throws IOException + public void testGetPath_OnlyHome() throws IOException { File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); File baseDir = null; + + ConfigSources config = new ConfigSources(); + config.add(new JettyHomeConfigSource(homeDir.toPath())); BaseHome hb = new BaseHome(homeDir,baseDir); - File startIni = hb.getFile("start.ini"); + hb.initialize(config); + Path startIni = hb.getPath("start.ini"); String ref = hb.toShortForm(startIni); Assert.assertThat("Reference",ref,startsWith("${jetty.home}")); - String contents = IO.readToString(startIni); + String contents = IO.readToString(startIni.toFile()); Assert.assertThat("Contents",contents,containsString("Home Ini")); } @@ -113,7 +120,11 @@ public class BaseHomeTest File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); File baseDir = null; + ConfigSources config = new ConfigSources(); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + BaseHome hb = new BaseHome(homeDir,baseDir); + hb.initialize(config); List paths = hb.getPaths("start.d/*"); List expected = new ArrayList<>(); @@ -133,7 +144,11 @@ public class BaseHomeTest File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); File baseDir = null; + ConfigSources config = new ConfigSources(); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + BaseHome hb = new BaseHome(homeDir,baseDir); + hb.initialize(config); List paths = hb.getPaths("start.d/*.ini"); List expected = new ArrayList<>(); @@ -153,7 +168,12 @@ public class BaseHomeTest File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); File baseDir = MavenTestingUtils.getTestResourceDir("hb.1/base"); + ConfigSources config = new ConfigSources(); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + BaseHome hb = new BaseHome(homeDir,baseDir); + hb.initialize(config); List paths = hb.getPaths("start.d/*.ini"); List expected = new ArrayList<>(); @@ -167,30 +187,6 @@ public class BaseHomeTest assertPathList(hb,"Paths found",expected,paths); } - - @Test - public void testGetPaths_More() throws IOException - { - File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); - File baseDir = MavenTestingUtils.getTestResourceDir("hb.1/base"); - File moreDir = MavenTestingUtils.getTestResourceDir("extra-start-dirs/more-startd"); - - BaseHome hb = new BaseHome(homeDir,baseDir); - hb.addExtraStart("more",moreDir); - List paths = hb.getPaths("start.d/*.ini"); - - List expected = new ArrayList<>(); - expected.add("${more}/start.d/more.ini"); - expected.add("${jetty.base}/start.d/jmx.ini"); - expected.add("${jetty.home}/start.d/jndi.ini"); - expected.add("${jetty.home}/start.d/jsp.ini"); - expected.add("${jetty.base}/start.d/logging.ini"); - expected.add("${jetty.home}/start.d/ssl.ini"); - expected.add("${jetty.base}/start.d/myapp.ini"); - FSTest.toOsSeparators(expected); - - assertPathList(hb,"Paths found",expected,paths); - } @Test public void testDefault() throws IOException @@ -201,18 +197,23 @@ public class BaseHomeTest } @Test - public void testGetFile_Both() throws IOException + public void testGetPath_Both() throws IOException { File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); File baseDir = MavenTestingUtils.getTestResourceDir("hb.1/base"); + ConfigSources config = new ConfigSources(); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + BaseHome hb = new BaseHome(homeDir,baseDir); - File startIni = hb.getFile("start.ini"); + hb.initialize(config); + Path startIni = hb.getPath("start.ini"); String ref = hb.toShortForm(startIni); Assert.assertThat("Reference",ref,startsWith("${jetty.base}")); - String contents = IO.readToString(startIni); + String contents = IO.readToString(startIni.toFile()); Assert.assertThat("Contents",contents,containsString("Base Ini")); } } diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java index 5ad4a238170..dcd9baf221d 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java @@ -25,6 +25,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -64,7 +65,7 @@ public class ConfigurationAssert } } List actualXmls = new ArrayList<>(); - for (File xml : args.getXmlFiles()) + for (Path xml : args.getXmlFiles()) { actualXmls.add(shorten(baseHome,xml,testResourcesDir)); } @@ -82,7 +83,7 @@ public class ConfigurationAssert List actualLibs = new ArrayList<>(); for (File path : args.getClasspath()) { - actualLibs.add(shorten(baseHome,path,testResourcesDir)); + actualLibs.add(shorten(baseHome,path.toPath(),testResourcesDir)); } assertContainsUnordered("Libs",expectedLibs,actualLibs); @@ -147,7 +148,7 @@ public class ConfigurationAssert assertContainsUnordered("Files/Dirs",expectedFiles,actualFiles); } - private static String shorten(BaseHome baseHome, File path, File testResourcesDir) + private static String shorten(BaseHome baseHome, Path path, File testResourcesDir) { String value = baseHome.toShortForm(path); if (value.startsWith(testResourcesDir.getAbsolutePath())) diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ExtraStartTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ExtraStartTest.java index c217e53d02e..f22c37b3fd6 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ExtraStartTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ExtraStartTest.java @@ -25,6 +25,9 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.jetty.start.Props.Prop; +import org.eclipse.jetty.start.config.ConfigSource; +import org.eclipse.jetty.start.config.ConfigSources; +import org.eclipse.jetty.start.config.DirConfigSource; import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.TestingDir; import org.junit.Assert; @@ -40,14 +43,15 @@ public class ExtraStartTest public void assertSearchOrder(List expectedSearchOrder) { + ConfigSources sources = main.getBaseHome().getConfigSources(); List actualOrder = new ArrayList<>(); - actualOrder.add("${jetty.base}"); - List startRefs = args.getExtraStartRefs(); - if (startRefs.size() > 0) + for (ConfigSource source : sources) { - actualOrder.addAll(startRefs); + if (source instanceof DirConfigSource) + { + actualOrder.add(source.getId()); + } } - actualOrder.add("${jetty.home}"); ConfigurationAssert.assertOrdered("Search Order",expectedSearchOrder,actualOrder); } @@ -92,7 +96,7 @@ public class ExtraStartTest FS.ensureEmpty(base); TestEnv.makeFile(base,"start.ini", // "jetty.host=127.0.0.1"); - + // Simple command line - no reference to extra-start-dirs MainResult result = runMain(base,home); @@ -125,7 +129,7 @@ public class ExtraStartTest // Simple command line reference to extra-start-dir MainResult result = runMain(base,home, - // direct reference via path + // direct reference via path "--extra-start-dir=" + common.getAbsolutePath()); List expectedSearchOrder = new ArrayList<>(); @@ -158,9 +162,9 @@ public class ExtraStartTest "jetty.host=127.0.0.1"); // Simple command line reference to extra-start-dir via property (also on command line) - MainResult result = runMain(base,home, - // property - "my.common=" + common.getAbsolutePath(), + MainResult result = runMain(base,home, + // property + "my.common=" + common.getAbsolutePath(), // reference via property "--extra-start-dir=${my.common}"); @@ -185,9 +189,9 @@ public class ExtraStartTest // Create opt File opt = testdir.getFile("opt"); FS.ensureEmpty(opt); - + // Create common - File common = new File(opt, "common"); + File common = new File(opt,"common"); FS.ensureEmpty(common); TestEnv.makeFile(common,"start.ini","jetty.port=8080"); @@ -196,13 +200,13 @@ public class ExtraStartTest FS.ensureEmpty(base); TestEnv.makeFile(base,"start.ini", // "jetty.host=127.0.0.1"); - + String dirRef = "${my.opt}" + File.separator + "common"; // Simple command line reference to extra-start-dir via property (also on command line) - MainResult result = runMain(base,home, - // property to 'opt' dir - "my.opt=" + opt.getAbsolutePath(), + MainResult result = runMain(base,home, + // property to 'opt' dir + "my.opt=" + opt.getAbsolutePath(), // reference via property prefix "--extra-start-dir=" + dirRef); @@ -219,7 +223,7 @@ public class ExtraStartTest @Test public void testCommandLine_1Extra_FromCompoundProp() throws Exception { - // Create home + // Create home File home = testdir.getFile("home"); FS.ensureEmpty(home); TestEnv.copyTestDir("usecases/home",home); @@ -227,9 +231,9 @@ public class ExtraStartTest // Create opt File opt = testdir.getFile("opt"); FS.ensureEmpty(opt); - + // Create common - File common = new File(opt, "common"); + File common = new File(opt,"common"); FS.ensureEmpty(common); TestEnv.makeFile(common,"start.ini","jetty.port=8080"); @@ -238,12 +242,12 @@ public class ExtraStartTest FS.ensureEmpty(base); TestEnv.makeFile(base,"start.ini", // "jetty.host=127.0.0.1"); - + String dirRef = "${my.opt}" + File.separator + "${my.dir}"; - + // Simple command line reference to extra-start-dir via property (also on command line) - MainResult result = runMain(base,home, - // property to 'opt' dir + MainResult result = runMain(base,home, + // property to 'opt' dir "my.opt=" + opt.getAbsolutePath(), // property to commmon dir name "my.dir=common", @@ -327,7 +331,7 @@ public class ExtraStartTest result.assertProperty("jetty.host","127.0.0.1"); result.assertProperty("jetty.port","8080"); // from 'common' } - + @Test public void testRefCommonRefCorp() throws Exception { @@ -368,7 +372,7 @@ public class ExtraStartTest result.assertProperty("jetty.host","127.0.0.1"); result.assertProperty("jetty.port","8080"); // from 'common' } - + @Test public void testRefCommonRefCorp_FromSimpleProps() throws Exception { @@ -396,7 +400,7 @@ public class ExtraStartTest FS.ensureEmpty(base); TestEnv.makeFile(base,"start.ini", // "jetty.host=127.0.0.1",// - "my.common="+common.getAbsolutePath(), // + "my.common=" + common.getAbsolutePath(), // "--extra-start-dir=${my.common}"); MainResult result = runMain(base,home); @@ -411,7 +415,7 @@ public class ExtraStartTest result.assertProperty("jetty.host","127.0.0.1"); result.assertProperty("jetty.port","8080"); // from 'common' } - + @Test public void testRefCommonRefCorp_CmdLineRef() throws Exception { @@ -448,7 +452,7 @@ public class ExtraStartTest "--extra-start-dir=" + common.getAbsolutePath()); MainResult result = runMain(base,home, - // command line provided extra-start-dir ref + // command line provided extra-start-dir ref "--extra-start-dir=" + devops.getAbsolutePath()); List expectedSearchOrder = new ArrayList<>(); @@ -462,7 +466,7 @@ public class ExtraStartTest result.assertProperty("jetty.host","127.0.0.1"); result.assertProperty("jetty.port","2222"); // from 'devops' } - + @Test public void testRefCommonRefCorp_CmdLineProp() throws Exception { @@ -492,7 +496,7 @@ public class ExtraStartTest "--extra-start-dir=" + common.getAbsolutePath()); MainResult result = runMain(base,home, - // command line property should override all others + // command line property should override all others "jetty.port=7070"); List expectedSearchOrder = new ArrayList<>(); @@ -505,7 +509,7 @@ public class ExtraStartTest result.assertProperty("jetty.host","127.0.0.1"); result.assertProperty("jetty.port","7070"); // from command line } - + @Test public void testBadDoubleRef() throws Exception { @@ -521,15 +525,15 @@ public class ExtraStartTest // Create corp File corp = testdir.getFile("corp"); FS.ensureEmpty(corp); - TestEnv.makeFile(corp,"start.ini", - // standard property + TestEnv.makeFile(corp,"start.ini", + // standard property "jetty.port=9090", // INTENTIONAL BAD Reference (duplicate) "--extra-start-dir=" + common.getAbsolutePath()); // Populate common - TestEnv.makeFile(common,"start.ini", - // standard property + TestEnv.makeFile(common,"start.ini", + // standard property "jetty.port=8080", // reference to corp "--extra-start-dir=" + corp.getAbsolutePath()); diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java index 92ad50363a3..c4aeb53c282 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java @@ -18,13 +18,16 @@ package org.eclipse.jetty.start; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; import java.io.File; import java.io.IOException; -import java.util.Collections; -import java.util.List; +import java.nio.file.Path; +import org.eclipse.jetty.start.config.CommandLineConfigSource; +import org.eclipse.jetty.start.config.ConfigSources; +import org.eclipse.jetty.start.config.JettyBaseConfigSource; +import org.eclipse.jetty.start.config.JettyHomeConfigSource; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.TestingDir; import org.junit.Assert; @@ -33,30 +36,40 @@ import org.junit.Test; public class ModuleGraphWriterTest { - @SuppressWarnings("unused") - private final static List TEST_SOURCE = Collections.singletonList(""); - - private StartArgs DEFAULT_ARGS = new StartArgs(new String[]{"jetty.version=TEST"}).parseCommandLine(); - @Rule public TestingDir testdir = new TestingDir(); @Test public void testGenerate_NothingEnabled() throws IOException { + // Test Env File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home"); File baseDir = testdir.getEmptyDir(); - BaseHome basehome = new BaseHome(homeDir,baseDir); + String cmdLine[] = new String[] {"jetty.version=TEST"}; + + // Configuration + CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); + ConfigSources config = new ConfigSources(); + config.add(cmdLineSource); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + + // Initialize + BaseHome basehome = new BaseHome(); + basehome.initialize(config); + + StartArgs args = new StartArgs(); + args.parse(config); Modules modules = new Modules(); - modules.registerAll(basehome, DEFAULT_ARGS); + modules.registerAll(basehome, args); modules.buildGraph(); - File outputFile = new File(baseDir,"graph.dot"); + Path outputFile = basehome.getBasePath("graph.dot"); ModuleGraphWriter writer = new ModuleGraphWriter(); writer.write(modules,outputFile); - Assert.assertThat("Output File Exists",outputFile.exists(),is(true)); + Assert.assertThat("Output File Exists",FS.exists(outputFile),is(true)); } } diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java index 31b2e4d299e..c49ee3a1068 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java @@ -34,7 +34,7 @@ public class ModuleTest private Module loadTestHomeModule(String moduleFileName) throws IOException { File file = MavenTestingUtils.getTestResourceFile("usecases/home/modules/" + moduleFileName); - return new Module(new BaseHome(),file); + return new Module(new BaseHome(),file.toPath()); } @Test 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 6ce160cd9d1..744a3bdc66e 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 @@ -27,23 +27,48 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.eclipse.jetty.start.config.CommandLineConfigSource; +import org.eclipse.jetty.start.config.ConfigSources; +import org.eclipse.jetty.start.config.JettyBaseConfigSource; +import org.eclipse.jetty.start.config.JettyHomeConfigSource; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestingDir; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; public class ModulesTest { private final static List TEST_SOURCE = Collections.singletonList(""); - private StartArgs DEFAULT_ARGS = new StartArgs(new String[] { "jetty.version=TEST" }).parseCommandLine(); + + @Rule + public TestingDir testdir = new TestingDir(); @Test public void testLoadAllModules() throws IOException { + // Test Env File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home"); - BaseHome basehome = new BaseHome(homeDir,homeDir); + File baseDir = testdir.getEmptyDir(); + String cmdLine[] = new String[] {"jetty.version=TEST"}; + + // Configuration + CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); + ConfigSources config = new ConfigSources(); + config.add(cmdLineSource); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + + // Initialize + BaseHome basehome = new BaseHome(); + basehome.initialize(config); + + StartArgs args = new StartArgs(); + args.parse(config); + // Test Modules Modules modules = new Modules(); - modules.registerAll(basehome,DEFAULT_ARGS); + modules.registerAll(basehome,args); List moduleNames = new ArrayList<>(); for (Module mod : modules) @@ -66,11 +91,28 @@ public class ModulesTest @Test public void testEnableRegexSimple() throws IOException { + // Test Env File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home"); - BaseHome basehome = new BaseHome(homeDir,homeDir); + File baseDir = testdir.getEmptyDir(); + String cmdLine[] = new String[] {"jetty.version=TEST"}; + + // Configuration + CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); + ConfigSources config = new ConfigSources(); + config.add(cmdLineSource); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + + // Initialize + BaseHome basehome = new BaseHome(); + basehome.initialize(config); + + StartArgs args = new StartArgs(); + args.parse(config); + // Test Modules Modules modules = new Modules(); - modules.registerAll(basehome,DEFAULT_ARGS); + modules.registerAll(basehome,args); modules.enable("[sj]{1}.*",TEST_SOURCE); String expected[] = { "jmx", "stats", "spdy", "security", "jndi", "jsp", "servlet", "jaas", "server" }; @@ -81,12 +123,28 @@ public class ModulesTest @Test public void testResolve_ServerHttp() throws IOException { + // Test Env File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home"); - BaseHome basehome = new BaseHome(homeDir,homeDir); + File baseDir = testdir.getEmptyDir(); + String cmdLine[] = new String[] {"jetty.version=TEST"}; + + // Configuration + CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); + ConfigSources config = new ConfigSources(); + config.add(cmdLineSource); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + + // Initialize + BaseHome basehome = new BaseHome(); + basehome.initialize(config); + + StartArgs args = new StartArgs(); + args.parse(config); - // Register modules + // Test Modules Modules modules = new Modules(); - modules.registerAll(basehome,DEFAULT_ARGS); + modules.registerAll(basehome,args); modules.buildGraph(); // Enable 2 modules @@ -137,12 +195,28 @@ public class ModulesTest @Test public void testResolve_WebSocket() throws IOException { + // Test Env File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home"); - BaseHome basehome = new BaseHome(homeDir,homeDir); + File baseDir = testdir.getEmptyDir(); + String cmdLine[] = new String[] {"jetty.version=TEST"}; + + // Configuration + CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); + ConfigSources config = new ConfigSources(); + config.add(cmdLineSource); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + + // Initialize + BaseHome basehome = new BaseHome(); + basehome.initialize(config); + + StartArgs args = new StartArgs(); + args.parse(config); - // Register modules + // Test Modules Modules modules = new Modules(); - modules.registerAll(basehome,DEFAULT_ARGS); + modules.registerAll(basehome,args); modules.buildGraph(); // modules.dump();