Skip to content

Simplify startup code #5701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 19 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.SystemProperties;
import org.exist.start.Classpath;
import org.exist.start.EXistClassLoader;
import org.exist.start.classloader.Classpath;
import org.exist.start.classloader.EXistClassLoader;
import org.exist.storage.BrokerPool;
import org.exist.storage.BrokerPoolService;
import org.expath.pkg.repo.FileSystemStorage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.EXistException;
import org.exist.start.Classpath;
import org.exist.start.EXistClassLoader;
import org.exist.start.classloader.Classpath;
import org.exist.start.classloader.EXistClassLoader;
import org.exist.storage.BrokerPool;
import org.exist.storage.journal.Journal;
import org.exist.util.Configuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.start.LatestFileResolver;
import org.exist.util.FileUtils;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,48 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.exist.start;
package org.exist.webstart;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* This class uses regex pattern matching to find the latest version of a
* particular jar file.
*
* @see LatestFileResolver#getResolvedFileName(String)
*
* particular jar file.
*
* @author Ben Schmaus ([email protected])
* @version $Revision$
* @see LatestFileResolver#getResolvedFileName(String)
*/
public class LatestFileResolver {

// Pattern that can be used to indicate that the
// latest version of a particular file should be added to the classpath.
// E.g., commons-fileupload-%latest%.jar would resolve to something like
// commons-fileupload-1.1.jar.
private final static Pattern latestVersionPattern = Pattern.compile(
"(%latest%)"
);
private final static Pattern latestVersionPattern = Pattern.compile("(%latest%)");

// Set debug mode for each file resolver instance based on whether or
// not the system was started with debugging turned on.
private static boolean _debug = Boolean.getBoolean("exist.start.debug");
private static final boolean _debug = Boolean.getBoolean("exist.start.debug");

/**
* If the passed file name contains a %latest% token,
* find the latest version of that file. Otherwise, return
* the passed file name unmodified.
*
*
* @param filename Path relative to exist home dir of
* a jar file that should be added to the classpath.
* a jar file that should be added to the classpath.
* @return Resolved filename.
*/
public String getResolvedFileName(final String filename) {
Expand All @@ -72,9 +73,7 @@ public String getResolvedFileName(final String filename) {
final String uptoToken = fileinfo[0];

// Dir that should contain our jar.
final String containerDirName = uptoToken.substring(
0, uptoToken.lastIndexOf(File.separatorChar)
);
final String containerDirName = uptoToken.substring(0, uptoToken.lastIndexOf(File.separatorChar));

final Path containerDir = Paths.get(containerDirName);

Expand All @@ -86,8 +85,8 @@ public String getResolvedFileName(final String filename) {

List<Path> jars;
try {
jars = Main.list(containerDir, p -> {
matcher.reset(Main.fileName(p));
jars = list(containerDir, p -> {
matcher.reset(fileName(p));
return matcher.find();
});
} catch (final IOException e) {
Expand All @@ -99,20 +98,34 @@ public String getResolvedFileName(final String filename) {
if (!jars.isEmpty()) {
final String actualFileName = jars.getFirst().toAbsolutePath().toString();
if (_debug) {
System.err.println(
"Found match: " + actualFileName
+ " for jar file pattern: " + filename
);
System.err.println("Found match: " + actualFileName + " for jar file pattern: " + filename);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOG.error() can now be used

}
return actualFileName;
} else {
if (_debug) {
System.err.println(
"WARN: No latest version found for JAR file: '"
+ filename + "'"
);
System.err.println("WARN: No latest version found for JAR file: '" + filename + "'");
}
}
return filename;
}
}

/**
* Copied from {@link org.exist.util.FileUtils#list(Path, Predicate)}
* as org.exist.start is compiled into a separate Jar and doesn't have
* the rest of eXist available on the classpath
*/
static List<Path> list(final Path directory, final Predicate<Path> filter) throws IOException {
try (final Stream<Path> entries = Files.list(directory).filter(filter)) {
return entries.collect(Collectors.toList());
}
}

/**
* Copied from {@link org.exist.util.FileUtils#fileName(Path)}
* as org.exist.start is compiled into a separate Jar and doesn't have
* the rest of eXist available on the classpath
*/
static String fileName(final Path path) {
return path.getFileName().toString();
}
}
2 changes: 1 addition & 1 deletion exist-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@
<identifier>org.exist.start.Main</identifier>
<mainClassName>org.exist.start.Main</mainClassName>
<executableName>eXist-JavaAppLauncher</executableName>
<jvmRequired>1.8</jvmRequired>
<jvmRequired>21</jvmRequired>
<minimumSystemVersion>10.9</minimumSystemVersion>
<version>${project.version}</version>
<shortVersion>${project.version}</shortVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class ExistDbDaemon implements Daemon {
private String[] args = null;

private void init(final String args[]) {
this.main = new Main("jetty");
this.main = new Main(Main.MODE_JETTY);
this.args = args;
}

Expand Down Expand Up @@ -65,12 +65,12 @@ public void start() throws Exception {
runArgs[0] = MODE_JETTY;
System.arraycopy(args, 0, runArgs, 1, args.length);

this.main.runEx(runArgs);
this.main.startExistdb(runArgs);
}

@Override
public void stop() throws Exception {
this.main.shutdownEx();
this.main.shutdownExistdb();
}

@Override
Expand Down
8 changes: 2 additions & 6 deletions exist-start/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@
-->
<excludes>
<exclude>Mortbay-APACHE-2-license.template.txt</exclude>
<exclude>src/main/java/org/exist/start/Classpath.java</exclude>
<exclude>src/main/java/org/exist/start/Main.java</exclude>
<exclude>src/main/java/org/exist/start/Version.java</exclude>
<exclude>src/main/java/org/exist/start/classloader/Classpath.java</exclude>
</excludes>

</licenseSet>
Expand All @@ -95,9 +93,7 @@ The original license statement is also included below.]]></preamble>
</multi>
<excludes />
<includes>
<include>src/main/java/org/exist/start/Classpath.java</include>
<include>src/main/java/org/exist/start/Main.java</include>
<include>src/main/java/org/exist/start/Version.java</include>
<include>src/main/java/org/exist/start/classloader/Classpath.java</include>
</includes>
</licenseSet>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,49 @@
import java.util.Optional;
import java.util.stream.Stream;

import static org.exist.start.CompatibleJavaVersionCheck.IncompatibleJavaVersion.IncompatibleJavaVersion;
import static org.exist.start.CompatibleJavaVersionCheck.IncompatibleJavaVersion.create;
import static org.exist.start.Main.ERROR_CODE_INCOMPATIBLE_JAVA_DETECTED;

/**
* Helper class for checking OpenJDK compatibility.
* <p>
* eXist-db has been compiled with Java21 (state of 2025Q2).
* <p>
* Older versions of Java contained a number of serious compiler bugs that caused database corruptions.
* These problematic versions are deprecated and therefore this class is not relevant anymore.
* <p>
* The code is kept for archival purposes and potential future re-usage.
* <p>
* ----------------------------
* <p>
* OpenJDK versions 12 through 15.0.1 suffer from a critical bug in the JIT C2 compiler that will
* cause data loss in eXist-db. The problem has been reported to the OpenJDK community.
* <p>
* For more information, see:
* - <a href="https://bugs.openjdk.java.net/browse/JDK-8253191">C2: Masked byte comparisons with large masks produce wrong result on x86</a>
* - <a href="https://github.com/eXist-db/exist/issues/3375">eXist-db does not run correctly on JDKs 12, 13, 14 and 15 #3375</a>
*
*
*/
public class CompatibleJavaVersionCheck {

private static final IncompatibleJavaVersion[] INCOMPATIBLE_JAVA_VERSIONS = {
IncompatibleJavaVersion(12),
IncompatibleJavaVersion(13),
IncompatibleJavaVersion(14),
IncompatibleJavaVersion(15, 0, 2)
create(12),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to compile start.jar with java21 iso java8 .... these items could be removed; voiding all tests too,

create(13),
create(14),
IncompatibleJavaVersion.create(15, 0, 2),

Check notice on line 57 in exist-start/src/main/java/org/exist/start/CompatibleJavaVersionCheck.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

exist-start/src/main/java/org/exist/start/CompatibleJavaVersionCheck.java#L57

Unnecessary use of fully qualified name 'IncompatibleJavaVersion.create' due to existing static import 'org.exist.start.CompatibleJavaVersionCheck.IncompatibleJavaVersion.create'
};

private static final String INCOMPATIBLE_JAVA_VERSION_NOTICE =
"*****************************************************%n" +
"Warning: Unreliable Java version has been detected!%n" +
"%n" +
"OpenJDK versions 12 through 15.0.1 suffer from a critical%n" +
" bug in the JIT C2 compiler that will cause data loss in%n" +
"eXist-db.%n" +
"%n" +
"The problem has been reported to the OpenJDK community.%n" +
"%n" +
"For more information, see:%n" +
"\t* https://bugs.openjdk.java.net/browse/JDK-8253191%n" +
"\t* https://github.com/eXist-db/exist/issues/3375%n" +
"%n" +
"The detected version of Java on your system is: %s.%n" +
"%n" +
"To prevent potential data loss, eXist-db will not be started.%n" +
"To start eXist-db, we recommend using Java 8 or 11.%n" +
"*****************************************************";
"*****************************************************%n"
+ "Incorrect version of Java detected!%n"
+ "%n"
+ "The detected version of Java on your system is: %s.%n"
+ "%n"
+ "eXist-db has been developed and qualified using Java 21.%n"
+ "%n"
+ "Newer versions of Java might or might not work correctly.%n"
+ "*****************************************************";

private static final Optional<String> RUNTIME_JAVA_VERSION = Optional.ofNullable(System.getProperty("java.version"));

Expand All @@ -71,16 +83,18 @@
static void checkForCompatibleJavaVersion(final Optional<String> checkJavaVersion) throws StartException {
final Optional<int[]> maybeJavaVersionComponents = extractJavaVersionComponents(checkJavaVersion);

if (!maybeJavaVersionComponents.isPresent()) {
if (maybeJavaVersionComponents.isEmpty()) {
// Could not determine major java version, so best to let the user proceed...
return;
}

// check for incompatible java version
final int[] javaVersionComponents = maybeJavaVersionComponents.get();
final int majorJavaVersion = javaVersionComponents[0];
/* @Nullable */ final Integer minorJavaVersion = javaVersionComponents.length > 1 ? javaVersionComponents[1] : null;
/* @Nullable */ final Integer patchJavaVersion = javaVersionComponents.length > 2 ? javaVersionComponents[2] : null;
/* @Nullable */
final Integer minorJavaVersion = javaVersionComponents.length > 1 ? javaVersionComponents[1] : null;
/* @Nullable */
final Integer patchJavaVersion = javaVersionComponents.length > 2 ? javaVersionComponents[2] : null;

for (final IncompatibleJavaVersion incompatibleJavaVersion : INCOMPATIBLE_JAVA_VERSIONS) {
// compare major versions
Expand All @@ -104,7 +118,8 @@
}

// version is NOT compatible!
throw new StartException(ERROR_CODE_INCOMPATIBLE_JAVA_DETECTED, String.format(INCOMPATIBLE_JAVA_VERSION_NOTICE, RUNTIME_JAVA_VERSION));
throw new StartException(ERROR_CODE_INCOMPATIBLE_JAVA_DETECTED,
String.format(INCOMPATIBLE_JAVA_VERSION_NOTICE, RUNTIME_JAVA_VERSION.orElse("UKNOWN")));
}

// version is compatible
Expand All @@ -131,22 +146,22 @@
/* @Nullable */ final Integer lessThanMinor;
/* @Nullable */ final Integer lessThanPatch;

private IncompatibleJavaVersion(final int major, /* @Nullable */ Integer lessThanMinor, /* @Nullable */ Integer lessThanPatch) {
private IncompatibleJavaVersion(final int major, /* @Nullable */ final Integer lessThanMinor, /* @Nullable */ final Integer lessThanPatch) {
this.major = major;
this.lessThanMinor = lessThanMinor;
this.lessThanPatch = lessThanPatch;
}

public static IncompatibleJavaVersion IncompatibleJavaVersion(final int major, /* @Nullable */ Integer lessThanMinor, /* @Nullable */ Integer lessThanPatch) {
public static IncompatibleJavaVersion create(final int major, /* @Nullable */ final Integer lessThanMinor, /* @Nullable */ final Integer lessThanPatch) {
return new IncompatibleJavaVersion(major, lessThanMinor, lessThanPatch);
}

public static IncompatibleJavaVersion IncompatibleJavaVersion(final int major, /* @Nullable */ Integer lessThanMinor) {
return IncompatibleJavaVersion(major, lessThanMinor, null);
public static IncompatibleJavaVersion create(final int major, /* @Nullable */ final Integer lessThanMinor) {
return new IncompatibleJavaVersion(major, lessThanMinor, null);
}

public static IncompatibleJavaVersion IncompatibleJavaVersion(final int major) {
return IncompatibleJavaVersion(major, null, null);
public static IncompatibleJavaVersion create(final int major) {
return new IncompatibleJavaVersion(major, null, null);
}
}
}
Loading
Loading