diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java index d971aca7fe3..751212651ae 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java @@ -170,21 +170,13 @@ public class Config /** * Natural language sorting for key names. */ - private final Comparator keySorter = new Comparator() - { - private final Collator collator = Collator.getInstance(); - - public int compare(String o1, String o2) - { - CollationKey key1 = collator.getCollationKey(o1); - CollationKey key2 = collator.getCollationKey(o2); - return key1.compareTo(key2); - } - }; + private final Comparator keySorter = new NaturalSort.Strings(); private static final String __version; private static boolean DEBUG = false; private static Config __instance; + + private final HomeBase _homebase; private final Map _properties = new HashMap(); private final Map _classpaths = new HashMap(); private final List _xml = new ArrayList(); @@ -192,11 +184,6 @@ public class Config private int argCount = 0; - public Config() - { - __instance=this; - } - private final Set _options = new TreeSet(new Comparator() { // Make sure "*" is always at the end of the list @@ -213,6 +200,21 @@ public class Config return o1.compareTo(o2); } }); + + public Config() + { + __instance=this; + _homebase = new HomeBase(); + setProperty("jetty.home",_homebase.getHome()); + if(_homebase.hasBase()) { + setProperty("jetty.base",_homebase.getBase()); + } + } + + public HomeBase getHomeBase() + { + return _homebase; + } public Classpath defineOption(String option) { @@ -292,32 +294,12 @@ public class Config private void close(InputStream stream) { - if (stream == null) - return; - - try - { - stream.close(); - } - catch (IOException ignore) - { - /* ignore */ - } + FS.close(stream); } private void close(Reader reader) { - if (reader == null) - return; - - try - { - reader.close(); - } - catch (IOException ignore) - { - /* ignore */ - } + FS.close(reader); } public static boolean isDebug() @@ -1031,38 +1013,4 @@ public class Config return buf.toString(); } - - public String getJettyHome() - { - return getProperty("jetty.home"); - } - - public String getJettyBase() - { - return getProperty("jetty.base"); - } - - public File getFileBaseHomeAbs(String filename) - { - File file; - - String base = getJettyBase(); - if (base!=null) - { - file=new File(base,filename); - if (file.exists()) - return file; - } - - file=new File(getJettyHome(),filename); - if (file.exists()) - return file; - - file=new File(filename); - if (file.exists()) - return file; - - return null; - - } } 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 new file mode 100644 index 00000000000..9476f8425ed --- /dev/null +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java @@ -0,0 +1,89 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.Closeable; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.regex.Pattern; + +public class FS +{ + public static class FilenameRegexFilter implements FileFilter + { + private final Pattern pattern; + + public FilenameRegexFilter(String regex) + { + pattern = Pattern.compile(regex,Pattern.CASE_INSENSITIVE); + } + + @Override + public boolean accept(File path) + { + return pattern.matcher(path.getName()).matches(); + } + } + + public static class IniFilter extends FilenameRegexFilter + { + public IniFilter() + { + super("^.*\\.ini$"); + } + } + + public static class XmlFilter extends FilenameRegexFilter + { + public XmlFilter() + { + super("^.*\\.xml$"); + } + } + + public static boolean isXml(String filename) + { + return Pattern.compile(".xml$",Pattern.CASE_INSENSITIVE).matcher(filename).matches(); + } + + public static boolean isFile(File file) + { + if (file == null) + { + return false; + } + return file.exists() && file.isFile(); + } + + public static void close(Closeable c) + { + if (c == null) + return; + + try + { + c.close(); + } + catch (IOException ignore) + { + /* ignore */ + } + } +} diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/HomeBase.java b/jetty-start/src/main/java/org/eclipse/jetty/start/HomeBase.java index 7322bb6673a..a7097c612ad 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/HomeBase.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/HomeBase.java @@ -23,6 +23,7 @@ import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -42,87 +43,6 @@ public class HomeBase } } - private final File homeDir; - private final File baseDir; - - public HomeBase(File homeDir, File baseDir) - { - this.homeDir = homeDir; - this.baseDir = baseDir; - } - - /** - * 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(String path) - { - if (path == null) - { - return path; - } - - String value = homeDir.getAbsolutePath(); - - if (path.startsWith(value)) - { - return "${jetty.home}" + path.substring(value.length()); - } - - if (baseDir != null) - { - value = baseDir.getAbsolutePath(); - if (path.startsWith(value)) - { - return "${jetty.base}" + path.substring(value.length()); - } - } - return path; - } - - /** - * Convenience method for toShortForm(file.getCanonicalPath()) - */ - public String toShortForm(File path) - { - try - { - return toShortForm(path.getCanonicalPath()); - } - catch (IOException ignore) - { - /* ignore */ - } - return toShortForm(path.getAbsolutePath()); - } - - /** - * Get a specific file reference. - *

- * If file exists in ${jetty.base}, return its reference, otherwise return the ${jetty.home} references. - * - * @param relPath - * the path to get. - * @return the file references. - */ - public File getFile(String relPath) - { - String rpath = separators(relPath); - - if (baseDir != null) - { - File file = new File(baseDir,rpath); - if (file.exists()) - { - return file; - } - } - return new File(homeDir,rpath); - } - public static String separators(String path) { StringBuilder ret = new StringBuilder(); @@ -140,6 +60,104 @@ public class HomeBase return ret.toString(); } + private File homeDir; + private File baseDir; + + public HomeBase() + { + String userDir = System.getProperty("user.dir"); + this.homeDir = new File(System.getProperty("jetty.home",userDir)); + String base = System.getProperty("jetty.base"); + if (base != null) + { + this.baseDir = new File(base); + } + } + + public HomeBase(File homeDir, File baseDir) + { + this.homeDir = homeDir; + this.baseDir = baseDir; + } + + public boolean hasBase() + { + return this.baseDir != null; + } + + public void setBaseDir(File dir) + { + this.baseDir = dir; + } + + public File getBaseDir() + { + return baseDir; + } + + public String getBase() + { + if (baseDir == null) + { + return null; + } + return baseDir.getAbsolutePath(); + } + + /** + * 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
  6. + *
+ * + * @param path + * the path to get. + * @return the file reference. + */ + public File getFile(String path) + { + String rpath = separators(path); + + // Relative to Base Directory First + if (baseDir != null) + { + File file = new File(baseDir,rpath); + if (file.exists()) + { + return file; + } + } + + // Then relative to Home Directory + File file = new File(homeDir,rpath); + if (file.exists()) + { + return file; + } + + // Finally, as an absolute path + return new File(rpath); + } + + public void setHomeDir(File dir) + { + this.homeDir = dir; + } + + public File getHomeDir() + { + return homeDir; + } + + public String getHome() + { + return homeDir.getAbsolutePath(); + } + /** * Get all of the files that are in a specific relative directory. *

@@ -196,11 +214,13 @@ public class HomeBase // add any remaining home files. ret.addAll(homeFiles); + Collections.sort(ret, new NaturalSort.Files()); return ret; } else { // simple return + Collections.sort(homeFiles, new NaturalSort.Files()); return homeFiles; } } @@ -209,4 +229,52 @@ public class HomeBase { return dir.toURI().relativize(path.toURI()).toASCIIString(); } + + /** + * Convenience method for toShortForm(file.getCanonicalPath()) + */ + public String toShortForm(File path) + { + try + { + return toShortForm(path.getCanonicalPath()); + } + catch (IOException ignore) + { + /* ignore */ + } + return toShortForm(path.getAbsolutePath()); + } + + /** + * 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(String path) + { + if (path == null) + { + return path; + } + + String value = homeDir.getAbsolutePath(); + + if (path.startsWith(value)) + { + return "${jetty.home}" + path.substring(value.length()); + } + + if (baseDir != null) + { + value = baseDir.getAbsolutePath(); + if (path.startsWith(value)) + { + return "${jetty.base}" + path.substring(value.length()); + } + } + return path; + } } 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 f67ab4dbedc..853c60ae7d7 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 @@ -26,7 +26,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; -import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -51,17 +50,17 @@ import java.util.Locale; import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; /*-------------------------------------------*/ /** *

- * Main start class. This class is intended to be the main class listed in the MANIFEST.MF of the start.jar archive. It - * allows an application to be started with the command "java -jar start.jar". + * Main start class. This class is intended to be the main class listed in the MANIFEST.MF of the start.jar archive. It allows an application to be started with + * the command "java -jar start.jar". *

* *

- * The behaviour of Main is controlled by the parsing of the {@link Config} "org/eclipse/start/start.config" file - * obtained as a resource or file. + * The behaviour of Main is controlled by the parsing of the {@link Config} "org/eclipse/start/start.config" file obtained as a resource or file. *

*/ public class Main @@ -78,10 +77,10 @@ public class Main private boolean _dumpVersions = false; private boolean _listConfig = false; private boolean _listOptions = false; - private boolean _noRun=false; + private boolean _noRun = false; private boolean _dryRun = false; private boolean _exec = false; - private final Config _config = new Config(); + private final Config _config; private final Set _sysProps = new HashSet<>(); private final List _jvmArgs = new ArrayList<>(); private final List _enable = new ArrayList<>(); @@ -107,40 +106,39 @@ public class Main Main() throws IOException { - String jetty_home=new File(System.getProperty("jetty.home",".")).getCanonicalPath(); - _config.setProperty("jetty.home",jetty_home); + _config = new Config(); } Config getConfig() { return _config; } - + public List processCommandLine(String[] args) throws Exception { - String source=""; - + String source = ""; + // Handle default ini args ArrayList arguments = new ArrayList<>(Arrays.asList(args)); - boolean ini=false; - for(String arg : arguments) + boolean ini = false; + for (String arg : arguments) if (arg.startsWith("--ini=") || arg.equals("--ini")) ini = true; if (!ini) arguments.add(0,"--ini=start.ini"); - + // The XML Configuration Files to initialize with List xmls = new ArrayList(); // Process the arguments in for loop so list of args can be extended. - for (int i=0;i8?arg.substring(9):arguments.get(++i); - _noRun=true; + String module = arg.length() > 8?arg.substring(9):arguments.get(++i); + _noRun = true; _enable.add(module); } if (arg.startsWith("--disable=") || arg.equals("--disable")) { - String module=arg.length()>9?arg.substring(10):arguments.get(++i); - _noRun=true; + String module = arg.length() > 9?arg.substring(10):arguments.get(++i); + _noRun = true; _disable.add(module); } - + if (arg.startsWith("--ini=") || arg.equals("--ini")) { ini = true; if (arg.length() > 6) { - String name=arg.substring(6); - File file=_config.getFileBaseHomeAbs(name); - arguments.addAll(i+1,loadStartIni(file,name)); + String name = arg.substring(6); + File file = _config.getHomeBase().getFile(name); + StartIni startini = new StartIni(file); + int idx; + while ((idx = startini.lineIndexOf(0,Pattern.compile("^.*/$"))) >= 0) + { + String subPath = startini.getLines().get(idx); + startini.getLines().remove(idx); + // find the sub ini files (based on HomeBase) + List childInis = _config.getHomeBase().listFiles(subPath,new FS.IniFilter()); + for (File childIni : childInis) + { + StartIni cini = new StartIni(childIni); + idx += startini.overlayAt(idx,cini); + } + } + arguments.addAll(i + 1,startini.getLines()); } - + continue; } - + // Alternative start.config file if (arg.startsWith("--config=")) { _startConfig = arg.substring(9); continue; } - - + // Special internal indicator that jetty was started by the jetty.sh Daemon // All this does is setup a start.log that captures startup console output // in the tiny window of time before the real logger kicks in. @@ -299,7 +309,7 @@ public class Main case 2: if ("_SRC_".equals(assign[0])) { - source=assign[1].trim(); + source = assign[1].trim(); } else if ("DEFINE".equals(assign[0])) { @@ -307,29 +317,29 @@ public class Main for (String opt : opts) _config.defineOption(opt.trim()); } - else if ("DEPEND".equals(assign[0])) + else if ("DEPEND".equals(assign[0])) { String opts[] = assign[1].split(","); for (String opt : opts) { - opt=opt.trim(); - if (!_config.getOptions().contains(opt)) + opt = opt.trim(); + if (!_config.getOptions().contains(opt)) { - System.err.printf("ERROR: Missing Dependency: %s DEPEND %s%n",path(source),opt ); - _noRun=true; + System.err.printf("ERROR: Missing Dependency: %s DEPEND %s%n",path(source),opt); + _noRun = true; } } } - else if ("EXCLUDE".equals(assign[0])) + else if ("EXCLUDE".equals(assign[0])) { String opts[] = assign[1].split(","); for (String opt : opts) { - opt=opt.trim(); - if (_config.getOptions().contains(opt)) + opt = opt.trim(); + if (_config.getOptions().contains(opt)) { - System.err.printf("ERROR: Excluded Dependency: %s EXCLUDE %s%n",path(source),opt ); - _noRun=true; + System.err.printf("ERROR: Excluded Dependency: %s EXCLUDE %s%n",path(source),opt); + _noRun = true; } } } @@ -348,7 +358,7 @@ public class Main this._config.setProperty(assign[0],assign[1]); } break; - + case 1: this._config.setProperty(assign[0],null); break; @@ -376,42 +386,42 @@ public class Main try { String[] split = arg.split(":",3); - if (split.length!=3 || "http".equalsIgnoreCase(split[0]) || !split[1].startsWith("//")) + if (split.length != 3 || "http".equalsIgnoreCase(split[0]) || !split[1].startsWith("//")) throw new IllegalArgumentException("Not --download=:"); - - String location=split[2]; - if (File.separatorChar!='/') + + String location = split[2]; + if (File.separatorChar != '/') location.replaceAll("/",File.separator); File file = new File(location); - + Config.debug("Download to %s %s",file.getAbsolutePath(),(file.exists()?"[Exists!]":"")); if (file.exists()) return; - - URL url = new URL(split[0].substring(11)+":"+split[1]); - System.err.println("DOWNLOAD: "+url+" to "+location); + URL url = new URL(split[0].substring(11) + ":" + split[1]); + + System.err.println("DOWNLOAD: " + url + " to " + location); if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); - byte[] buf=new byte[8192]; + byte[] buf = new byte[8192]; try (InputStream in = url.openStream(); OutputStream out = new FileOutputStream(file);) { - while(true) + while (true) { int len = in.read(buf); - if (len>0) + if (len > 0) out.write(buf,0,len); - if (len<0) + if (len < 0) break; } } } - catch(Exception e) + catch (Exception e) { - System.err.println("ERROR: processing "+arg+"\n"+e); + System.err.println("ERROR: processing " + arg + "\n" + e); e.printStackTrace(); usageExit(EXIT_USAGE); } @@ -457,7 +467,7 @@ public class Main } else if (info.equals("@CONFIGS")) { - FileFilter filter =new FileFilter() + FileFilter filter = new FileFilter() { public boolean accept(File path) { @@ -470,45 +480,25 @@ public class Main return (name.startsWith("jetty") && name.endsWith(".xml")); } }; - - // list home etc - File etc = new File(_config.getJettyHome(),"etc"); - if (!etc.exists() || !etc.isDirectory()) - { - System.out.print(indent); - System.out.println("Unable to find/list " + etc); - continue; - } - List configFiles = new ArrayList(); - File[] configs = etc.listFiles(filter); - configFiles.addAll(Arrays.asList(configs)); - - // list base etc - if (!_config.getJettyHome().equals(_config.getJettyBase())) - { - etc = new File(_config.getJettyBase(),"etc"); - if (etc.exists() && etc.isDirectory()) - { - configs = etc.listFiles(filter); - configFiles.addAll(Arrays.asList(configs)); - } - } - - Collections.sort(configFiles); + + // list etc + List configFiles = _config.getHomeBase().listFiles("etc",filter); for (File configFile : configFiles) + { System.out.printf("%s%s%n",indent,path(configFile)); + } } else if (info.equals("@STARTINI")) { for (File file : _iniFiles) { - String path=path(file); + String path = path(file); System.out.printf("%s%s%n",indent,path); if (Config.isDebug()) { - try (FileReader reader=new FileReader(file); BufferedReader in = new BufferedReader(reader);) + try (FileReader reader = new FileReader(file); BufferedReader in = new BufferedReader(reader);) { String arg; while ((arg = in.readLine()) != null) @@ -540,45 +530,16 @@ public class Main System.exit(EXIT_USAGE); } - /** - * 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 - */ private String path(String path) { - if (path == null) - { - return path; - } - if (path.startsWith(_config.getJettyHome())) - { - return "${jetty.home}" + path.substring(_config.getJettyHome().length()); - } - if (_config.getJettyBase() != null && path.startsWith(_config.getJettyBase())) - { - return "${jetty.base}" + path.substring(_config.getJettyBase().length()); - } - return path; + return _config.getHomeBase().toShortForm(path); } - - /** - * Convenience method for path(file.getCanonicalPath()) - */ - private String path(File file) + + private String path(File file) { - try - { - return path(file.getCanonicalPath()); - } - catch (IOException e) - { - } - return path(file.getAbsolutePath()); + return _config.getHomeBase().toShortForm(file); } - + public void invokeMain(ClassLoader classloader, String classname, List args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { @@ -622,24 +583,11 @@ public class Main main.invoke(null,method_params); } - /* ------------------------------------------------------------ */ public static void close(Closeable c) { - if (c == null) - { - return; - } - try - { - c.close(); - } - catch (IOException e) - { - e.printStackTrace(System.err); - } + FS.close(c); } - /* ------------------------------------------------------------ */ public void start(List xmls) throws IOException, InterruptedException { // Load potential Config (start.config) @@ -676,7 +624,7 @@ public class Main enable(m); for (String m : _disable) disable(m); - + // Show the usage information and return if (_showUsage) usage(); @@ -698,7 +646,7 @@ public class Main CommandLineBuilder cmd = buildCommandLine(classpath,configuredXmls); System.out.println(cmd.toString()); } - + // Informational command line, don't run jetty if (_noRun) return; @@ -793,26 +741,25 @@ public class Main private String resolveXmlConfig(String xmlFilename) throws FileNotFoundException { - if (!xmlFilename.toLowerCase(Locale.ENGLISH).endsWith(".xml")) + if (!FS.isXml(xmlFilename)) { // Nothing to resolve. return xmlFilename; } - // Look for the file as absolute, jetty-base or jetty-home - File xml = _config.getFileBaseHomeAbs(xmlFilename); - if (xml!=null && xml.isFile()) + // Try normal locations + File xml = _config.getHomeBase().getFile(xmlFilename); + if (FS.isFile(xml)) + { return xml.getAbsolutePath(); - - // Try corrected / for \ - xml = _config.getFileBaseHomeAbs(fixPath(xmlFilename)); - if (xml!=null && xml.isFile()) - return xml.getAbsolutePath(); - - // Try in etc - xml = _config.getFileBaseHomeAbs("etc/"+xmlFilename); - if (xml!=null && xml.isFile()) + } + + // Try again, but prefixed with "etc/" + xml = _config.getHomeBase().getFile("etc/" + xmlFilename); + if (FS.isFile(xml)) + { return xml.getAbsolutePath(); + } throw new FileNotFoundException("Unable to find XML Config: " + xmlFilename); } @@ -825,9 +772,11 @@ public class Main { cmd.addArg(x); } - cmd.addRawArg("-Djetty.home=" + _config.getJettyHome()); - if (_config.getJettyBase()!=null) - cmd.addRawArg("-Djetty.base=" + _config.getJettyBase()); + cmd.addRawArg("-Djetty.home=" + _config.getHomeBase().getHome()); + if (_config.getHomeBase().hasBase()) + { + cmd.addRawArg("-Djetty.base=" + _config.getHomeBase().getBase()); + } // Special Stop/Shutdown properties ensureSystemPropertySet("STOP.PORT"); @@ -857,14 +806,13 @@ public class Main for (String xml : xmls) { - cmd.addRawArg(xml); + cmd.addRawArg(xml); } return cmd; } /** - * Ensure that the System Properties are set (if defined as a System property, or start.config property, or - * start.ini property) + * Ensure that the System Properties are set (if defined as a System property, or start.config property, or start.ini property) * * @param key * the key to be sure of @@ -950,8 +898,13 @@ public class Main System.out.println("Note: If using multiple options (eg: 'Server,servlet,webapp,jms,jmx') " + "then overlapping entries will not be repeated in the eventual classpath."); System.out.println(); - System.out.printf("${jetty.home} = %s%n",_config.getJettyHome()); - System.out.printf("${jetty.base} = %s%n",_config.getJettyBase()); + System.out.printf("${jetty.home} = %s%n",_config.getHomeBase().getHome()); + String base = ""; + if (_config.getHomeBase().hasBase()) + { + base = _config.getHomeBase().getBase(); + } + System.out.printf("${jetty.base} = %s%n",base); System.out.println(); for (String sectionId : sectionIds) @@ -1014,11 +967,6 @@ public class Main System.out.printf("%2d: %20s | %s\n",i++,getVersion(element),path(element)); } - private String fixPath(String path) - { - return path.replace('/',File.separatorChar); - } - private String getVersion(File element) { if (element.isDirectory()) @@ -1079,8 +1027,8 @@ public class Main /** * Load Configuration. * - * No specific configuration is real until a {@link Config#getCombinedClasspath(java.util.Collection)} is used to - * execute the {@link Class} specified by {@link Config#getMainClassname()} is executed. + * No specific configuration is real until a {@link Config#getCombinedClasspath(java.util.Collection)} is used to execute the {@link Class} specified by + * {@link Config#getMainClassname()} is executed. * * @param xmls * the command line specified xml configuration options. @@ -1228,114 +1176,32 @@ public class Main static void usageExit(int exit) { - usageExit(null, exit); - } - - /** - * Convert a start.ini format file into an argument list. - */ - private List loadStartIni(File ini,String name) - { - if (ini==null || !ini.exists() || ini.isDirectory() || !ini.canRead()) - { - System.err.println("Warning - bad ini file: " + name); - // No start.ini found, skip load. - return Collections.emptyList(); - } - - ini=ini.getAbsoluteFile(); - if (!_iniFiles.contains(ini)) - _iniFiles.add(ini); - List args = new ArrayList(); - - args.add("_SRC_="+name); - - FileReader reader = null; - BufferedReader buf = null; - try - { - reader = new FileReader(ini); - buf = new BufferedReader(reader); - - String arg; - while ((arg = buf.readLine()) != null) - { - arg = arg.trim(); - if (arg.length() == 0 || arg.startsWith("#")) - { - continue; - } - - if (arg.endsWith("/")) - { - try - { - File start_d = _config.getFileBaseHomeAbs(arg); - if (start_d!=null && start_d.isDirectory()) - { - _iniDirs.add(start_d); - File[] inis = start_d.listFiles(new FilenameFilter() - { - @Override - public boolean accept(File dir, String name) - { - return name.toLowerCase(Locale.ENGLISH).endsWith(".ini"); - } - }); - Arrays.sort(inis); - - for (File i : inis) - args.addAll(loadStartIni(i,i.getAbsolutePath())); - - args.add("_SRC_="+name); - continue; - } - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - args.add(arg); - } - } - catch (IOException e) - { - usageExit(e,ERR_UNKNOWN); - } - finally - { - Main.close(buf); - Main.close(reader); - } - - return args; + usageExit(null,exit); } void addJvmArgs(List jvmArgs) { _jvmArgs.addAll(jvmArgs); } - + private void enable(final String module) { - final String mini=module+".ini"; - final String disable=module+".ini.disabled"; - final AtomicBoolean found=new AtomicBoolean(false); - FileFilter filter =new FileFilter() + final String mini = module + ".ini"; + final String disable = module + ".ini.disabled"; + final AtomicBoolean found = new AtomicBoolean(false); + FileFilter filter = new FileFilter() { public boolean accept(File path) { if (!path.isFile()) return false; - String n=path.getName(); - int i=n.indexOf(mini); - if (i<0) + String n = path.getName(); + int i = n.indexOf(mini); + if (i < 0) return false; - if (i>0 && i!=4 && n.charAt(i-1)!='-') + if (i > 0 && i != 4 && n.charAt(i - 1) != '-') return false; - + found.set(true); if (n.endsWith(mini)) { @@ -1343,41 +1209,41 @@ public class Main } else if (n.endsWith(disable)) { - String enabled=n.substring(0,n.length()-9); + String enabled = n.substring(0,n.length() - 9); System.err.printf("Enable %s in %s as %s%n",module,path(path.getParent()),enabled); path.renameTo(new File(path.getParentFile(),enabled)); } - else + else System.err.printf("Bad module %s in %s as %s%n",module,path(path.getParent()),n); - + return false; } }; - + for (File dir : _iniDirs) dir.listFiles(filter); - + if (!found.get()) for (File dir : _iniDirs) System.err.printf("Module %s not found in %s%n",module,path(dir)); } - + private void disable(final String module) { - final String mini=module+".ini"; - final String disable=module+".ini.disabled"; - final AtomicBoolean found=new AtomicBoolean(false); - FileFilter filter =new FileFilter() + final String mini = module + ".ini"; + final String disable = module + ".ini.disabled"; + final AtomicBoolean found = new AtomicBoolean(false); + FileFilter filter = new FileFilter() { public boolean accept(File path) { if (!path.isFile()) return false; - String n=path.getName(); - int i=n.indexOf(mini); - if (i<0) + String n = path.getName(); + int i = n.indexOf(mini); + if (i < 0) return false; - if (i>0 && i!=4 && n.charAt(i-1)!='-') + if (i > 0 && i != 4 && n.charAt(i - 1) != '-') return false; found.set(true); @@ -1387,20 +1253,20 @@ public class Main } else if (n.endsWith(mini)) { - String disabled=n+".disabled"; + String disabled = n + ".disabled"; System.err.printf("Disable %s in %s as %s%n",module,path(path.getParent()),disabled); path.renameTo(new File(path.getParentFile(),disabled)); } - else + else System.err.printf("Bad module %s in %s as %s%n",module,path(path.getParent()),n); - + return false; } }; - + for (File dir : _iniDirs) dir.listFiles(filter); - + if (!found.get()) for (File dir : _iniDirs) System.err.printf("Module %s not found in %s%n",module,path(dir)); diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/NaturalSort.java b/jetty-start/src/main/java/org/eclipse/jetty/start/NaturalSort.java new file mode 100644 index 00000000000..dc72712af2a --- /dev/null +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/NaturalSort.java @@ -0,0 +1,56 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.text.CollationKey; +import java.text.Collator; +import java.util.Comparator; + +/** + * Natural Language Sorting + */ +public class NaturalSort +{ + public static class Strings implements Comparator + { + private final Collator collator = Collator.getInstance(); + + @Override + public int compare(String o1, String o2) + { + CollationKey key1 = collator.getCollationKey(o1); + CollationKey key2 = collator.getCollationKey(o2); + return key1.compareTo(key2); + } + } + + public static class Files implements Comparator + { + private final Collator collator = Collator.getInstance(); + + @Override + public int compare(File o1, File o2) + { + CollationKey key1 = collator.getCollationKey(o1.getAbsolutePath()); + CollationKey key2 = collator.getCollationKey(o2.getAbsolutePath()); + return key1.compareTo(key2); + } + } +} 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 new file mode 100644 index 00000000000..ab4c477191c --- /dev/null +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java @@ -0,0 +1,149 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Simple Start .INI handler + */ +public class StartIni implements Iterable +{ + private final File file; + private final LinkedList lines; + + public StartIni(File file) throws FileNotFoundException, IOException + { + this.file = file; + this.lines = new LinkedList<>(); + try (FileReader reader = new FileReader(file)) + { + try (BufferedReader buf = new BufferedReader(reader)) + { + String line; + while ((line = buf.readLine()) != null) + { + line = line.trim(); + if (line.length() == 0) + { + // skip (empty line) + continue; + } + if (line.charAt(0) == '#') + { + // skip (comment) + continue; + } + + // Smart Handling, split into multiple OPTIONS lines + if (line.startsWith("OPTIONS=")) + { + for (String part : line.split(",")) + { + lines.add("OPTIONS=" + part); + } + } + else + { + // Add line as-is + lines.add(line); + } + } + } + } + } + + public File getFile() + { + return file; + } + + public int lineIndexOf(int offset, Pattern pattern) + { + int len = lines.size(); + for (int i = offset; i < len; i++) + { + if (pattern.matcher(lines.get(i)).matches()) + { + return i; + } + } + return -1; + } + + public List getLineMatches(Pattern pattern) + { + List ret = new ArrayList<>(); + for (String line : lines) + { + if (pattern.matcher(line).matches()) + { + ret.add(line); + } + } + return ret; + } + + public List getLines() + { + return lines; + } + + @Override + public Iterator iterator() + { + return lines.iterator(); + } + + public int overlayAt(int index, StartIni child) + { + int idx = index; + int count = 0; + for (String line : child) + { + if (this.hasLine(line)) + { + // skip + continue; + } + lines.add(idx++,line); + count++; + } + return count; + } + + private boolean hasLine(String line) + { + return lines.contains(line); + } + + public void removeLine(String line) + { + lines.remove(line); + } +} diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/HomeBaseTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/HomeBaseTest.java index 5df9f12ea5f..2785a83cce3 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/HomeBaseTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/HomeBaseTest.java @@ -77,6 +77,25 @@ public class HomeBaseTest assertFileList(hb,"Files found",expected,files); } + @Test + public void testListFiles_Filtered_OnlyHome() throws IOException + { + File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); + File baseDir = null; + + HomeBase hb = new HomeBase(homeDir,baseDir); + List files = hb.listFiles("/start.d", new FS.IniFilter()); + + List expected = new ArrayList<>(); + expected.add("${jetty.home}/start.d/jmx.ini"); + expected.add("${jetty.home}/start.d/jndi.ini"); + expected.add("${jetty.home}/start.d/jsp.ini"); + expected.add("${jetty.home}/start.d/logging.ini"); + expected.add("${jetty.home}/start.d/ssl.ini"); + + assertFileList(hb,"Files found",expected,files); + } + @Test public void testListFiles_Both() throws IOException { @@ -96,7 +115,7 @@ public class HomeBaseTest assertFileList(hb,"Files found",expected,files); } - + @Test public void testGetFile_Both() throws IOException { diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java index c4243260afe..69a5c6c5552 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java @@ -18,12 +18,8 @@ package org.eclipse.jetty.start; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.io.File; import java.io.IOException; @@ -35,6 +31,7 @@ import java.util.Vector; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -59,11 +56,17 @@ public class MainTest { Main main = new Main(); List xmls = main.processCommandLine(new String[] {}); - - assertEquals("etc/jetty.xml",xmls.get(0)); - assertEquals("etc/jetty-jmx.xml",xmls.get(1)); - assertEquals("start.d","etc/jetty-testrealm.xml",xmls.get(2)); - assertEquals("start.d","etc/jetty-contexts.xml",xmls.get(5)); + + List expectedXmls = new ArrayList(); + expectedXmls.add("etc/jetty.xml"); // from start.ini + expectedXmls.add("etc/jetty-jmx.xml"); // from start.d/10-jmx.ini + // nothing from start.d/20-websocket.xml + expectedXmls.add("etc/jetty-testrealm.xml"); // from start.d/90-testrealm.ini + expectedXmls.add("etc/jetty-deploy.xml"); // from start.ini + expectedXmls.add("etc/jetty-webapps.xml"); // from start.ini + expectedXmls.add("etc/jetty-contexts.xml"); // from start.ini + + Assert.assertThat("XML Resolution Order "+xmls, xmls, contains(expectedXmls.toArray())); Set options = main.getConfig().getOptions(); assertThat(options,Matchers.contains("Server","ext","jmx","jsp","newOption","resources","websocket")); diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java index 9275957109d..a5a1f9972cd 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java @@ -190,6 +190,8 @@ public class PropertyPassingTest System.out.println("Command line: " + cline); ProcessBuilder builder = new ProcessBuilder(commands); + // Set PWD + builder.directory(MavenTestingUtils.getTestResourceDir("empty.home")); Process pid = builder.start(); ConsoleCapture stdOutPump = new ConsoleCapture("STDOUT",pid.getInputStream()).start(); diff --git a/jetty-start/src/test/resources/empty.home/start.ini b/jetty-start/src/test/resources/empty.home/start.ini new file mode 100644 index 00000000000..e751e99807d --- /dev/null +++ b/jetty-start/src/test/resources/empty.home/start.ini @@ -0,0 +1,3 @@ +#=========================================================== +# Empty start.ini +#===========================================================