Skip to content
Open
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,9 +24,15 @@
import java.io.IOException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -82,6 +88,18 @@ public static void startUp(ServletContext servletContext) {
LOGGER.info("Library order: {}", () -> servletContext.getAttribute(ORDERED_LIBS));
}

if (MCRConfiguration2.getBoolean("MCR.Startup.CheckClassProperties").orElse(false)) {
SortedSet<PropertyClassStatus> propertyClassStatuses = checkClassProperties();
if (!propertyClassStatuses.isEmpty()) {
MCRTableMessage<PropertyClassStatus> propertyTable = new MCRTableMessage<>(
new MCRTableMessage.Column<>("Property", PropertyClassStatus::property),
new MCRTableMessage.Column<>("Class", PropertyClassStatus::className),
new MCRTableMessage.Column<>("Status", PropertyClassStatus::status));
propertyClassStatuses.forEach(propertyTable::add);
LOGGER.warn(() -> propertyTable.logMessage("Configured Classes report:"));
}
}

MCRTableMessage<AutoExecutable> executableTable = new MCRTableMessage<>(
new MCRTableMessage.Column<>("Name", AutoExecutable::getName),
new MCRTableMessage.Column<>("Priority", AutoExecutable::getPriority),
Expand All @@ -98,6 +116,34 @@ public static void startUp(ServletContext servletContext) {

}

private static SortedSet<PropertyClassStatus> checkClassProperties() {
Pattern classPattern = Pattern.compile(MCRConfiguration2.getString("MCR.Startup.CheckClassRegEx").orElse("^$"));
return MCRConfiguration2.getPropertiesMap()
.entrySet()
.stream()
.filter(entry -> isClassProperty(entry.getKey(), entry.getValue(), classPattern))
.flatMap(entry -> MCRConfiguration2.splitValue(entry.getValue())
.map(value -> new PropertyClassStatus(entry.getKey(), value, null)))
.filter(pcs -> !pcs.className.isBlank())
.map(pcs -> {
try {
Class<?> aClass = Class.forName(pcs.className(), false, MCRClassTools.getClassLoader());
if (aClass.getAnnotation(Deprecated.class) != null) {
return new PropertyClassStatus(pcs.property(), pcs.className(), ClassStatus.DEPRECATED);
}
} catch (ClassNotFoundException | LinkageError e) {
return new PropertyClassStatus(pcs.property(), pcs.className(), ClassStatus.NOT_FOUND);
}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toCollection(TreeSet::new));
}

private static boolean isClassProperty(String key, String value, Pattern classPattern) {
return key.endsWith(".Class") || classPattern.matcher(value).find();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include lowercase class suffixes in the scan

When an application configures a custom class using the supported lowercase .class suffix (for example Foo.Bar.class=com.acme.Missing), this predicate returns false unless the value also matches the org.mycore regex. The configurable-instance code treats .Class and .class equivalently, so valid lowercase properties in non-MyCoRe packages are never included in the startup report, defeating the new missing/deprecated-class check for those extension configs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

".class" does not respect the mycore.properties naming scheme for properties. After a '.' a capital letter must follow if not other circumstances require a lower case letter. But for configured classes this is not the case so only ".Class" is supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Well, this is only the case since MCR-3670, so only in 2026.06.x and later. In 2025.06.x we still have, for example:

  • MCR.Crypt.Cipher.accesskey.class=...
  • MCR.LayoutService.FoFormatter.class=...

}

private static String toType(MCRComponent component) {
if (component.isMyCoReBaseComponent()) {
return "MyCoRe base component";
Expand Down Expand Up @@ -168,4 +214,33 @@ default int compareTo(AutoExecutable other) {
}

}

private enum ClassStatus {
NOT_FOUND("not found"), DEPRECATED("deprecated");

private final String tableValue;

ClassStatus(String tableValue) {
this.tableValue = tableValue;
}

@Override
public String toString() {
return tableValue;
}
}

private record PropertyClassStatus(String property, String className, ClassStatus status)
implements Comparable<PropertyClassStatus> {

private static final Comparator<PropertyClassStatus> COMPARATOR =
Comparator.comparing(PropertyClassStatus::status)
.thenComparing(PropertyClassStatus::property)
.thenComparing(PropertyClassStatus::className);

@Override
public int compareTo(PropertyClassStatus other) {
return COMPARATOR.compare(this, other);
}
}
}
3 changes: 2 additions & 1 deletion mycore-base/src/main/resources/config/mycore.properties
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@ MCR.Jersey.Resource.ApplicationPaths=rsc
##############################################################################

MCR.Startup.Class=org.mycore.backend.jpa.MCRJPAConfigurationCheck,org.mycore.backend.jpa.MCRJPABootstrapper,org.mycore.datamodel.niofs.MCRFileSystemPromoter,org.mycore.frontend.support.MCRAutoDeploy,org.mycore.frontend.fileupload.MCRUploadServletDeployer,org.mycore.frontend.jersey.MCRJWTUtil

MCR.Startup.CheckClassProperties=true
MCR.Startup.CheckClassRegEx=(?:^|,\\s*)org\\.mycore(\\.[a-z0-9]+)*\\.[A-Z]
##############################################################################
# Website #
##############################################################################
Expand Down
Loading