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

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

//
//  ========================================================================
//  Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//  ------------------------------------------------------------------------
//  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.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.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.eclipse.jetty.start.Props.Prop;

/**
 * Represents a Module metadata, as defined in Jetty.
 *
 * 

A module consists of: *

    *
  • A set of jar files, directories and/or jar file patterns to be added to the classpath
  • *
  • A list of XML configuration files
  • *
  • Properties set either directly or via a file of properties
  • *
  • A set of modules names (or capability names) that this module depends on.
  • *
  • A set of capability names that this module provides (including it's own name).
  • *
  • Licence details for using the module
  • *
* Modules are discovered in the ${jetty.home}/modules and * ${jetty.home}/modules directories. A module may refer to * non-discovered dynamic module in a subdirectory, using a property as part or * all of the name. * A module may be enabled, either directly by name or transiently via a dependency * from another module by name or provided capability. */ public class Module implements Comparable { private static final String VERSION_UNSPECIFIED = "0.0"; static Pattern MOD_NAME = Pattern.compile("^(.*)\\.mod", Pattern.CASE_INSENSITIVE); static Pattern SET_PROPERTY = Pattern.compile("^(#?)\\s*([^=\\s]+)=(.*)$"); /** * The file of the module */ private final Path _path; /** * The name of the module */ private final String _name; /** * Is the module dynamic - ie referenced rather than discovered */ private final boolean _dynamic; /** * The version of Jetty the module supports */ private Version version; /** * The module description */ private final List _description = new ArrayList<>(); /** * List of xml configurations for this Module */ private final List _xmls = new ArrayList<>(); /** * List of ini template lines */ private final List _iniTemplate = new ArrayList<>(); /** * List of default config */ private final List _defaultConfig = new ArrayList<>(); /** * List of library options for this Module */ private final List _libs = new ArrayList<>(); /** * List of JPMS options for this Module */ private final List _jpms = new ArrayList<>(); /** * List of files for this Module */ private final List _files = new ArrayList<>(); /** * List of selections for this Module */ private final Set _enables = new HashSet<>(); /** * List of provides for this Module */ private final Set _provides = new HashSet<>(); /** * List of tags for this Module */ private final List _tags = new ArrayList<>(); /** * Boolean true if directly enabled, false if all selections are transitive */ private boolean _notTransitive; /** * Skip File Validation (default: false) */ private boolean _skipFilesValidation = false; /** * List of jvm Args */ private final List _jvmArgs = new ArrayList<>(); /** * License lines */ private final List _license = new ArrayList<>(); /** * Dependencies from {@code [depends]} section */ private final List _depends = new ArrayList<>(); /** * Optional dependencies from {@code [optional]} section are structural in nature. */ private final Set _optional = new HashSet<>(); public Module(BaseHome basehome, Path path) throws IOException { super(); _path = path; // Module name is the / separated path below the modules directory int m = -1; for (int i = path.getNameCount(); i-- > 0; ) { if ("modules".equals(path.getName(i).toString())) { m = i; break; } } if (m < 0) throw new IllegalArgumentException("Module not contained within modules directory: " + basehome.toShortForm(path)); String n = path.getName(m + 1).toString(); for (int i = m + 2; i < path.getNameCount(); i++) { n = n + "/" + path.getName(i).toString(); } Matcher matcher = MOD_NAME.matcher(n); if (!matcher.matches()) throw new IllegalArgumentException("Module filename must have .mod extension: " + basehome.toShortForm(path)); _name = matcher.group(1); _provides.add(_name); _dynamic = _name.contains("/"); process(basehome); } public static boolean isConditionalDependency(String depends) { return (depends != null) && (depends.charAt(0) == '?'); } public static String normalizeModuleName(String name) { if (isConditionalDependency(name)) return name.substring(1); return name; } public String getName() { return _name; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Module other = (Module)obj; if (_path == null) return other._path == null; return _path.equals(other._path); } public void expandDependencies(Props props) { Function expander = d -> props.expand(d); List tmp = _depends.stream().map(expander).collect(Collectors.toList()); _depends.clear(); _depends.addAll(tmp); tmp = _optional.stream().map(expander).collect(Collectors.toList()); _optional.clear(); _optional.addAll(tmp); } public List getDefaultConfig() { return _defaultConfig; } public List getIniTemplate() { return _iniTemplate; } public List getFiles() { return _files; } public boolean isSkipFilesValidation() { return _skipFilesValidation; } public List getJvmArgs() { return _jvmArgs; } public List getLibs() { return _libs; } public List getLicense() { return _license; } public List getXmls() { return _xmls; } public List getJPMS() { return _jpms; } public Version getVersion() { return version; } public boolean hasDefaultConfig() { return !_defaultConfig.isEmpty(); } public boolean hasIniTemplate() { return !_iniTemplate.isEmpty(); } @Override public int hashCode() { return _name.hashCode(); } public boolean hasLicense() { return (_license != null) && (_license.size() > 0); } /** * Indicates a module that is dynamic in nature * * @return a module where the name is not in the top level of the modules directory */ public boolean isDynamic() { return _dynamic; } public boolean hasFiles(BaseHome baseHome, Props props) { for (String ref : getFiles()) { FileArg farg = new FileArg(this, props.expand(ref)); Path refPath = baseHome.getBasePath(farg.location); if (!Files.exists(refPath)) { return false; } } return true; } public void process(BaseHome basehome) throws IOException { Pattern section = Pattern.compile("\\s*\\[([^]]*)\\]\\s*"); if (!FS.canReadFile(_path)) { StartLog.debug("Skipping read of missing file: %s", basehome.toShortForm(_path)); return; } try (BufferedReader buf = Files.newBufferedReader(_path, StandardCharsets.UTF_8)) { String sectionType = ""; String line; while ((line = buf.readLine()) != null) { line = line.trim(); Matcher sectionMatcher = section.matcher(line); if (sectionMatcher.matches()) { sectionType = sectionMatcher.group(1).trim().toUpperCase(Locale.ENGLISH); } else { // blank lines and comments are valid for ini-template section if ((line.length() == 0) || line.startsWith("#")) { // Remember ini comments and whitespace (empty lines) // for the [ini-template] section if ("INI-TEMPLATE".equals(sectionType)) { _iniTemplate.add(line); } } else { switch (sectionType) { case "": // ignore (this would be entries before first section) break; case "DESCRIPTION": _description.add(line); break; case "DEPEND": case "DEPENDS": if (!_depends.contains(line)) _depends.add(line); break; case "FILE": case "FILES": _files.add(line); break; case "TAG": case "TAGS": _tags.add(line); break; case "DEFAULTS": // old name introduced in 9.2.x case "INI": // new name for 9.3+ _defaultConfig.add(line); break; case "INI-TEMPLATE": _iniTemplate.add(line); break; case "LIB": case "LIBS": _libs.add(line); break; case "JPMS": _jpms.add(line); break; case "LICENSE": case "LICENSES": case "LICENCE": case "LICENCES": _license.add(line); break; case "NAME": StartLog.warn("Deprecated [name] used in %s", basehome.toShortForm(_path)); _provides.add(line); break; case "PROVIDE": case "PROVIDES": _provides.add(line); break; case "OPTIONAL": _optional.add(line); break; case "EXEC": _jvmArgs.add(line); break; case "VERSION": if (version != null) { throw new IOException("[version] already specified"); } version = new Version(line); break; case "XML": _xmls.add(line); break; default: throw new IOException("Unrecognized module section: [" + sectionType + "]"); } } } } } if (version == null) { version = new Version(VERSION_UNSPECIFIED); } } public boolean clearTransitiveEnable() { if (_notTransitive) throw new IllegalStateException("Not Transitive"); if (isEnabled()) { _enables.clear(); return true; } return false; } public void setSkipFilesValidation(boolean skipFilesValidation) { this._skipFilesValidation = skipFilesValidation; } @Override public String toString() { StringBuilder str = new StringBuilder(); str.append(getName()); char sep = '{'; if (isDynamic()) { str.append(sep).append("dynamic"); sep = ','; } if (isEnabled()) { str.append(sep).append("enabled"); sep = ','; } if (isTransitive()) { str.append(sep).append("transitive"); sep = ','; } if (sep != '{') str.append('}'); return str.toString(); } public List getDepends() { return new ArrayList<>(_depends); } public Set getProvides() { return new HashSet<>(_provides); } public Set getOptional() { return new HashSet<>(_optional); } public List getDescription() { return _description; } public List getTags() { return _tags; } public String getPrimaryTag() { return _tags.isEmpty() ? "*" : _tags.get(0); } public boolean isEnabled() { return !_enables.isEmpty(); } public Set getEnableSources() { return new HashSet<>(_enables); } /** * @param source String describing where the module was enabled from * @param transitive True if the enable is transitive * @return true if the module was not previously enabled */ public boolean enable(String source, boolean transitive) { boolean updated = _enables.isEmpty(); if (transitive) { // Ignore transitive selections if explicitly enabled if (!_notTransitive) _enables.add(source); } else { if (!_notTransitive) { // Ignore transitive selections if explicitly enabled updated = true; _enables.clear(); // clear any transitive enabling } _notTransitive = true; _enables.add(source); } return updated; } public boolean isTransitive() { return isEnabled() && !_notTransitive; } public void writeIniSection(BufferedWriter writer, Props props) { PrintWriter out = new PrintWriter(writer); out.println("# --------------------------------------- "); out.println("# Module: " + getName()); for (String line : getDescription()) { out.append("# ").println(line); } out.println("# --------------------------------------- "); out.println("--module=" + getName()); out.println(); for (String line : getIniTemplate()) { Matcher m = SET_PROPERTY.matcher(line); if (m.matches() && m.groupCount() == 3) { String name = m.group(2); String value = m.group(3); Prop p = props.getProp(name); if (p != null && (p.source == null || !p.source.endsWith("?=")) && ("#".equals(m.group(1)) || !value.equals(p.value))) { System.err.printf("%s == %s :: %s%n", name, value, p.source); StartLog.info("%-15s property set %s=%s", this._name, name, p.value); out.printf("%s=%s%n", name, p.value); } else out.println(line); } else out.println(line); } out.println(); out.flush(); } @Override public int compareTo(Module m) { int byTag = getPrimaryTag().compareTo(m.getPrimaryTag()); if (byTag != 0) return byTag; return getName().compareTo(m.getName()); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy