From 349fa2aaf133c4a607bb5f575cb2dd67aa88135b Mon Sep 17 00:00:00 2001 From: "Schudt, Christian" Date: Mon, 14 Feb 2022 12:17:05 +0100 Subject: [PATCH] SystemProperty: Remember the classloader which loaded a class Following happened to me: 1. Set a custom LockoutProvider class which is located in a plugin 2. During authentication, the LockOutManager.getInstance() was called for the first time and tried to load the custom LockoutProvider class. It failed, because JiveClassLoader could not find it (it's the classloader used in auth code). This commit sets the classloader whenever a class is set in a property via the setValue() method. When getValue() is called, the classloader associated with the set class can be used to load the class with the correct classloader. This does not work during the initial start of Openfire if properties are loaded statically, but if a plugin later sets its own class and Openfire code then tries to load this class (in my example during authentication), it can use the correct classloader. Current workaround is to call LockOutManager.getInstance() in the plugin code, so that it already initialized with the custom lockout provider and does not try to load the class during authentication. --- .../org/jivesoftware/util/SystemProperty.java | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/xmppserver/src/main/java/org/jivesoftware/util/SystemProperty.java b/xmppserver/src/main/java/org/jivesoftware/util/SystemProperty.java index 37b96ece8a..0bd4ee7220 100644 --- a/xmppserver/src/main/java/org/jivesoftware/util/SystemProperty.java +++ b/xmppserver/src/main/java/org/jivesoftware/util/SystemProperty.java @@ -232,6 +232,7 @@ public void xmlPropertyDeleted(final String property, final Map private final Class baseClass; private final Class collectionType; private final boolean sorted; + private volatile ClassLoader classLoader; private SystemProperty(final Builder builder) { // Before we do anything, convert XML based provider setup to Database based @@ -241,6 +242,9 @@ private SystemProperty(final Builder builder) { this.plugin = builder.plugin; this.description = LocaleUtils.getLocalizedPluginString(plugin, "system_property." + key); this.defaultValue = builder.defaultValue; + if (defaultValue instanceof Class) { + this.classLoader = ((Class) defaultValue).getClassLoader(); + } this.minValue = builder.minValue; this.maxValue = builder.maxValue; this.dynamic = builder.dynamic; @@ -302,21 +306,31 @@ private Class getConverterClass() { */ @SuppressWarnings("unchecked") public T getValue() { - final T value = (T) FROM_STRING.get(getConverterClass()).apply(JiveGlobals.getProperty(key), this); - if (value == null || (Collection.class.isAssignableFrom(value.getClass()) && ((Collection) value).isEmpty())) { - return defaultValue; - } - if (minValue != null && ((Comparable) minValue).compareTo(value) > 0) { - LOGGER.warn("Configured value of {} is less than the minimum value of {} for the SystemProperty {} - will use default value of {} instead", - value, minValue, key, defaultValue); - return defaultValue; - } - if (maxValue != null && ((Comparable) maxValue).compareTo(value) < 0) { - LOGGER.warn("Configured value of {} is more than the maximum value of {} for the SystemProperty {} - will use default value of {} instead", - value, maxValue, key, defaultValue); - return defaultValue; + ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader(); + try { + ClassLoader cl = classLoader; + if (cl != null) { + Thread.currentThread().setContextClassLoader(cl); + } + + final T value = (T) FROM_STRING.get(getConverterClass()).apply(JiveGlobals.getProperty(key), this); + if (value == null || (Collection.class.isAssignableFrom(value.getClass()) && ((Collection) value).isEmpty())) { + return defaultValue; + } + if (minValue != null && ((Comparable) minValue).compareTo(value) > 0) { + LOGGER.warn("Configured value of {} is less than the minimum value of {} for the SystemProperty {} - will use default value of {} instead", + value, minValue, key, defaultValue); + return defaultValue; + } + if (maxValue != null && ((Comparable) maxValue).compareTo(value) < 0) { + LOGGER.warn("Configured value of {} is more than the maximum value of {} for the SystemProperty {} - will use default value of {} instead", + value, maxValue, key, defaultValue); + return defaultValue; + } + return value; + } finally { + Thread.currentThread().setContextClassLoader(previousClassLoader); } - return value; } /** @@ -354,6 +368,10 @@ public String getDefaultDisplayValue() { * @param value the new value for the SystemProperty */ public void setValue(final T value) { + if (value instanceof Class) { + Class clazz = ((Class) value); + this.classLoader = clazz.getClassLoader(); + } JiveGlobals.setProperty(key, TO_STRING.get(getConverterClass()).apply(value, this), isEncrypted()); }