org.eclipse.jetty.start.BaseHome Maven / Gradle / Ivy
// // ======================================================================== // 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.nio.file.PathMatcher; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.ListIterator; import java.util.Objects; 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; import org.eclipse.jetty.start.config.JettyBaseConfigSource; import org.eclipse.jetty.start.config.JettyHomeConfigSource; /** * File access for
* * * *${jetty.home}
,${jetty.base}
, directories. ** By default, both
${jetty.home}
and${jetty.base}
are the same directory, but they can point at different directories. ** The
${jetty.home}
directory is where the main Jetty binaries and default configuration is housed. ** The
${jetty.base}
directory is where the execution specific configuration and webapps are obtained from. */ public class BaseHome { public static class SearchDir { private Path dir; private String name; public SearchDir(String name) { this.name = name; } public Path getDir() { 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) { if (path != null) { return setDir(path.toPath()); } return this; } public SearchDir setDir(Path path) { if (path != null) { this.dir = path.toAbsolutePath(); } return this; } public SearchDir setDir(String path) { if (path != null) { return setDir(FS.toPath(path)); } return this; } public String toShortForm(Path path) { Path relative = dir.relativize(path); return String.format("${%s}%c%s",name,File.separatorChar,relative.toString()); } } public static final String JETTY_BASE = "jetty.base"; public static final String JETTY_HOME = "jetty.home"; private final static EnumSetSEARCH_VISIT_OPTIONS = EnumSet.of(FileVisitOption.FOLLOW_LINKS); private final static int MAX_SEARCH_DEPTH = Integer.getInteger("org.eclipse.jetty.start.searchDepth",10); private final ConfigSources sources; private final Path homeDir; private final Path baseDir; public BaseHome() throws IOException { this(new String[0]); } public BaseHome(String cmdLine[]) throws IOException { this(new CommandLineConfigSource(cmdLine)); } public BaseHome(CommandLineConfigSource cmdLineSource) throws IOException { sources = new ConfigSources(); sources.add(cmdLineSource); this.homeDir = cmdLineSource.getHomePath(); this.baseDir = cmdLineSource.getBasePath(); // TODO this is cyclic construction as start log uses BaseHome, but BaseHome constructor // calls other constructors that log. This appears to be a workable sequence. StartLog.getInstance().initialize(this,cmdLineSource); sources.add(new JettyBaseConfigSource(cmdLineSource.getBasePath())); sources.add(new JettyHomeConfigSource(cmdLineSource.getHomePath())); System.setProperty(JETTY_HOME,homeDir.toAbsolutePath().toString()); System.setProperty(JETTY_BASE,baseDir.toAbsolutePath().toString()); } public BaseHome(ConfigSources sources) { this.sources = sources; Path home = null; Path base = null; for (ConfigSource source : sources) { if (source instanceof CommandLineConfigSource) { CommandLineConfigSource cmdline = (CommandLineConfigSource)source; home = cmdline.getHomePath(); base = cmdline.getBasePath(); } else if (source instanceof JettyBaseConfigSource) { base = ((JettyBaseConfigSource)source).getDir(); } else if (source instanceof JettyHomeConfigSource) { home = ((JettyHomeConfigSource)source).getDir(); } } Objects.requireNonNull(home,"jetty.home cannot be null"); this.homeDir = home; this.baseDir = (base != null)?base:home; System.setProperty(JETTY_HOME,homeDir.toAbsolutePath().toString()); System.setProperty(JETTY_BASE,baseDir.toAbsolutePath().toString()); } public String getBase() { if (baseDir == null) { return null; } return baseDir.toString(); } public Path getBasePath() { return baseDir; } /** * Create a {@link Path} reference to some content in "${jetty.base}"
* * @param path * the path to reference * @return the file reference */ public Path getBasePath(String path) { return baseDir.resolve(path); } public ConfigSources getConfigSources() { return this.sources; } public String getHome() { return homeDir.toString(); } public Path getHomePath() { return homeDir; } /** * Get a specific path reference. ** Path references are searched based on the config source search order. *
*
* * @param path * the path to get. * @return the path reference. */ public Path getPath(final String path) { Path apath = FS.toPath(path); if (apath.isAbsolute()) { if (FS.exists(apath)) { return apath; } } for (ConfigSource source : sources) { if (source instanceof DirConfigSource) { DirConfigSource dirsource = (DirConfigSource)source; Path file = dirsource.getDir().resolve(apath); if (FS.exists(file)) { return file; } } } // 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- If provided path is an absolute reference., and exists, return that reference
*- If exists relative to
*${jetty.base}
, return that reference- If exists relative to and
*include-jetty-dir
locations, return that reference- If exists relative to
*${jetty.home}
, return that reference- Return standard {@link Path} reference obtained from {@link java.nio.file.FileSystem#getPath(String, String...)} (no exists check performed)
*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); finder.setIncludeDirsInResults(true); 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. * * 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 underlib
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 *
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.
*
* @param path
* the path to shorten
* @return the potentially shortened path
*/
public String toShortForm(final Path path)
{
Path apath = path.toAbsolutePath();
for (ConfigSource source : sources)
{
if (source instanceof DirConfigSource)
{
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();
}
}
}
}
return apath.toString();
}
/**
* Replace/Shorten arbitrary path with property strings "${jetty.home}"
or "${jetty.base}"
where appropriate.
*
* @param path
* the path to shorten
* @return the potentially shortened path
*/
public String toShortForm(final String path)
{
if (path == null)
{
return path;
}
return toShortForm(FS.toPath(path));
}
}