All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.start.BaseHome Maven / Gradle / Ivy

The newest version!
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.start;

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(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}%s%s", name, FS.separator(), relative); } } public static final String JETTY_BASE = "jetty.base"; public static final String JETTY_HOME = "jetty.home"; private static final EnumSet SEARCH_VISIT_OPTIONS = EnumSet.of(FileVisitOption.FOLLOW_LINKS); private static final 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).normalize().toAbsolutePath(); } 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. *

    *
  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 include-jetty-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) { 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 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: *

    *
  1. 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.
  2. *
  3. 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.
  4. *
  5. All other patterns are treated as relative to BaseHome information: *
      *
    1. Search ${jetty.home} first
    2. *
    3. Search ${jetty.base} for overrides
    4. *
    *
  6. *
*

* Pattern examples: *

*
lib/logging/*.jar
*
Relative pattern, not recursive, search ${jetty.home} then ${jetty.base} for lib/logging/*.jar content
* *
lib/**/*-dev.jar
*
Relative pattern, recursive search ${jetty.home} then ${jetty.base} for files under lib ending in * -dev.jar
* *
etc/jetty.xml
*
Relative pattern, no glob, search for ${jetty.home}/etc/jetty.xml then ${jetty.base}/etc/jetty.xml
* *
glob:/opt/app/common/*-corp.jar
*
PathMapper pattern, glob, search /opt/app/common/ for *-corp.jar
* *
* *

* Notes: *

    *
  • FileSystem case sensitivity is implementation specific (eg: linux is case-sensitive, windows is case-insensitive).
    * See {@link java.nio.file.FileSystem#getPathMatcher(String)} for more details
  • *
  • Pattern slashes are implementation neutral (use '/' always and you'll be fine)
  • *
  • Recursive searching is limited to 30 levels deep (not configurable)
  • *
  • File System loops are detected and skipped
  • *
* * @param pattern the pattern to search. * @return the collection of paths found * @throws IOException if error during search operation */ public List getPaths(String pattern) throws IOException { StartLog.debug("getPaths('%s')", pattern); List hits = new ArrayList<>(); if (PathMatchers.isAbsolute(pattern)) { // Perform absolute path pattern search // The root to start search from Path root = PathMatchers.getSearchRoot(pattern); // The matcher for file hits PathMatcher matcher = PathMatchers.getMatcher(pattern); if (FS.isValidDirectory(root)) { PathFinder finder = new PathFinder(); finder.setIncludeDirsInResults(true); finder.setFileMatcher(matcher); finder.setBase(root); Files.walkFileTree(root, SEARCH_VISIT_OPTIONS, MAX_SEARCH_DEPTH, finder); hits.addAll(finder.getHits()); } } else { // Perform relative path pattern search Path relativePath = PathMatchers.getSearchRoot(pattern); PathMatcher matcher = PathMatchers.getMatcher(pattern); PathFinder finder = new PathFinder(); finder.setIncludeDirsInResults(true); finder.setFileMatcher(matcher); // walk config sources backwards ... ListIterator iter = sources.reverseListIterator(); while (iter.hasPrevious()) { ConfigSource source = iter.previous(); if (source instanceof DirConfigSource) { 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); } } } hits.addAll(finder.getHits()); } Collections.sort(hits, new NaturalSort.Paths()); return hits; } public boolean isBaseDifferent() { return homeDir.compareTo(baseDir) != 0; } /** * 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%s%s", dirsource.getId(), FS.separator(), 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) || (path.charAt(0) == '<')) { return path; } return toShortForm(FS.toPath(path)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy