451973 - Ambiguous module init location when mixing --add-to-start & --add-to-startd in the same exec

+ Cleaning up entire base buildout into BaseBuilder class
+ The management of the configuration is maintained in
  - StartDirBuilder
  - StartIniBuilder
+ The buildout of the directories from the [files] section is now
  maintained by the BaseBuilder itself.
+ Using new FileInitializer system as well
+ Using new Licensing system as well
This commit is contained in:
Joakim Erdfelt 2014-11-17 13:21:01 -07:00
parent 61e480c2c1
commit dbf6f2e644
14 changed files with 1024 additions and 586 deletions

View File

@ -0,0 +1,365 @@
//
// ========================================================================
// 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.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.start.Modules.AndMatcher;
import org.eclipse.jetty.start.Modules.EnabledMatcher;
import org.eclipse.jetty.start.Modules.Matcher;
import org.eclipse.jetty.start.Modules.SourceSetMatcher;
import org.eclipse.jetty.start.Modules.UniqueSourceMatcher;
import org.eclipse.jetty.start.builders.StartDirBuilder;
import org.eclipse.jetty.start.builders.StartIniBuilder;
import org.eclipse.jetty.start.fileinits.MavenLocalRepoFileInitializer;
import org.eclipse.jetty.start.fileinits.TestFileInitializer;
import org.eclipse.jetty.start.fileinits.UriFileInitializer;
/**
* Build a start configuration in <code>${jetty.base}</code>, including
* ini files, directories, and libs. Also handles License management.
*/
public class BaseBuilder
{
public static interface Config
{
/**
* Add a module to the start environment in <code>${jetty.base}</code>
*
* @param module
* the module to add
* @return true if module was added, false if module was not added
* (because that module already exists)
* @throws IOException
*/
public boolean addModule(Module module) throws IOException;
}
private static final String EXITING_LICENSE_NOT_ACKNOWLEDGED = "Exiting: license not acknowledged!";
private final BaseHome baseHome;
private final List<FileInitializer> fileInitializers;
private final StartArgs startArgs;
public BaseBuilder(BaseHome baseHome, StartArgs args)
{
this.baseHome = baseHome;
this.startArgs = args;
this.fileInitializers = new ArrayList<>();
// Establish FileInitializers
if (args.isTestingModeEnabled())
{
// No downloads performed
fileInitializers.add(new TestFileInitializer());
}
else if (args.isDownload())
{
// Downloads are allowed to be performed
// Setup Maven Local Repo
Path localRepoDir = args.getMavenLocalRepoDir();
if (localRepoDir != null)
{
// Use provided local repo directory
fileInitializers.add(new MavenLocalRepoFileInitializer(baseHome,localRepoDir));
}
else
{
// No no local repo directory (direct downloads)
fileInitializers.add(new MavenLocalRepoFileInitializer(baseHome));
}
// Normal URL downloads
fileInitializers.add(new UriFileInitializer(baseHome));
}
}
private void ackLicenses() throws IOException
{
if (startArgs.isLicenseCheckRequired())
{
if (startArgs.isApproveAllLicenses())
{
StartLog.info("All Licenses Approved via Command Line Option");
}
else
{
Licensing licensing = new Licensing();
for (Module module : startArgs.getAllModules().getEnabled())
{
licensing.addModule(module);
}
if (licensing.hasLicenses())
{
StartLog.debug("Requesting License Acknowledgement");
if (!licensing.acknowledgeLicenses())
{
StartLog.warn(EXITING_LICENSE_NOT_ACKNOWLEDGED);
System.exit(1);
}
}
}
}
}
/**
* Build out the Base directory (if needed)
*
* @return true if base directory was changed, false if left unchanged.
* @throws IOException
*/
public boolean build() throws IOException
{
Modules modules = startArgs.getAllModules();
boolean dirty = false;
String dirSource = "<add-to-startd>";
String iniSource = "<add-to-start-ini>";
int count = 0;
count += modules.enableAll(startArgs.getAddToStartdIni(),dirSource);
count += modules.enableAll(startArgs.getAddToStartIni(),iniSource);
Matcher startDMatcher = new AndMatcher(new EnabledMatcher(),new UniqueSourceMatcher(dirSource));
Matcher startIniMatcher = new AndMatcher(new EnabledMatcher(),new UniqueSourceMatcher(iniSource));
// look for ambiguous declaration in 2 places
Matcher ambiguousMatcher = new AndMatcher(new EnabledMatcher(),new SourceSetMatcher(dirSource,iniSource));
List<Module> ambiguous = modules.getMatching(ambiguousMatcher);
if (ambiguous.size() > 0)
{
StringBuilder err = new StringBuilder();
err.append("Unable to add ");
err.append(ambiguous.size());
err.append(" module");
if (ambiguous.size() > 1)
{
err.append('s');
}
err.append(" (found declared via both --add-to-start and --add-to-startd): [");
for (int i = 0; i < ambiguous.size(); i++)
{
if (i > 0)
{
err.append(", ");
}
err.append(ambiguous.get(i).getName());
}
err.append(']');
throw new RuntimeException(err.toString());
}
StartLog.debug("Adding %s new module(s)",count);
// Acknowledge Licenses
ackLicenses();
// Collect specific modules to enable
List<Module> startDModules = modules.getMatching(startDMatcher);
List<Module> startIniModules = modules.getMatching(startIniMatcher);
List<FileArg> files = new ArrayList<FileArg>();
if (!startDModules.isEmpty())
{
StartDirBuilder builder = new StartDirBuilder(this);
for (Module mod : startDModules)
{
dirty |= builder.addModule(mod);
for (String file : mod.getFiles())
{
files.add(new FileArg(mod,file));
}
}
}
if (!startIniModules.isEmpty())
{
StartIniBuilder builder = new StartIniBuilder(this);
for (Module mod : startIniModules)
{
dirty |= builder.addModule(mod);
for (String file : mod.getFiles())
{
files.add(new FileArg(mod,file));
}
}
}
// Process files
files.addAll(startArgs.getFiles());
dirty |= processFileResources(files);
return dirty;
}
public BaseHome getBaseHome()
{
return baseHome;
}
public StartArgs getStartArgs()
{
return startArgs;
}
/**
* Process a specific file resource
*
* @param arg
* the fileArg to work with
* @param file
* the resolved file reference to work with
* @return true if change was made as a result of the file, false if no change made.
* @throws IOException
* if there was an issue in processing this file
*/
private boolean processFileResource(FileArg arg, Path file) throws IOException
{
if (startArgs.isDownload() && (arg.uri != null))
{
URI uri = URI.create(arg.uri);
// Process via initializers
for (FileInitializer finit : fileInitializers)
{
if (finit.init(uri,file))
{
// Completed successfully
return true;
}
}
return false;
}
else
{
// Process directly
boolean isDir = arg.location.endsWith("/");
if (FS.exists(file))
{
// Validate existence
if (isDir)
{
if (!Files.isDirectory(file))
{
throw new IOException("Invalid: path should be a directory (but isn't): " + file);
}
if (!FS.canReadDirectory(file))
{
throw new IOException("Unable to read directory: " + file);
}
}
else
{
if (!FS.canReadFile(file))
{
throw new IOException("Unable to read file: " + file);
}
}
return false;
}
if (isDir)
{
// Create directory
StartLog.log("MKDIR",baseHome.toShortForm(file));
return FS.ensureDirectoryExists(file);
}
else
{
// Warn on missing file (this has to be resolved manually by user)
String shortRef = baseHome.toShortForm(file);
if (startArgs.isTestingModeEnabled())
{
StartLog.log("TESTING MODE","Skipping required file check on: %s",shortRef);
return true;
}
StartLog.warn("Missing Required File: %s",baseHome.toShortForm(file));
startArgs.setRun(false);
if (arg.uri != null)
{
StartLog.warn(" Can be downloaded From: %s",arg.uri);
StartLog.warn(" Run start.jar --create-files to download");
}
return true;
}
}
}
/**
* Process the {@link FileArg} for startup, assume that all licenses have
* been acknowledged at this stage.
*
* @param files
* the list of {@link FileArg}s to process
* @return true if base directory modified, false if left untouched
*/
private boolean processFileResources(List<FileArg> files) throws IOException
{
if ((files == null) || (files.isEmpty()))
{
return false;
}
boolean dirty = false;
List<String> failures = new ArrayList<String>();
for (FileArg arg : files)
{
Path file = baseHome.getBasePath(arg.location);
try
{
dirty |= processFileResource(arg,file);
}
catch (Throwable t)
{
StartLog.warn(t);
failures.add(String.format("[%s] %s - %s",t.getClass().getSimpleName(),t.getMessage(),file.toAbsolutePath().toString()));
}
}
if (!failures.isEmpty())
{
StringBuilder err = new StringBuilder();
err.append("Failed to process all file resources.");
for (String failure : failures)
{
err.append(System.lineSeparator()).append(" - ").append(failure);
}
StartLog.warn(err.toString());
throw new RuntimeException(err.toString());
}
return dirty;
}
}

View File

@ -67,14 +67,15 @@ public class FS
return Files.exists(ret);
}
public static void ensureDirectoryExists(Path dir) throws IOException
public static boolean ensureDirectoryExists(Path dir) throws IOException
{
if (exists(dir))
{
// exists already, nothing to do
return;
return false;
}
Files.createDirectories(dir);
return true;
}
public static void ensureDirectoryWritable(Path dir) throws IOException

View File

@ -34,8 +34,8 @@ public interface FileInitializer
* the remote URI of the resource acting as its source
* @param file
* the local file resource to initialize
* @return true if local file is initialized, false if this
* {@link FileInitializer} skipped this attempt.
* @return true if local file is initialized (resulted in a change on disk), false if this
* {@link FileInitializer} did nothing.
* @throws IOException
* if there was an attempt to initialize, but an error occurred.
*/

View File

@ -21,37 +21,23 @@ 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.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URI;
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.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;
import org.eclipse.jetty.start.config.CommandLineConfigSource;
import org.eclipse.jetty.start.fileinits.MavenLocalRepoFileInitializer;
import org.eclipse.jetty.start.fileinits.TestFileInitializer;
import org.eclipse.jetty.start.fileinits.UriFileInitializer;
/**
* Main start class.
@ -82,7 +68,6 @@ import org.eclipse.jetty.start.fileinits.UriFileInitializer;
*/
public class Main
{
private static final String EXITING_LICENSE_NOT_ACKNOWLEDGED = "Exiting: license not acknowledged!";
private static final int EXIT_USAGE = 1;
public static void main(String[] args)
@ -272,222 +257,6 @@ public class Main
modules.dumpEnabledTree();
}
/**
* Build out INI file.
* <p>
* This applies equally for either <code>${jetty.base}/start.ini</code> or
* <code>${jetty.base}/start.d/${name}.ini</code>
*
* @param fileInitializers the configured initializers
* @param args the arguments of what modules are enabled
* @param name the name of the module to based the build of the ini
* @param topLevel
* @param appendStartIni true to append to <code>${jetty.base}/start.ini</code>,
* false to create a <code>${jetty.base}/start.d/${name}.ini</code> entry instead.
* @throws IOException
*/
private void buildIni(List<FileInitializer> fileInitializers, StartArgs args, String name, boolean topLevel, boolean appendStartIni) throws IOException
{
// Find the start.d relative to the base directory only.
Path start_d = baseHome.getBasePath("start.d");
// Is this a module?
Modules modules = args.getAllModules();
Module module = modules.get(name);
if (module == null)
{
StartLog.warn("ERROR: No known module for %s",name);
return;
}
boolean transitive = module.isEnabled() && (module.getSources().size() == 0);
// Find any named ini file and check it follows the convention
Path start_ini = baseHome.getBasePath("start.ini");
String short_start_ini = baseHome.toShortForm(start_ini);
Path startd_ini = start_d.resolve(name + ".ini");
String short_startd_ini = baseHome.toShortForm(startd_ini);
StartIni module_ini = null;
if (FS.exists(startd_ini))
{
module_ini = new StartIni(startd_ini);
if (module_ini.getLineMatches(Pattern.compile("--module=(.*, *)*" + name)).size() == 0)
{
StartLog.warn("ERROR: %s is not enabled in %s!",name,short_startd_ini);
return;
}
}
if (!args.isApproveAllLicenses())
{
if (!module.acknowledgeLicense())
{
StartLog.warn(EXITING_LICENSE_NOT_ACKNOWLEDGED);
System.exit(1);
}
}
boolean buildIni=false;
if (module.isEnabled())
{
// is it an explicit request to create an ini file?
if (topLevel && !FS.exists(startd_ini) && !appendStartIni)
{
buildIni=true;
}
// else is it transitive
else if (transitive)
{
if (module.hasDefaultConfig())
{
buildIni = true;
StartLog.info("%-15s initialised transitively",name);
}
}
// else must be initialized explicitly
else
{
for (String source : module.getSources())
{
StartLog.info("%-15s initialised in %s",name,baseHome.toShortForm(source));
}
}
}
else
{
buildIni=true;
}
String source = "<transitive>";
// If we need an ini
if (buildIni)
{
// File BufferedWriter
BufferedWriter writer = null;
PrintWriter out = null;
try
{
if (appendStartIni)
{
source = short_start_ini;
StartLog.info("%-15s initialised in %s (appended)",name,source);
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);
source = short_startd_ini;
StartLog.info("%-15s initialised in %s (created)",name,source);
writer = Files.newBufferedWriter(startd_ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE);
out = new PrintWriter(writer);
}
if (appendStartIni)
{
out.println();
}
out.println("# --------------------------------------- ");
out.println("# Module: " + name);
out.println("--module=" + name);
args.parse("--module=" + name,source);
args.parseModule(module);
for (String line : module.getDefaultConfig())
{
out.println(line);
}
}
finally
{
if (out != null)
{
out.close();
}
}
}
modules.enable(name,Collections.singletonList(source));
// Also list other places this module is enabled
for (String src : module.getSources())
{
StartLog.debug("also enabled in: %s",src);
if (!short_start_ini.equals(src))
{
StartLog.info("%-15s enabled in %s",name,baseHome.toShortForm(src));
}
}
// Do downloads now
List<FileArg> files = new ArrayList<FileArg>();
for (String file : module.getFiles())
{
files.add(new FileArg(module,file));
}
processFileResources(fileInitializers,args,files);
// Process dependencies
module.expandProperties(args.getProperties());
modules.registerParentsIfMissing(module);
modules.buildGraph();
// process new ini modules
if (topLevel)
{
List<Module> depends = new ArrayList<>();
for (String depend : modules.resolveParentModulesOf(name))
{
if (!name.equals(depend))
{
Module m = modules.get(depend);
m.setEnabled(true);
depends.add(m);
}
}
Collections.sort(depends,Collections.reverseOrder(new Module.DepthComparator()));
Set<String> done = new HashSet<>(0);
while (true)
{
// initialize known dependencies
boolean complete=true;
for (Module m : depends)
{
if (!done.contains(m.getName()))
{
complete=false;
buildIni(fileInitializers,args,m.getName(),false,appendStartIni);
done.add(m.getName());
}
}
if (complete)
{
break;
}
// look for any new ones resolved via expansion
depends.clear();
for (String depend : modules.resolveParentModulesOf(name))
{
if (!name.equals(depend))
{
Module m = modules.get(depend);
m.setEnabled(true);
depends.add(m);
}
}
Collections.sort(depends,Collections.reverseOrder(new Module.DepthComparator()));
}
}
}
/**
* Convenience for <code>processCommandLine(cmdLine.toArray(new String[cmdLine.size()]))</code>
*/
@ -534,7 +303,8 @@ public class Main
modules.buildGraph();
args.setAllModules(modules);
List<Module> activeModules = modules.resolveEnabled();
List<Module> activeModules = modules.getEnabled();
modules.assertModulesValid(activeModules);
// ------------------------------------------------------------
// 5) Lib & XML Expansion / Resolution
@ -552,139 +322,6 @@ public class Main
return args;
}
/**
* Process the {@link FileArg} for startup, assume that all licenses have
* been acknowledged at this stage.
*
* @param fileInitializers the file initializer mechanisms.
* @param args the start arguments
*/
private void processFileResources(List<FileInitializer> fileInitializers, StartArgs args) throws IOException
{
processFileResources(fileInitializers,args,args.getFiles());
}
/**
* Process the {@link FileArg} for startup, assume that all licenses have
* been acknowledged at this stage.
*
* @param fileInitializers the file initializer mechanisms.
* @param args the start arguments
* @param files the list of {@link FileArg}s to process
*/
private void processFileResources(List<FileInitializer> fileInitializers, StartArgs args, List<FileArg> files) throws IOException
{
List<String> failures = new ArrayList<String>();
for (FileArg arg : files)
{
Path file = baseHome.getBasePath(arg.location);
try
{
if (!processFileResource(fileInitializers,args,arg,file))
{
failures.add(String.format("[GenericError] %s",file.toAbsolutePath().toString()));
}
}
catch (Throwable t)
{
StartLog.warn(t);
failures.add(String.format("[%s] %s - %s",t.getClass().getSimpleName(),t.getMessage(),file.toAbsolutePath().toString()));
}
}
if (failures.isEmpty())
{
return;
}
StartLog.warn("Failed to process all file resources.");
for (String failure : failures)
{
StartLog.warn(" - %s",failure);
}
}
private boolean processFileResource(List<FileInitializer> fileInitializers, StartArgs args, FileArg arg, Path file) throws IOException
{
if (args.isDownload() && arg.uri != null)
{
URI uri = URI.create(arg.uri);
// Process via initializers
for (FileInitializer finit : fileInitializers)
{
if (finit.init(uri,file))
{
// Completed successfully
return true;
}
}
return false;
}
else
{
// Process directly
boolean isDir = arg.location.endsWith("/");
if (FS.exists(file))
{
// Validate existence
if (isDir)
{
if (!Files.isDirectory(file))
{
throw new IOException("Invalid: path should be a directory (but isn't): " + file);
}
if (!FS.canReadDirectory(file))
{
throw new IOException("Unable to read directory: " + file);
}
}
else
{
if (!FS.canReadFile(file))
{
throw new IOException("Unable to read file: " + file);
}
}
return true;
}
if (isDir)
{
// Create directory
StartLog.log("MKDIR",baseHome.toShortForm(file));
FS.ensureDirectoryExists(file);
return true;
}
else
{
// Warn on missing file (this has to be resolved manually by
// user)
String shortRef = baseHome.toShortForm(file);
if (args.isTestingModeEnabled())
{
StartLog.log("TESTING MODE","Skipping required file check on: %s",shortRef);
return true;
}
StartLog.warn("Missing Required File: %s",baseHome.toShortForm(file));
args.setRun(false);
if (arg.uri != null)
{
StartLog.warn(" Can be downloaded From: %s",arg.uri);
StartLog.warn(" Run start.jar --create-files to download");
}
return false;
}
}
}
public void start(StartArgs args) throws IOException, InterruptedException
{
StartLog.debug("StartArgs: %s",args);
@ -740,74 +377,13 @@ public class Main
doStop(args);
}
// Establish FileInitializers
List<FileInitializer> fileInitializers = new ArrayList<FileInitializer>();
if (args.isTestingModeEnabled())
BaseBuilder baseBuilder = new BaseBuilder(baseHome,args);
if(baseBuilder.build())
{
// No downloads performed
fileInitializers.add(new TestFileInitializer());
// base directory changed.
StartLog.info("Base directory was modified");
return;
}
else
{
// Downloads are allowed to be performed
// Setup Maven Local Repo
Path localRepoDir = args.getMavenLocalRepoDir();
if (localRepoDir != null)
{
// Use provided local repo directory
fileInitializers.add(new MavenLocalRepoFileInitializer(localRepoDir));
}
else
{
// No no local repo directory (direct downloads)
fileInitializers.add(new MavenLocalRepoFileInitializer());
}
// Normal URL downloads
fileInitializers.add(new UriFileInitializer());
}
boolean rebuildGraph = false;
// Initialize start.ini
for (String module : args.getAddToStartIni())
{
buildIni(fileInitializers,args,module,true,true);
rebuildGraph = true;
}
// Initialize start.d
for (String module : args.getAddToStartdIni())
{
buildIni(fileInitializers,args,module,true,false);
rebuildGraph = true;
}
if (rebuildGraph)
{
args.getAllModules().clearMissing();
args.getAllModules().buildGraph();
}
// If in --create-files, check licenses
if(args.isDownload())
{
if (!args.isApproveAllLicenses())
{
StartLog.debug("Requesting License Acknowledgement");
for (Module module : args.getAllModules().resolveEnabled())
{
if (!module.acknowledgeLicense())
{
StartLog.warn(EXITING_LICENSE_NOT_ACKNOWLEDGED);
System.exit(1);
}
}
}
}
processFileResources(fileInitializers, args);
// Informational command line, don't run jetty
if (!args.isRun())
@ -860,8 +436,6 @@ public class Main
}
}
private void doStop(StartArgs args)
{
int stopPort = Integer.parseInt(args.getProperties().getString("STOP.PORT"));

View File

@ -108,7 +108,7 @@ public class Module
/** License lines */
private List<String> license;
/** Is this Module enabled via start.jar command line, start.ini, or start.d/*.ini ? */
/** Is this Module enabled via start.jar command line, start.ini, or start.d/*.ini */
private boolean enabled = false;
/** List of sources that enabled this module */
private final Set<String> sources = new HashSet<>();
@ -272,6 +272,29 @@ public class Module
{
return license != null && license.size() > 0;
}
public boolean hasSource(String regex)
{
for (String source : sources)
{
if (source.matches(regex))
{
return true;
}
}
return false;
}
public boolean hasUniqueSource(String regex)
{
if (sources.size() != 1)
{
return false;
}
return sources.iterator().next().matches(regex);
}
public boolean acknowledgeLicense() throws IOException
{
@ -361,6 +384,11 @@ public class Module
return enabled;
}
public boolean isVirtual()
{
return !logicalName.equals(fileRef);
}
public void process(BaseHome basehome) throws FileNotFoundException, IOException
{
Pattern section = Pattern.compile("\\s*\\[([^]]*)\\]\\s*");
@ -477,5 +505,4 @@ public class Module
str.append(']');
return str.toString();
}
}

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -38,6 +39,134 @@ import java.util.regex.Pattern;
*/
public class Modules implements Iterable<Module>
{
public static interface Matcher
{
public boolean match(Module module);
}
public static class AllMatcher implements Matcher
{
@Override
public boolean match(Module module)
{
return true;
}
}
public static class AndMatcher implements Matcher
{
private final Matcher matchers[];
public AndMatcher(Matcher ... matchers)
{
this.matchers = matchers;
}
@Override
public boolean match(Module module)
{
for (Matcher matcher : this.matchers)
{
if (!matcher.match(module))
{
return false;
}
}
return true;
}
}
public static class EnabledMatcher implements Matcher
{
@Override
public boolean match(Module module)
{
return module.isEnabled();
}
}
public static class RegexNameMatcher implements Matcher
{
private final Pattern pat;
public RegexNameMatcher(String regex)
{
this.pat = Pattern.compile(regex);
}
@Override
public boolean match(Module module)
{
return pat.matcher(module.getName()).matches();
}
}
public static class UniqueSourceMatcher implements Matcher
{
private final Pattern pat;
public UniqueSourceMatcher(String sourceRegex)
{
this.pat = Pattern.compile(sourceRegex);
}
@Override
public boolean match(Module module)
{
if (module.getSources().size() != 1)
{
// Not unique
return false;
}
String sourceId = module.getSources().iterator().next();
return pat.matcher(sourceId).matches();
}
}
public static class SourceSetMatcher implements Matcher
{
private final Set<String> nameSet;
public SourceSetMatcher(String... names)
{
this.nameSet = new HashSet<>();
for (String name : names)
{
this.nameSet.add(name);
}
}
@Override
public boolean match(Module module)
{
Set<String> sources = module.getSources();
if (sources == null)
{
// empty sources list
return false;
}
if (sources.size() != nameSet.size())
{
// non-equal sized set
return false;
}
for (String source : module.getSources())
{
if (!this.nameSet.contains(source))
{
return false;
}
}
return true;
}
}
private final BaseHome baseHome;
private final StartArgs args;
@ -194,7 +323,7 @@ public class Modules implements Iterable<Module>
ordered.addAll(modules.values());
Collections.sort(ordered,new Module.NameComparator());
List<Module> active = resolveEnabled();
List<Module> active = getEnabled();
for (Module module : ordered)
{
@ -275,37 +404,40 @@ public class Modules implements Iterable<Module>
List<String> empty = Collections.emptyList();
enable(name,empty);
}
public void enable(String name, List<String> sources) throws IOException
public int enableAll(List<String> names, String source) throws IOException
{
if ((names == null) || (names.isEmpty()))
{
// nothing to do
return 0;
}
List<String> sources = Collections.singletonList(source);
int count = 0;
for (String name : names)
{
count += enable(name,sources);
}
return count;
}
public int enable(String name, List<String> sources) throws IOException
{
int count = 0;
if (name.contains("*"))
{
// A regex!
Pattern pat = Pattern.compile(name);
List<Module> matching = new ArrayList<>();
do
List<Module> matching = getMatching(new RegexNameMatcher(name));
// enable them
for (Module module : matching)
{
matching.clear();
// find matching entries that are not enabled
for (Map.Entry<String, Module> entry : modules.entrySet())
{
if (pat.matcher(entry.getKey()).matches())
{
if (!entry.getValue().isEnabled())
{
matching.add(entry.getValue());
}
}
}
// enable them
for (Module module : matching)
{
enableModule(module,sources);
}
count += enableModule(module,sources);
}
while (!matching.isEmpty());
}
else
{
@ -313,32 +445,36 @@ public class Modules implements Iterable<Module>
if (module == null)
{
System.err.printf("WARNING: Cannot enable requested module [%s]: not a valid module name.%n",name);
return;
return count;
}
enableModule(module,sources);
count += enableModule(module,sources);
}
return count;
}
private void enableModule(Module module, List<String> sources) throws IOException
private int enableModule(Module module, List<String> sources) throws IOException
{
String via = "<transitive>";
// Always add the sources
if (sources != null)
int count = 0;
if(sources == null)
{
module.addSources(sources);
via = Utils.join(sources, ", ");
// We use source for tagging how a node was selected, it should
// always be required
throw new RuntimeException("sources should never be empty");
}
module.addSources(sources);
String via = Utils.join(sources, ", ");
// If already enabled, nothing else to do
if (module.isEnabled())
{
StartLog.debug("Enabled module: %s (via %s)",module.getName(),via);
return;
return count;
}
StartLog.debug("Enabling module: %s (via %s)",module.getName(),via);
module.setEnabled(true);
count++;
args.parseModule(module);
module.expandProperties(args.getProperties());
@ -370,9 +506,10 @@ public class Modules implements Iterable<Module>
}
if (parent != null)
{
enableModule(parent,null);
count += enableModule(parent,sources);
}
}
return count;
}
private void findChildren(Module module, Set<Module> ret)
@ -560,12 +697,40 @@ public class Modules implements Iterable<Module>
findChildren(module,ret);
return asNameSet(ret);
}
public List<Module> getEnabled()
{
return getMatching(new EnabledMatcher());
}
/**
* Resolve the execution order of the enabled modules, and all dependant modules, based on depth first transitive reduction.
* Get the modules from the tree that match the provided matcher.
*
* @return the list of active modules (plus dependant modules), in execution order.
* @param matcher the matcher to use for matches
* @return the list of matching modules in execution order.
*/
public List<Module> getMatching(Matcher matcher)
{
List<Module> selected = new ArrayList<Module>();
for (Module module : modules.values())
{
if (matcher.match(module))
{
selected.add(module);
}
}
Collections.sort(selected,new Module.DepthComparator());
return selected;
}
/**
* Resolve the execution order of the enabled modules, and all dependent modules, based on depth first transitive reduction.
*
* @return the list of active modules (plus dependent modules), in execution order.
*/
@Deprecated
public List<Module> resolveEnabled()
{
Map<String, Module> active = new HashMap<String, Module>();
@ -578,6 +743,16 @@ public class Modules implements Iterable<Module>
}
}
assertModulesValid(active.values());
List<Module> ordered = new ArrayList<>();
ordered.addAll(active.values());
Collections.sort(ordered,new Module.DepthComparator());
return ordered;
}
public void assertModulesValid(Collection<Module> active)
{
/*
* check against the missing modules
*
@ -585,9 +760,9 @@ public class Modules implements Iterable<Module>
*/
for (String missing : missingModules)
{
for (String activeModule : active.keySet())
for (Module module : active)
{
if (missing.startsWith(activeModule))
if (missing.startsWith(module.getName()))
{
StartLog.warn("** Unable to continue, required dependency missing. [%s]",missing);
StartLog.warn("** As configured, Jetty is unable to start due to a missing enabled module dependency.");
@ -596,11 +771,6 @@ public class Modules implements Iterable<Module>
}
}
}
List<Module> ordered = new ArrayList<>();
ordered.addAll(active.values());
Collections.sort(ordered,new Module.DepthComparator());
return ordered;
}
public Set<String> resolveParentModulesOf(String moduleName)

View File

@ -1,48 +0,0 @@
Jetty start
-----------
The run directory is either the top-level of a distribution
or jetty-distribution/target/distribution directory when built from
source.
Jetty start.jar provides a cross platform replacement for startup scripts.
It makes use of executable JAR that builds the classpath and then executes
jetty.
To run with the demo:
java -jar start.jar --enable=demo
java -jar start.jar
To run with the default modules:
java -jar start.jar
The default options may be specified in the start.ini file, or if
that is not present, they are defined in the start.config file that
is within the start.jar.
To run with specific configuration file(s)
java -jar start.jar etc/jetty.xml
To see the available options
java -jar start.jar --help
To run with JSP support (if available)
java -jar start.jar --module=jsp
To run with JMX support
java -jar start.jar --module=jmx
To run with JSP & JMX support
java -jar start.jar --module=jsp,jmx
Note that JSP requires the jasper jars to be within $JETTY/lib/jsp These
are currently not distributed with the eclipse release and must be
obtained from a jetty-hightide release from codehaus.

View File

@ -116,6 +116,7 @@ public class StartArgs
/** Download related args */
private boolean download = false;
private boolean licenseCheckRequired = false;
private boolean testingMode = false;
private boolean help = false;
@ -139,10 +140,6 @@ public class StartArgs
FileArg arg = new FileArg(module, uriLocation);
if (!files.contains(arg))
{
if (arg.uri != null)
{
this.download = true;
}
files.add(arg);
}
}
@ -656,6 +653,11 @@ public class StartArgs
return exec;
}
public boolean isLicenseCheckRequired()
{
return licenseCheckRequired;
}
public boolean isNormalMainClass()
{
return SERVER_MAIN.equals(getMainClassname());
@ -792,6 +794,7 @@ public class StartArgs
{
run = false;
download = true;
licenseCheckRequired = true;
return;
}
@ -861,6 +864,7 @@ public class StartArgs
addToStartdIni.addAll(moduleNames);
run = false;
download = true;
licenseCheckRequired = true;
return;
}
@ -871,6 +875,7 @@ public class StartArgs
addToStartIni.addAll(moduleNames);
run = false;
download = true;
licenseCheckRequired = true;
return;
}

View File

@ -0,0 +1,86 @@
//
// ========================================================================
// 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.builders;
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 org.eclipse.jetty.start.BaseBuilder;
import org.eclipse.jetty.start.FS;
import org.eclipse.jetty.start.Module;
/**
* Management of the <code>${jetty.base}/start.d/</code> based configuration.
* <p>
* Implementation of the <code>--add-to-startd=[name]</code> command line behavior
*/
public class StartDirBuilder implements BaseBuilder.Config
{
private final Path startDir;
public StartDirBuilder(BaseBuilder baseBuilder) throws IOException
{
this.startDir = baseBuilder.getBaseHome().getBasePath("start.d");
FS.ensureDirectoryExists(startDir);
}
@Override
public boolean addModule(Module module) throws IOException
{
if (module.isVirtual())
{
// skip, no need to reference
return false;
}
// Create start.d/{name}.ini
Path ini = startDir.resolve(module.getName() + ".ini");
try (BufferedWriter writer = Files.newBufferedWriter(ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING))
{
writeModuleSection(writer,module);
}
return true;
}
protected void writeModuleSection(BufferedWriter writer, Module module)
{
PrintWriter out = new PrintWriter(writer);
out.println("# --------------------------------------- ");
out.println("# Module: " + module.getName());
out.println("--module=" + module.getName());
for (String line : module.getDefaultConfig())
{
out.println(line);
}
out.println();
out.flush();
}
}

View File

@ -0,0 +1,127 @@
//
// ========================================================================
// 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.builders;
import java.io.BufferedReader;
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.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jetty.start.BaseBuilder;
import org.eclipse.jetty.start.Module;
import org.eclipse.jetty.start.Props;
/**
* Management of the <code>${jetty.base}/start.ini</code> based configuration.
* <p>
* Implementation of the <code>--add-to-start=[name]</code> command line
* behavior
*/
public class StartIniBuilder implements BaseBuilder.Config
{
private final Path startIni;
/* List of modules already present in start.ini */
private Set<String> modulesPresent = new HashSet<>();
/* List of properties (keys only) already present in start.ini */
private Set<String> propsPresent = new HashSet<>();
public StartIniBuilder(BaseBuilder baseBuilder) throws IOException
{
this.startIni = baseBuilder.getBaseHome().getBasePath("start.ini");
if (Files.exists(startIni))
{
parseIni();
}
}
private void parseIni() throws IOException
{
try (BufferedReader reader = Files.newBufferedReader(startIni,StandardCharsets.UTF_8))
{
String line;
while ((line = reader.readLine()) != null)
{
line = line.trim();
if (line.startsWith("--module="))
{
List<String> moduleNames = Props.getValues(line);
this.modulesPresent.addAll(moduleNames);
}
else if (!line.startsWith("-") && line.contains("-"))
{
String key = line.substring(0,line.indexOf('='));
this.propsPresent.add(key);
}
}
}
}
@Override
public boolean addModule(Module module) throws IOException
{
if (modulesPresent.contains(module.getName()))
{
// skip, already present
return false;
}
if (module.isVirtual())
{
// skip, no need to reference
return false;
}
// Append to start.ini
try (BufferedWriter writer = Files.newBufferedWriter(startIni,StandardCharsets.UTF_8,StandardOpenOption.APPEND,StandardOpenOption.CREATE))
{
writeModuleSection(writer,module);
}
return true;
}
protected void writeModuleSection(BufferedWriter writer, Module module)
{
PrintWriter out = new PrintWriter(writer);
out.println("# --------------------------------------- ");
out.println("# Module: " + module.getName());
out.println("--module=" + module.getName());
for (String line : module.getDefaultConfig())
{
// TODO: validate property keys
out.println(line);
}
out.println();
out.flush();
}
}

View File

@ -23,6 +23,7 @@ import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import org.eclipse.jetty.start.BaseHome;
import org.eclipse.jetty.start.FS;
import org.eclipse.jetty.start.FileInitializer;
import org.eclipse.jetty.start.StartLog;
@ -80,13 +81,14 @@ public class MavenLocalRepoFileInitializer extends UriFileInitializer implements
private Path localRepositoryDir;
public MavenLocalRepoFileInitializer()
public MavenLocalRepoFileInitializer(BaseHome baseHome)
{
this(null);
this(baseHome,null);
}
public MavenLocalRepoFileInitializer(Path localRepoDir)
public MavenLocalRepoFileInitializer(BaseHome baseHome, Path localRepoDir)
{
super(baseHome);
this.localRepositoryDir = localRepoDir;
}

View File

@ -27,6 +27,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import org.eclipse.jetty.start.BaseHome;
import org.eclipse.jetty.start.FS;
import org.eclipse.jetty.start.FileInitializer;
import org.eclipse.jetty.start.StartLog;
@ -34,6 +35,12 @@ import org.eclipse.jetty.start.StartLog;
public class UriFileInitializer implements FileInitializer
{
private final static String[] SUPPORTED_SCHEMES = { "http", "https" };
private final BaseHome baseHome;
public UriFileInitializer(BaseHome baseHome)
{
this.baseHome = baseHome;
}
@Override
public boolean init(URI uri, Path file) throws IOException
@ -57,7 +64,7 @@ public class UriFileInitializer implements FileInitializer
protected void download(URI uri, Path file) throws IOException
{
StartLog.log("DOWNLOAD","%s to %s",uri,file);
StartLog.log("DOWNLOAD","%s to %s",uri,baseHome.toShortForm(file));
FS.ensureDirectoryExists(file.getParent());

View File

@ -18,21 +18,25 @@
package org.eclipse.jetty.start;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.jetty.start.Modules.AndMatcher;
import org.eclipse.jetty.start.Modules.EnabledMatcher;
import org.eclipse.jetty.start.Modules.UniqueSourceMatcher;
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;
@ -49,18 +53,18 @@ public class ModulesTest
// Test Env
File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
File baseDir = testdir.getEmptyDir();
String cmdLine[] = new String[] {"jetty.version=TEST"};
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(config);
StartArgs args = new StartArgs();
args.parse(config);
@ -112,14 +116,14 @@ public class ModulesTest
expected.add("server");
expected.add("annotations");
expected.add("resources");
expected.add("logging");
expected.add("logging");
ConfigurationAssert.assertContainsUnordered("All Modules",expected,moduleNames);
}
/**
* Test loading of only shallow modules, not deep references.
* In other words. ${search-dir}/modules/*.mod should be the only
* In other words. ${search-dir}/modules/*.mod should be the only
* valid references, but ${search-dir}/alt/foo/modules/*.mod should
* not be considered valid.
*/
@ -128,20 +132,21 @@ public class ModulesTest
{
// Test Env
File homeDir = MavenTestingUtils.getTestResourceDir("jetty home with spaces");
// intentionally setup top level resources dir (as this would have many deep references)
// intentionally setup top level resources dir (as this would have many
// deep references)
File baseDir = MavenTestingUtils.getTestResourcesDir();
String cmdLine[] = new String[] {"jetty.version=TEST"};
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(config);
StartArgs args = new StartArgs();
args.parse(config);
@ -154,10 +159,10 @@ public class ModulesTest
{
moduleNames.add(mod.getName());
}
List<String> expected = new ArrayList<>();
expected.add("base");
ConfigurationAssert.assertContainsUnordered("All Modules",expected,moduleNames);
}
@ -167,18 +172,18 @@ public class ModulesTest
// Test Env
File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
File baseDir = testdir.getEmptyDir();
String cmdLine[] = new String[] {"jetty.version=TEST", "java.version=1.7.0_60"};
String cmdLine[] = new String[] { "jetty.version=TEST", "java.version=1.7.0_60" };
// 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(config);
StartArgs args = new StartArgs();
args.parse(config);
@ -206,9 +211,9 @@ public class ModulesTest
expected.add("protonego-impl");
expected.add("xml");
expected.add("jsp-impl");
List<String> resolved = new ArrayList<>();
for (Module module : modules.resolveEnabled())
for (Module module : modules.getEnabled())
{
resolved.add(module.getName());
}
@ -222,23 +227,23 @@ public class ModulesTest
// Test Env
File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
File baseDir = testdir.getEmptyDir();
String cmdLine[] = new String[] {"jetty.version=TEST"};
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(config);
StartArgs args = new StartArgs();
args.parse(config);
// Test Modules
Modules modules = new Modules(basehome, args);
Modules modules = new Modules(basehome,args);
modules.registerAll();
// Enable 2 modules
@ -248,7 +253,7 @@ public class ModulesTest
modules.buildGraph();
// Collect active module list
List<Module> active = modules.resolveEnabled();
List<Module> active = modules.getEnabled();
// Assert names are correct, and in the right order
List<String> expectedNames = new ArrayList<>();
@ -263,7 +268,7 @@ public class ModulesTest
actualNames.add(actual.getName());
}
Assert.assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
// Assert Library List
List<String> expectedLibs = new ArrayList<>();
@ -277,7 +282,7 @@ public class ModulesTest
expectedLibs.add("lib/jetty-server-${jetty.version}.jar");
List<String> actualLibs = modules.normalizeLibs(active);
Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
// Assert XML List
List<String> expectedXmls = new ArrayList<>();
@ -285,7 +290,7 @@ public class ModulesTest
expectedXmls.add("etc/jetty-http.xml");
List<String> actualXmls = modules.normalizeXmls(active);
Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
}
@Test
@ -294,18 +299,18 @@ public class ModulesTest
// Test Env
File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
File baseDir = testdir.getEmptyDir();
String cmdLine[] = new String[] {"jetty.version=TEST"};
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(config);
StartArgs args = new StartArgs();
args.parse(config);
@ -321,7 +326,7 @@ public class ModulesTest
// modules.dump();
// Collect active module list
List<Module> active = modules.resolveEnabled();
List<Module> active = modules.getEnabled();
// Assert names are correct, and in the right order
List<String> expectedNames = new ArrayList<>();
@ -341,7 +346,7 @@ public class ModulesTest
actualNames.add(actual.getName());
}
Assert.assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
// Assert Library List
List<String> expectedLibs = new ArrayList<>();
@ -362,7 +367,7 @@ public class ModulesTest
expectedLibs.add("lib/websocket/*.jar");
List<String> actualLibs = modules.normalizeLibs(active);
Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
// Assert XML List
List<String> expectedXmls = new ArrayList<>();
@ -373,6 +378,98 @@ public class ModulesTest
expectedXmls.add("etc/jetty-websockets.xml");
List<String> actualXmls = modules.normalizeXmls(active);
Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
}
@Test
public void testResolve_Alt() throws IOException
{
// Test Env
File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
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(config);
StartArgs args = new StartArgs();
args.parse(config);
// Test Modules
Modules modules = new Modules(basehome,args);
modules.registerAll();
// Enable test modules
modules.enable("http",TEST_SOURCE);
modules.enable("annotations",TEST_SOURCE);
modules.enable("deploy",TEST_SOURCE);
// Enable alternate modules
String alt = "<alt>";
modules.enable("websocket",Collections.singletonList(alt));
modules.enable("jsp",Collections.singletonList(alt));
modules.buildGraph();
// modules.dump();
// Collect active module list
List<Module> active = modules.getEnabled();
// Assert names are correct, and in the right order
List<String> expectedNames = new ArrayList<>();
expectedNames.add("base");
expectedNames.add("jsp-impl");
expectedNames.add("xml");
expectedNames.add("server");
expectedNames.add("http");
expectedNames.add("jndi");
expectedNames.add("security");
expectedNames.add("servlet");
expectedNames.add("jsp");
expectedNames.add("plus");
expectedNames.add("webapp");
expectedNames.add("annotations");
expectedNames.add("deploy");
expectedNames.add("websocket");
List<String> actualNames = new ArrayList<>();
for (Module actual : active)
{
actualNames.add(actual.getName());
}
assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
// Now work with the 'alt' selected
List<String> expectedAlts = new ArrayList<>();
expectedAlts.add("jsp-impl");
expectedAlts.add("jsp");
expectedAlts.add("websocket");
for (String expectedAlt : expectedAlts)
{
Module altMod = modules.get(expectedAlt);
assertThat("Alt.mod[" + expectedAlt + "].enabled",altMod.isEnabled(),is(true));
Set<String> sources = altMod.getSources();
assertThat("Alt.mod[" + expectedAlt + "].sources: [" + Utils.join(sources,", ") + "]",sources,contains(alt));
}
// Now collect the unique source list
List<Module> alts = modules.getMatching(new AndMatcher(new EnabledMatcher(),new UniqueSourceMatcher(alt)));
// Assert names are correct, and in the right order
actualNames = new ArrayList<>();
for (Module actual : alts)
{
actualNames.add(actual.getName());
}
assertThat("Resolved Alt (Sources) Names: " + actualNames,actualNames,contains(expectedAlts.toArray()));
}
}

View File

@ -21,9 +21,17 @@ package org.eclipse.jetty.start.fileinits;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import org.eclipse.jetty.start.BaseHome;
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.start.fileinits.MavenLocalRepoFileInitializer.Coordinates;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@ -32,11 +40,28 @@ public class MavenLocalRepoFileInitializerTest
{
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public TestingDir testdir = new TestingDir();
private BaseHome baseHome;
@Before
public void setupBaseHome() throws IOException
{
File homeDir = testdir.getEmptyDir();
ConfigSources config = new ConfigSources();
config.add(new JettyHomeConfigSource(homeDir.toPath()));
config.add(new JettyBaseConfigSource(homeDir.toPath()));
this.baseHome = new BaseHome(config);
}
@Test
public void testGetCoordinate_NotMaven()
{
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer();
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
String ref = "http://www.eclipse.org/jetty";
Coordinates coords = repo.getCoordinates(URI.create(ref));
assertThat("Coords",coords,nullValue());
@ -45,7 +70,7 @@ public class MavenLocalRepoFileInitializerTest
@Test
public void testGetCoordinate_InvalidMaven()
{
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer();
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
String ref = "maven://www.eclipse.org/jetty";
expectedException.expect(RuntimeException.class);
expectedException.expectMessage(containsString("Not a valid maven:// uri"));
@ -55,7 +80,7 @@ public class MavenLocalRepoFileInitializerTest
@Test
public void testGetCoordinate_Normal()
{
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer();
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
String ref = "maven://org.eclipse.jetty/jetty-start/9.3.x";
Coordinates coords = repo.getCoordinates(URI.create(ref));
assertThat("Coordinates",coords,notNullValue());
@ -73,7 +98,7 @@ public class MavenLocalRepoFileInitializerTest
@Test
public void testGetCoordinate_Zip()
{
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer();
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
String ref = "maven://org.eclipse.jetty/jetty-distribution/9.3.x/zip";
Coordinates coords = repo.getCoordinates(URI.create(ref));
assertThat("Coordinates",coords,notNullValue());
@ -91,7 +116,7 @@ public class MavenLocalRepoFileInitializerTest
@Test
public void testGetCoordinate_TestJar()
{
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer();
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
String ref = "maven://org.eclipse.jetty/jetty-http/9.3.x/jar/tests";
Coordinates coords = repo.getCoordinates(URI.create(ref));
assertThat("Coordinates",coords,notNullValue());
@ -109,7 +134,7 @@ public class MavenLocalRepoFileInitializerTest
@Test
public void testGetCoordinate_Test_UnspecifiedType()
{
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer();
MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
String ref = "maven://org.eclipse.jetty/jetty-http/9.3.x//tests";
Coordinates coords = repo.getCoordinates(URI.create(ref));
assertThat("Coordinates",coords,notNullValue());